En begyndervenlig introduktion til containere, VM'er og Docker

Hvis du er programmerer eller tekniker, er chancerne for, at du i det mindste har hørt om Docker: et nyttigt værktøj til pakning, forsendelse og kørsel af applikationer i "containere". Det ville være svært ikke at med al den opmærksomhed, det får i disse dage - fra både udviklere og systemadministratorer. Selv de store hunde som Google, VMware og Amazon bygger tjenester til at understøtte det.

Uanset om du har en øjeblikkelig brugssag i tankerne for Docker eller ej, synes jeg stadig, det er vigtigt at forstå nogle af de grundlæggende begreber omkring, hvad en "container" er, og hvordan den sammenlignes med en virtuel maskine (VM). Mens Internettet er fuld af fremragende brugsguider til Docker, kunne jeg ikke finde mange nybegyndervenlige konceptuelle guider, især om hvad en container består af. Så forhåbentlig løser dette indlæg dette problem :)

Lad os starte med at forstå, hvad VM'er og containere endda er.

Hvad er "containere" og "VM'er"?

Containere og VM'er er ens i deres mål: at isolere en applikation og dens afhængigheder i en selvstændig enhed, der kan køre hvor som helst.

Desuden fjerner containere og virtuelle maskiner behovet for fysisk hardware, hvilket giver mulighed for en mere effektiv brug af computerressourcer, både hvad angår energiforbrug og omkostningseffektivitet.

Hovedforskellen mellem containere og virtuelle maskiner er i deres arkitektoniske tilgang. Lad os se nærmere på.

Virtuelle maskiner

En VM er i det væsentlige en emulering af en rigtig computer, der udfører programmer som en rigtig computer. VM'er kører oven på en fysisk maskine ved hjælp af en “hypervisor” . En hypervisor kører til gengæld enten på en værtsmaskine eller på "bare-metal" .

Lad os pakke ud jargongen:

En hypervisor er et stykke software, firmware eller hardware, som virtuelle computere kører oven på. Hypervisorerne kører selv på fysiske computere, kaldet "værtsmaskinen" . Værtsmaskinen forsyner de virtuelle computere med ressourcer, inklusive RAM og CPU. Disse ressourcer er opdelt mellem virtuelle computere og kan fordeles, som du finder det passende. Så hvis en VM kører en mere ressourcetung applikation, kan du allokere flere ressourcer til den ene end de andre VM'er, der kører på den samme værtsmaskine.

Den virtuelle maskine, der kører på værtsmaskinen (igen ved hjælp af en hypervisor) kaldes også ofte en "gæstemaskine." Denne gæstemaskine indeholder både applikationen og alt hvad den har brug for til at køre applikationen (f.eks. Systembinarier og biblioteker). Det bærer også en hel virtualiseret hardwarestak, inklusive virtualiserede netværkskort, lagring og CPU - hvilket betyder, at den også har sit eget fuldgyldige gæstoperativsystem. Indefra opfører gæstemaskinen sig som sin egen enhed med sine egne dedikerede ressourcer. Udefra ved vi, at det er en VM - delingsressourcer, der leveres af værtsmaskinen.

Som nævnt ovenfor kan en gæstemaskine køre på enten en hostet hypervisor eller en bare metal hypervisor . Der er nogle vigtige forskelle mellem dem.

Først og fremmest kører en hostet virtualiseringshypervisor på værtsmaskinens operativsystem. For eksempel kan en computer, der kører OSX, have en VM (f.eks. VirtualBox eller VMware Workstation 8) installeret oven på dette operativsystem. VM har ikke direkte adgang til hardware, så det skal gå gennem værtsoperativsystemet (i vores tilfælde Macs OSX).

Fordelen ved en hostet hypervisor er, at den underliggende hardware er mindre vigtig. Værts operativsystem er ansvarlig for hardwaredrivere i stedet for selve hypervisoren og anses derfor for at have mere "hardwarekompatibilitet." På den anden side skaber dette ekstra lag imellem hardware og hypervisor mere ressourceomkostninger, hvilket sænker VM's ydeevne.

Et hypervisor-miljø med bare metal tackler ydeevneproblemet ved at installere og køre fra værtsmaskinens hardware. Fordi det grænseflader direkte med den underliggende hardware, behøver det ikke et værtsoperativsystem at køre på. I dette tilfælde er den første ting, der er installeret på en værtsmaskins server som operativsystem, hypervisoren. I modsætning til den hostede hypervisor har en bare metal-hypervisor sine egne enhedsdrivere og interagerer direkte med hver komponent direkte til alle I / O-, behandlings- eller OS-specifikke opgaver. Dette resulterer i bedre ydeevne, skalerbarhed og stabilitet. Kompromisen her er, at hardwarekompatibilitet er begrænset, fordi hypervisor kun kan have så mange enhedsdrivere indbygget i den.

Efter al denne snak om hypervisorer undrer du dig måske over, hvorfor vi overhovedet har brug for dette ekstra "hypervisor" -lag mellem VM og værtsmaskinen.

Da VM har et virtuelt operativsystem, spiller hypervisor en vigtig rolle i at give VM'erne en platform til at administrere og udføre dette gæstoperativsystem. Det giver værtscomputere mulighed for at dele deres ressourcer blandt de virtuelle maskiner, der kører som gæster oven på dem.

Som du kan se i diagrammet, pakker VM'ere den virtuelle hardware, en kerne (dvs. OS) og brugerplads til hver nye VM.

Beholder

I modsætning til en VM, der leverer hardwarevirtualisering, leverer en container virtualisering på operativsystemniveau ved at abstrahere "brugerrummet". Du kan se, hvad jeg mener, når vi pakker ordet container ud .

For alle formål og formål ser containere ud som en VM. For eksempel har de privat plads til behandling, kan udføre kommandoer som root, have en privat netværksgrænseflade og IP-adresse, tillade brugerdefinerede ruter og iptable regler, kan montere filsystemer osv.

Den ene store forskel mellem containere og VM'er er, at containere * deler * værtssystemets kerne med andre containere.

Dette diagram viser dig, at containere kun pakker brugerpladsen og ikke kernen eller den virtuelle hardware, som en VM gør. Hver container får sit eget isolerede brugerrum, så flere containere kan køre på en enkelt værtsmaskine. Vi kan se, at hele operativsystemets niveauarkitektur deles på tværs af containere. De eneste dele, der oprettes fra bunden, er skraldespandene og libs. Dette er hvad der gør containere så lette.

Hvor kommer Docker ind?

Docker er et open source-projekt baseret på Linux-containere. Det bruger Linux Kernel-funktioner som navneområder og kontrolgrupper til at oprette containere oven på et operativsystem.

Beholdere er langt fra nye; Google har brugt deres egen containerteknologi i årevis. Andre Linux-containerteknologier inkluderer Solaris-zoner, BSD-fængsler og LXC, som har eksisteret i mange år.

Så hvorfor får Docker pludselig damp?

1. Brugervenlighed: Docker har gjort det meget lettere for alle - udviklere, systemadministratorer, arkitekter og andre - at drage fordel af containere for hurtigt at opbygge og teste bærbare applikationer. Det giver enhver mulighed for at pakke en applikation på deres bærbare computer, som igen kan køre umodificeret på enhver offentlig sky, privat sky eller endda bare metal. Mantraet er: "bygg en gang, kør hvor som helst."

2. Hastighed: Docker-containere er meget lette og hurtige. Da containere bare er sandkassemiljøer, der kører på kernen, optager de færre ressourcer. Du kan oprette og køre en Docker-container på få sekunder sammenlignet med virtuelle computere, der kan tage længere tid, fordi de skal starte et komplet virtuelt operativsystem hver gang.

3. Docker Hub: Docker-brugere drager også fordel af det stadig mere rige økosystem af Docker Hub, som du kan tænke på som en "app store til Docker-billeder." Docker Hub har titusinder af offentlige billeder oprettet af samfundet, der er let tilgængelige til brug. Det er utroligt nemt at søge efter billeder, der opfylder dine behov, klar til at trække ned og bruge med lidt til ingen ændringer.

4. Modularitet og skalerbarhed: Docker gør det let at opdele applikationens funktionalitet i individuelle containere. For eksempel kan du have din Postgres-database kørende i en container og din Redis-server i en anden, mens din Node.js-app er i en anden. Med Docker er det blevet lettere at linke disse containere sammen for at oprette din applikation, hvilket gør det nemt at skalere eller opdatere komponenter uafhængigt i fremtiden.

Sidst men ikke mindst, hvem elsker ikke Dockerhvalen? ;)

Grundlæggende Docker-koncepter

Nu hvor vi har det store billede på plads, lad os gennemgå de grundlæggende dele af Docker stykke for stykke:

Docker-motor

Docker-motor er det lag, som Docker kører på. Det er en let køretid og værktøj, der administrerer containere, billeder, builds og meget mere. Det kører indbygget på Linux-systemer og består af:

1. En Docker-dæmon, der kører på værtscomputeren.

2. En Docker-klient, der derefter kommunikerer med Docker-dæmonen for at udføre kommandoer.

3. En REST API til ekstern interaktion med Docker Daemon.

Docker-klient

Docker-klienten er det, du som slutbruger af Docker kommunikerer med. Tænk på det som brugergrænsefladen til Docker. For eksempel når du gør ...

du kommunikerer til Docker-klienten, som derefter kommunikerer dine instruktioner til Docker-dæmonen.

Docker Daemon

Docker-dæmonen er, hvad der faktisk udfører kommandoer, der sendes til Docker-klienten - som at bygge, køre og distribuere dine containere. Docker Daemon kører på værtsmaskinen, men som bruger kommunikerer du aldrig direkte med Daemon. Docker-klienten kan også køre på værtsmaskinen, men det er ikke nødvendigt. Det kan køre på en anden maskine og kommunikere med Docker-dæmonen, der kører på værtsmaskinen.

Dockerfil

En Dockerfil er hvor du skriver instruktionerne til at oprette et Docker-billede. Disse instruktioner kan være:

  • KØR apt-get y install some-package : at installere en softwarepakke
  • EXPOSE 8000: at eksponere en port
  • ENV ANT_HOME / usr / local / apache-ant for at videregive en miljøvariabel

og så videre. Når du har konfigureret din Dockerfile, kan du bruge kommandoen docker build til at oprette et billede ud fra det. Her er et eksempel på en Dockerfile:

Docker-billede

Billeder er skrivebeskyttede skabeloner, som du bygger ud fra et sæt instruktioner, der er skrevet i din Dockerfile. Billeder definerer både hvad du vil have din pakkede applikation og dens afhængighed til at se ud * og * hvilke processer der skal køres, når den startes.

Docker-billedet er bygget ved hjælp af en Dockerfil. Hver instruktion i Dockerfile tilføjer et nyt "lag" til billedet med lag, der repræsenterer en del af billedfilsystemet, der enten føjer til eller erstatter laget under det. Lag er nøglen til Dockers lette, men alligevel stærke struktur. Docker bruger et Union File System til at opnå dette:

Union filsystemer

Docker bruger Union File Systems til at opbygge et billede. Du kan tænke på et EU-filsystem som et stabelbart filsystem, hvilket betyder, at filer og mapper til separate filsystemer (kendt som grene) kan overlejres transparent for at danne et enkelt filsystem.

Indholdet af mapper, der har samme sti inden for de overlejrede grene, ses som en enkelt flettet mappe, som undgår behovet for at oprette separate kopier af hvert lag. I stedet for kan de alle få henvisninger til den samme ressource; når visse lag skal ændres, opretter det en kopi og ændrer en lokal kopi, så originalen forbliver uændret. Sådan kan filsystemer * vises * skrivbare uden faktisk at tillade skrivning. (Med andre ord et "copy-on-write" -system.)

Lagdelte systemer tilbyder to hovedfordele:

1. Kopiering-fri: lag hjælper med at undgå at duplikere et komplet sæt filer hver gang du bruger et billede til at oprette og køre en ny container, hvilket gør instantiering af dockercontainere meget hurtig og billig.

2. Lagadskillelse: At foretage en ændring er meget hurtigere - når du ændrer et billede, udbreder Docker kun opdateringerne til det lag, der blev ændret.

Volumener

Volumener er "data" -delen af ​​en container, initialiseret, når en container oprettes. Volumener giver dig mulighed for at fortsætte og dele en containers data. Datamængder er adskilt fra Unionens standardfilsystem og findes som normale mapper og filer på værtsfilsystemet. Så selvom du ødelægger, opdaterer eller genopbygger din container, forbliver datamængderne uberørt. Når du vil opdatere en lydstyrke, foretager du ændringer i den direkte. (Som en ekstra bonus kan datamængder deles og genbruges mellem flere containere, hvilket er ret pænt.)

Docker-containere

En Docker-container, som beskrevet ovenfor, indpakker en applikations software i en usynlig boks med alt, hvad applikationen har brug for at køre. Det inkluderer operativsystemet, applikationskode, runtime, systemværktøjer, systembiblioteker osv. Docker-containere er bygget af Docker-billeder. Da billeder er skrivebeskyttet, tilføjer Docker et skrive-skrive-filsystem over billedets skrivebeskyttede filsystem for at oprette en container.

Desuden opretter Docker derefter en netværksgrænseflade, så containeren kan tale med den lokale vært, vedhæfte en tilgængelig IP-adresse til containeren og udføre den proces, du har angivet for at køre din applikation, når du definerer billedet.

Når du har oprettet en container, kan du køre den i ethvert miljø uden at skulle foretage ændringer.

Dobbeltklik på "containere"

Pis! Det er mange bevægelige dele. En ting, der altid fik mig nysgerrig, var hvordan en container faktisk implementeres, især da der ikke er nogen abstrakt infrastrukturgrænse omkring en container. Efter masser af læsning giver det hele mening, så her er mit forsøg på at forklare det for dig! :)

Udtrykket "container" er egentlig bare et abstrakt koncept til at beskrive, hvordan et par forskellige funktioner fungerer sammen for at visualisere en "container". Lad os løbe hurtigt igennem dem:

1) Navneområder

Navneområder giver containere deres egen visning af det underliggende Linux-system, hvilket begrænser, hvad containeren kan se og få adgang til. Når du kører en container, opretter Docker navneområder, som den specifikke container vil bruge.

Der er flere forskellige typer navneområder i en kerne, som Docker bruger, for eksempel:

en. NET: Leverer en container med sin egen visning af systemets netværksstak (f.eks. Dens egne netværksenheder, IP-adresser, IP-routingtabeller, / proc / net-bibliotek, portnumre osv.).

b. PID: PID står for proces-id. Hvis du nogensinde har kørt ps aux i kommandolinjen for at kontrollere, hvilke processer der kører på dit system, har du set en kolonne med navnet "PID". PID-navneområdet giver containere deres egen oversigt over processer, de kan se og interagere med, inklusive en uafhængig init (PID 1), som er "forfader til alle processer".

c. MNT: Giver en container sin egen oversigt over "monteringerne" på systemet. Så processer i forskellige monteringsnavneområder har forskellige visninger af filsystemhierarkiet.

d. UTS: UTS står for UNIX Timesharing System. Det tillader en proces at identificere systemidentifikatorer (dvs. værtsnavn, domænenavn osv.). UTS tillader containere at have deres eget værtsnavn og NIS-domænenavn, der er uafhængige af andre containere og værtssystemet.

e. IPC: IPC står for InterProcess Communication. IPC-navneområdet er ansvarligt for at isolere IPC-ressourcer mellem processer, der kører inde i hver container.

f. BRUGER: Dette navneområde bruges til at isolere brugere inden for hver container. Det fungerer ved at tillade containere at have en anden visning af uid (bruger-ID) og gid (gruppe-ID), sammenlignet med værtssystemet. Som et resultat kan en proces uid og gid være forskellig inden for og uden for et brugernavneområde, hvilket også tillader en proces at have en uprivilegeret bruger uden for en container uden at ofre rodret i en container.

Docker bruger disse navneområder sammen for at isolere og starte oprettelsen af ​​en container. Den næste funktion kaldes kontrolgrupper.

2) Kontrolgrupper

Kontrolgrupper (også kaldet cgroups) er en Linux-kernefunktion, der isolerer, prioriterer og tager højde for ressourceforbruget (CPU, hukommelse, disk I / O, netværk osv.) Af et sæt processer. I denne forstand sikrer en cgroup, at Docker-containere kun bruger de ressourcer, de har brug for - og om nødvendigt opsætter grænser for, hvilke ressourcer en container * kan * bruge. Cgroups sikrer også, at en enkelt container ikke udtømmer en af ​​disse ressourcer og bringer hele systemet ned.

Endelig er fagforeningsfilsystemer en anden funktion, som Docker bruger:

3) Isoleret EU-filsystem:

Beskrevet ovenfor i afsnittet Docker Images :)

Dette er virkelig alt hvad der er til en Docker-container (selvfølgelig er djævelen i implementeringsdetaljerne - som hvordan man styrer interaktionerne mellem de forskellige komponenter).

Fremtiden for Docker: Docker og VM'er eksisterer samtidig

Mens Docker helt sikkert vinder meget damp, tror jeg ikke, det bliver en reel trussel mod virtuelle computere. Containere vil fortsat vinde terræn, men der er mange brugssager, hvor virtuelle computere stadig er bedre egnet.

For eksempel, hvis du har brug for at køre flere applikationer på flere servere, giver det sandsynligvis mening at bruge VM'er. På den anden side, hvis du har brug for at køre mange * kopier * af en enkelt applikation, tilbyder Docker nogle overbevisende fordele.

Desuden, mens containere giver dig mulighed for at opdele din applikation i mere funktionelle diskrete dele for at skabe en adskillelse af bekymringer, betyder det også, at der er et voksende antal dele at administrere, hvilket kan blive uhåndterligt.

Sikkerhed har også været et område med bekymring for Docker-containere - da containere deler den samme kerne, er barrieren mellem containere tyndere. Mens en fuld VM kun kan udstede hypercalls til værtshypervisoren, kan en Docker-container lave syscalls til værtskernen, hvilket skaber et større overfladeareal til angreb. Når sikkerhed er særlig vigtig, vil udviklere sandsynligvis vælge VM'er, der er isoleret af abstrakt hardware - hvilket gør det meget sværere at blande sig i hinanden.

Naturligvis vil spørgsmål som sikkerhed og ledelse helt sikkert udvikle sig, efterhånden som containere får mere eksponering i produktion og yderligere kontrol fra brugerne. For øjeblikket er debatten om containere vs VM virkelig bedst for dev ops folk, der lever og ånder dem hver dag!

Konklusion

Jeg håber, du nu er udstyret med den viden, du har brug for for at lære mere om Docker og måske endda bruge den i et projekt en dag.

Giv mig som altid en række i kommentarerne, hvis jeg har lavet fejl eller alligevel kan være til hjælp i! :)