Afmystificering af containere 101: et dybt dyk ned i containerteknologi for begyndere

Foto af Rye Jessen på Unsplash

Introduktion

Uanset om du er studerende i skolen, en udvikler hos et firma eller en software-entusiast, er chancerne for, at du hører om containere. Du har måske også hørt, at containere er lette virtuelle maskiner, men hvad betyder det egentlig, hvordan præcist fungerer containere, og hvorfor er de så vigtige?

Denne historie fungerer som et kig på containere, deres vigtigste tekniske ideer og applikationerne. Jeg antager ikke nogen forudgående viden på dette område bortset fra en grundlæggende forståelse af datalogi.

Kernen og OS

Din bærbare computer er sammen med alle andre computere bygget oven på nogle hardware-stykker som CPU, vedvarende opbevaring (diskdrev, SSD), hukommelse, netværkskort osv.

For at interagere med denne hardware fungerer et stykke software i operativsystemet kaldet kernen som broen mellem hardwaren og resten af ​​systemet. Kernen er ansvarlig for planlægning af processer (programmer) til at køre, styring af enheder (læsning og skrivning af adresser på disk og hukommelse) med mere.

Resten af ​​operativsystemet tjener til at starte og styre brugerpladsen, hvor brugerprocesser køres, og vil konstant interagere med kernen.

Kernen er en del af operativsystemet og interface med hardwaren. Operativsystemet som helhed lever i

Den virtuelle maskine

Så du har en computer, der kører MacOS og et program, der er bygget til at køre på Ubuntu. Hmmm… En almindelig løsning er at starte op en virtuel maskine på din MacOS-computer, der kører Ubuntu og derefter køre dit program der.

En virtuel maskine består af et niveau af hardware og kernevirtualisering, som kører et gæstoperativsystem. Et stykke software kaldet en hypervisor opretter den virtualiserede hardware, der kan omfatte den virtuelle disk, det virtuelle netværksgrænseflade, den virtuelle CPU og mere. Virtuelle maskiner inkluderer også en gæstekerne, der kan tale med denne virtuelle hardware.

Hypervisoren kan være vært, hvilket betyder, at det er noget software, der kører på Host OS (MacOS) som i eksemplet. Det kan også være kendt metal, der kører direkte på maskinens hardware (udskiftning af dit operativsystem). Uanset hvad betragtes hypervisor-fremgangsmåden som tung vægt, da den kræver virtualisering af flere dele, hvis ikke al hardware og kerne.

Når der skal være flere isolerede grupper på den samme maskine, er det alt for tungt og spildt med ressourcer at køre en VM for hver af disse grupper til at være en god tilgang.

Overhead ikke skaleret.

VM'er kræver hardwarevirtualisering til isolering på maskinniveau, mens containere fungerer isoleret inden for det samme driftssystem. Forskellen over hovedet vises virkelig, når antallet af isolerede rum øges. En almindelig bærbar computer kan køre snesevis af containere, men kan kæmpe for at køre selv en VM godt.

cgroups

I 2006 opfandt ingeniører hos Google Linux “kontrolgrupper”, forkortet som cgroups. Dette er en funktion i Linux-kernen, der isolerer og kontrollerer ressourceforbruget til brugerprocesser.

Disse processer kan sættes i navneområder, hovedsageligt samlinger af processer, der har de samme ressourcebegrænsninger. En computer kan have flere navneområder, hver med ressourceegenskaberne håndhævet af kernen.

Ressourcetildelingen pr. Navneområde kan styres for at begrænse mængden af ​​den samlede CPU, RAM osv., Som et sæt processer kan bruge. For eksempel vil en baggrundslog-aggregeringsapplik sandsynligvis skulle have sin ressourcegrænse for ikke ved et uheld at overvælde den faktiske server, den logger.

Selvom det ikke var en original funktion, blev cgroups i Linux efterhånden omarbejdet til at omfatte en funktion, der kaldes namespace isolation. Ideen om navneområdeisolering er ikke ny, og Linux havde allerede mange slags navneområdeisolering. Et almindeligt eksempel er procesisolering, der adskiller hver enkelt proces og forhindrer sådanne ting som delt hukommelse.

Cgroupisolering er et højere niveau af isolering, der sikrer, at processer inden for et cgroup-navneområde er uafhængige af processer i andre navneområder. Nogle få vigtige isoleringsfunktioner i navneområdet er skitseret nedenfor og skaber grundlaget for den isolering, vi forventer fra containere.

  • PID (Process Identifier) ​​Navneområder: dette sikrer, at processer inden for et navnefelt ikke er opmærksomme på processen i andre navneområder.
  • Netværkets navneområder: Isolering af netværksgrænsefladecontrolleren, iptables, routingtabeller og andre lavere niveau netværksværktøjer.
  • Montering af navneområder: Filsystemer er monteret, så filsystemets omfang af et navneområde er begrænset til kun de monterede mapper.
  • Brugernavneområder: Begrænser brugere inden for et navnefelt til kun det navneområde og undgår bruger-ID-konflikter på tværs af navneområder.

For at sige det enkelt, synes hvert navneområde at være sin egen maskine til processerne inden for det.

Linux-containere

Linux-grupperinger banede vejen for en teknologi kaldet linux-containere (LXC). LXC var virkelig den første store implementering af det, vi ved i dag, for at være en container, idet de drage fordel af cgroups og navnepladsisolering for at skabe virtuelt miljø med separat proces og netværksplads.

På en måde tillader dette uafhængige og isolerede brugerrum. Ideen om containere følger direkte fra LXC. Faktisk blev tidligere versioner af Docker bygget direkte oven på LXC.

Docker

Docker er den mest anvendte containerteknologi og virkelig hvad de fleste mennesker mener, når de refererer til containere. Mens der er andre open source-containerteknikker (som rkt af CoreOS) og store virksomheder, der bygger deres egen containermotor (som lmctfy hos Google), er Docker blevet branchestandarden for containerisering. Det er stadig bygget på cgroups og navneafstand leveret af Linux-kernen og for nylig Windows også.

Billedkilde: Docker

En Docker-beholder består af lag af billeder, binære pakker sammen i en enkelt pakke. Basebilledet indeholder operativsystemet til beholderen, der kan være anderledes end værtsets operativsystem.

Containerens operativsystem er i form af et billede. Dette er ikke det fulde operativsystem, som på værten, og forskellen er, at billedet kun er filsystemet og binære filer til OS, mens det fulde operativsystem inkluderer filsystemet, binære filer og kernen.

Oven på basebilledet er der flere billeder, der hver bygger en del af beholderen. For eksempel kan oven på basisbilledet være det billede, der indeholder apt-get-afhængigheder. Oven på det kan være det billede, der indeholder applikationen binær, og så videre.

Den seje del er, hvis der er to containere med billedlagene a, b, c og a, b, d, så skal du kun gemme en kopi af hvert billedlag a, b, c, d både lokalt og i depotet . Dette er Dockers unionsfilsystem.

Hvert billede, der er identificeret med en hash, er kun et af mange mulige lag af billeder, der udgør en beholder. Imidlertid identificeres en container kun ved sit billede på øverste niveau, der har henvisninger til overordnede billeder. To billeder på øverste niveau (billede 1 og billede 2) vist her deler de tre første lag. Billede 2 har to yderligere konfigurationsrelaterede lag, men deler de samme overordnede billeder som billede 1.

Når en container startes, downloades billedet og dets overordnede billeder fra repoen, cgroup- og navneområdet oprettes, og billedet bruges til at oprette et virtuelt miljø. Fra containeren ser filerne og binærerne, der er angivet på billedet, ud til at være de eneste filer på hele maskinen. Derefter starter beholderens hovedproces, og containeren betragtes som levende.

Docker har nogle andre virkelig rigtig seje funktioner, såsom kopi på skrivning, bind (delte filsystemer mellem containere), docker-dæmonen (administrerer containere på en maskine), versionskontrollerede lagre (som Github til containere) og mere. For at lære mere om dem og se nogle praktiske eksempler på, hvordan du bruger Docker, er denne Medium-artikel ekstremt nyttig.

En kommandolinjeklient (1) fortæller en proces på maskinen kaldet docker-dæmonen (2), hvad de skal gøre. Demonen trækker billeder fra et registreringsdatabase / depot (3). Disse billeder er cache (4) på ​​den lokale maskine og kan startes op af dæmonen for at køre containere (5). Billedkilde: Docker

Hvorfor containere

Bortset fra procesisolering har containere mange andre fordelagtige egenskaber.

Beholderen fungerer som en selvisoleret enhed, der kan køre overalt, der understøtter den. Og i hvert af disse tilfælde vil beholderen i sig selv være nøjagtig identisk. Det betyder ikke noget, om værts OS er CentOS, Ubuntu, MacOS eller endda noget ikke UNIX som Windows - fra containeren vil OS være det OS, som containeren har specificeret. Således kan du være sikker på, at containeren, du har bygget på din bærbare computer, også kører på virksomhedens servere.

Containeren fungerer også som en standardiseret enhed til arbejde eller beregning. Et almindeligt paradigme er, at hver container skal køre en enkelt webserver, en enkelt skærv i en database eller en enkelt gnistarbejder osv. For at skalere en applikation skal du blot skalere antallet af containere.

I dette paradigme får hver container en fast ressourcekonfiguration (CPU, RAM, antal tråde osv.), Og skalering af applikationen kræver skalering af kun antallet af containere i stedet for de individuelle ressourceprimiver. Dette giver en meget lettere abstraktion for ingeniører, når applikationer skal skaleres op eller ned.

Containere fungerer også som et godt værktøj til at implementere mikrotjenestearkitektur, hvor hver mikroservice kun er et sæt samarbejdscontainere. F.eks. Kan Redis mikrotjeneste implementeres med en enkelt mastercontainer og flere slavecontainere.

Denne (mikro) serviceorienterede arkitektur har nogle meget vigtige egenskaber, der gør det let for ingeniørteams at oprette og distribuere applikationer (se min tidligere artikel for flere detaljer).

Orchestration

Lige siden tidspunktet for linuxcontainere har brugerne forsøgt at implementere applikationer i stor skala over mange virtuelle maskiner, hvor hver proces kører i sin egen container. Dette kræver at være i stand til effektivt at implementere titusindvis af containere på tværs af potentielt hundreder af virtuelle maskiner og styre deres netværk, filsystemer, ressourcer osv. Docker i dag gør dette lidt lettere, da det udsætter abstraktioner for at definere containernetværk, mængder til fil systemer, ressourcekonfigurationer osv.

Dog er der stadig brug for et værktøj til:

  • faktisk tage en specifikation og tildele containere til maskiner (planlægning)
  • starter faktisk de specificerede containere på maskinerne gennem Docker
  • håndtere opgraderinger / rollbacks / systemets konstant skiftende karakter
  • reagere på fejl som containerbrydning
  • og oprette klyngeressourcer som serviceopdagelse, inter VM-netværk, klyngeindtrængning / egress osv.

Dette sæt problemer vedrører orkestrering af et distribueret system bygget oven på et sæt (muligvis kortvarige eller konstant skiftende) containere, og folk har bygget nogle virkelig mirakuløse systemer til at løse dette problem.

I min næste historie vil jeg tale i dybden om implementeringen af ​​Kubernetes, den største open source-orkestrator, sammen med to lige så vigtige, men mindre kendte, Mesos og Borg.

Denne historie er del af en serie. Jeg er en undergrad på UC Berkeley. Min forskning er i distribuerede systemer, og jeg får råd fra Scott Shenker.

Forrige: Sådan gemte Microservices Internettet
Næste: Orchestration (TBD)