Hvad er Docker: en kort udflugt til historie og grundlæggende abstraktioner

Startede den 10. august i Slurm Docker video kursus, hvor vi analyserer det fuldstændigt - fra grundlæggende abstraktioner til netværksparametre.

I denne artikel vil vi tale om Dockers historie og dens vigtigste abstraktioner: Image, Cli, Dockerfile. Foredraget er beregnet til begyndere, så det er usandsynligt, at det er interessant for erfarne brugere. Der vil ikke være blod, blindtarm eller dyb nedsænkning. Det helt basale.

Hvad er Docker: en kort udflugt til historie og grundlæggende abstraktioner

Hvad er Docker

Lad os se på definitionen af ​​Docker fra Wikipedia.

Docker er software til automatisering af udrulning og administration af applikationer i containermiljøer.

Intet er klart ud fra denne definition. Det er især uklart, hvad "i miljøer, der understøtter containerisering" betyder. For at finde ud af det, lad os gå tilbage i tiden. Lad os starte med den æra, som jeg traditionelt kalder den "monolitiske æra."

Monolitisk æra

Den monolitiske æra er begyndelsen af ​​2000'erne, hvor alle applikationer var monolitiske, med en masse afhængigheder. Udviklingen tog lang tid. Samtidig var der ikke mange servere; vi kendte dem alle ved navn og overvågede dem. Der er sådan en sjov sammenligning:

Kæledyr er husdyr. I den monolitiske æra behandlede vi vores servere som kæledyr, plejede og elskede, og vi blæste støvpletter væk. Og for at få bedre ressourcestyring brugte vi virtualisering: vi tog en server og klippede den i flere virtuelle maskiner og sikrede derved isolering af miljøet.

Hypervisor-baserede virtualiseringssystemer

Alle har sikkert hørt om virtualiseringssystemer: VMware, VirtualBox, Hyper-V, Qemu KVM osv. De giver applikationsisolering og ressourcestyring, men de har også ulemper. For at lave virtualisering skal du bruge en hypervisor. Og hypervisoren er en ressource overhead. Og selve den virtuelle maskine er normalt en hel kolos – et tungt billede, der indeholder et styresystem, Nginx, Apache og muligvis MySQL. Billedet er stort, og den virtuelle maskine er ubelejlig at betjene. Som et resultat kan arbejdet med virtuelle maskiner være langsomt. For at løse dette problem blev virtualiseringssystemer oprettet på kerneniveau.

Virtualiseringssystemer på kerneniveau

Virtualisering på kerneniveau understøttes af OpenVZ, Systemd-nspawn, LXC-systemer. Et slående eksempel på sådan virtualisering er LXC (Linux Containers).

LXC er et virtualiseringssystem på operativsystemniveau til at køre flere isolerede forekomster af Linux-operativsystemet på en enkelt node. LXC bruger ikke virtuelle maskiner, men skaber et virtuelt miljø med sit eget procesrum og netværksstak.

I bund og grund skaber LXC containere. Hvad er forskellen mellem virtuelle maskiner og containere?

Hvad er Docker: en kort udflugt til historie og grundlæggende abstraktioner

Containeren er ikke egnet til at isolere processer: Der findes sårbarheder i virtualiseringssystemer på kerneniveau, som gør det muligt for dem at flygte fra containeren til værten. Derfor, hvis du skal isolere noget, er det bedre at bruge en virtuel maskine.

Forskellene mellem virtualisering og containerisering kan ses i diagrammet.
Der er hardware hypervisorer, hypervisorer oven på OS og containere.

Hvad er Docker: en kort udflugt til historie og grundlæggende abstraktioner

Hardware hypervisorer er seje, hvis du virkelig vil isolere noget. Fordi det er muligt at isolere på niveau med hukommelsessider og processorer.

Der er hypervisorer som et program, og der er containere, og dem vil vi tale nærmere om. Containeriseringssystemer har ikke en hypervisor, men der er en Container Engine, der opretter og administrerer containere. Denne ting er mere let, så på grund af arbejdet med kernen er der mindre overhead eller slet ingen.

Hvad bruges til containerisering på kerneniveau

De vigtigste teknologier, der giver dig mulighed for at oprette en container isoleret fra andre processer, er navnerum og kontrolgrupper.

Navneområder: PID, Netværk, Mount og Bruger. Der er flere, men for at lette forståelsen vil vi fokusere på disse.

PID-navneområde begrænser processer. Når vi for eksempel opretter et PID Namespace og placerer en proces der, bliver det med PID 1. Normalt i systemer er PID 1 systemd eller init. Derfor, når vi placerer en proces i et nyt navneområde, modtager den også PID 1.

Networking Namespace giver dig mulighed for at begrænse/isolere netværket og placere dine egne grænseflader inde. Mount er en filsystembegrænsning. Bruger – begrænsning for brugere.

Kontrolgrupper: Hukommelse, CPU, IOPS, Netværk - omkring 12 indstillinger i alt. Ellers kaldes de også C-grupper ("C-grupper").

Kontrolgrupper administrerer ressourcer for en container. Gennem kontrolgrupper kan vi sige, at containeren ikke bør forbruge mere end en vis mængde ressourcer.

For at containeriseringen skal fungere fuldt ud, bruges yderligere teknologier: Funktioner, Copy-on-write og andre.

Evner er, når vi fortæller en proces, hvad den kan og ikke kan. På kerneniveau er disse simpelthen bitmaps med mange parametre. For eksempel har root-brugeren fulde privilegier og kan gøre alt. Tidsserveren kan ændre systemtiden: den har funktioner på Time Capsule, og det er det. Ved at bruge privilegier kan du fleksibelt konfigurere begrænsninger for processer og dermed beskytte dig selv.

Copy-on-write-systemet giver os mulighed for at arbejde med Docker-billeder og bruge dem mere effektivt.

Docker har i øjeblikket kompatibilitetsproblemer med Cgroups v2, så denne artikel fokuserer specifikt på Cgroups v1.

Men lad os vende tilbage til historien.

Da virtualiseringssystemer dukkede op på kerneniveau, begyndte de at blive brugt aktivt. Overheaden på hypervisoren forsvandt, men nogle problemer forblev:

  • store billeder: de skubber et operativsystem, biblioteker, en masse forskellig software ind i den samme OpenVZ, og i sidste ende viser billedet sig stadig at være ret stort;
  • Der er ingen normal standard for emballering og levering, så problemet med afhængigheder består. Der er situationer, hvor to stykker kode bruger det samme bibliotek, men med forskellige versioner. Der kan være en konflikt mellem dem.

For at løse alle disse problemer er den næste æra kommet.

Container æra

Da Era of Containers ankom, ændrede filosofien om at arbejde med dem sig:

  • Én proces - én beholder.
  • Vi leverer alle de afhængigheder, processen har brug for, til sin container. Dette kræver opskæring af monolitter i mikrotjenester.
  • Jo mindre billede, jo bedre – der er færre mulige sårbarheder, det ruller hurtigere ud og så videre.
  • Forekomster bliver flygtige.

Kan du huske, hvad jeg sagde om kæledyr vs kvæg? Tidligere var tilfælde som husdyr, men nu er de blevet som kvæg. Tidligere var der en monolit - en ansøgning. Nu er det 100 mikrotjenester, 100 containere. Nogle beholdere kan have 2-3 replikaer. Det bliver mindre vigtigt for os at kontrollere hver container. Hvad der er vigtigere for os, er tilgængeligheden af ​​selve tjenesten: hvad dette sæt containere gør. Dette ændrer tilgang til overvågning.

I 2014-2015 blomstrede Docker - teknologien, som vi vil tale om nu.

Docker ændrede filosofien og standardiserede applikationsemballagen. Ved hjælp af Docker kan vi pakke en applikation, sende den til et lager, downloade den derfra og implementere den.

Vi lægger alt, hvad vi har brug for, i Docker-containeren, så afhængighedsproblemet er løst. Docker garanterer reproducerbarhed. Jeg tror, ​​at mange mennesker er stødt på irreproducerbarhed: alt fungerer for dig, du skubber det til produktion, og der holder det op med at virke. Med Docker forsvinder dette problem. Hvis din Docker-container starter og gør, hvad den skal, så vil den med stor sandsynlighed starte i produktion og gøre det samme der.

Digression om overhead

Der er altid uenighed om faste omkostninger. Nogle mennesker mener, at Docker ikke bærer en ekstra belastning, da den bruger Linux-kernen og alle dens processer, der er nødvendige for containerisering. Som, "hvis du siger, at Docker er overhead, så er Linux-kernen overhead."

På den anden side, hvis du går dybere, er der faktisk flere ting i Docker, som med et stræk kan siges at være overhead.

Den første er PID-navneområdet. Når vi placerer en proces i et navneområde, tildeles den PID 1. Samtidig har denne proces et andet PID, som er placeret på værtsnavnerummet, uden for containeren. For eksempel lancerede vi Nginx i en container, det blev PID 1 (masterproces). Og på værten har den PID 12623. Og det er svært at sige, hvor meget overhead det er.

Den anden ting er Cgroups. Lad os tage Cgroups efter hukommelse, det vil sige evnen til at begrænse hukommelsen i en beholder. Når det er aktiveret, aktiveres tællere og hukommelsesregnskab: kernen skal forstå, hvor mange sider der er blevet tildelt, og hvor mange der stadig er ledige til denne beholder. Dette er muligvis en overhead, men jeg har ikke set nogen præcise undersøgelser af, hvordan det påvirker ydeevnen. Og jeg har ikke selv bemærket, at applikationen, der kører i Docker, pludselig oplevede et kraftigt tab i ydeevne.

Og endnu en bemærkning om ydeevne. Nogle kerneparametre sendes fra værten til containeren. Især nogle netværksparametre. Derfor, hvis du vil køre noget højtydende i for eksempel Docker, noget der aktivt vil bruge netværket, så skal du i det mindste justere disse parametre. Nogle nf_conntrack, for eksempel.

Om Docker-konceptet

Docker består af flere komponenter:

  1. Docker Daemon er den samme Container Engine; lancerer containere.
  2. Docker CII er et Docker-administrationsværktøj.
  3. Dockerfile - instruktioner om hvordan man bygger et billede.
  4. Billede — det billede, hvorfra beholderen rulles ud.
  5. Beholder.
  6. Docker registry er et billedlager.

Skematisk ser det sådan ud:

Hvad er Docker: en kort udflugt til historie og grundlæggende abstraktioner

Docker-dæmonen kører på Docker_host og starter containere. Der er en klient, der sender kommandoer: byg billedet, download billedet, start containeren. Docker-dæmonen går til registreringsdatabasen og udfører dem. Docker-klienten kan få adgang både lokalt (til en Unix-socket) og via TCP fra en fjernvært.

Lad os gennemgå hver komponent.

Docker-dæmon - dette er serverdelen, den virker på værtsmaskinen: downloader billeder og starter containere fra dem, opretter et netværk mellem containere, samler logfiler. Når vi siger "skab et billede", gør dæmonen også det.

Docker CLI — Docker-klientdel, konsolværktøj til at arbejde med dæmonen. Jeg gentager, det kan ikke kun fungere lokalt, men også over netværket.

Grundlæggende kommandoer:

docker ps - vis containere, der i øjeblikket kører på Docker-værten.
docker-billeder - vis billeder, der er downloadet lokalt.
docker-søgning <> - søg efter et billede i registreringsdatabasen.
docker pull <> - download et billede fra registreringsdatabasen til maskinen.
docker build < > - saml billedet.
docker run <> - start containeren.
docker rm <> - fjern beholderen.
docker logs <> - container logs
docker start/stop/genstart <> - arbejder med containeren

Hvis du mestrer disse kommandoer og er sikker på at bruge dem, skal du betragte dig selv som 70 % dygtig til Docker på brugerniveau.

Dockerfil - instruktioner til oprettelse af et billede. Næsten hver instruktionskommando er et nyt lag. Lad os se på et eksempel.

Hvad er Docker: en kort udflugt til historie og grundlæggende abstraktioner

Sådan ser Dockerfilen ud: kommandoer til venstre, argumenter til højre. Hver kommando, der er her (og generelt skrevet i Dockerfilen) opretter et nyt lag i billedet.

Selv ser man på venstre side, kan man nogenlunde forstå, hvad der sker. Vi siger: "opret en mappe til os" - dette er et lag. "Få mappen til at fungere" er et andet lag, og så videre. Lagkage gør livet lettere. Hvis jeg opretter en anden Dockerfile og ændrer noget i den sidste linje - jeg kører noget andet end "python" "main.py", eller installerer afhængigheder fra en anden fil - så vil de tidligere lag blive genbrugt som en cache.

Billede - dette er containeremballage; containere startes fra billedet. Hvis vi ser på Docker fra en pakkemanagers synspunkt (som om vi arbejdede med deb- eller rpm-pakker), så er image i det væsentlige en rpm-pakke. Gennem yum install kan vi installere applikationen, slette den, finde den i lageret og downloade den. Det er omtrent det samme her: containere lanceres fra billedet, de gemmes i Docker-registret (svarende til yum, i et lager), og hvert billede har en SHA-256-hash, et navn og et tag.

Billedet er bygget i henhold til instruktionerne fra Dockerfilen. Hver instruktion fra Dockerfilen opretter et nyt lag. Lag kan genbruges.

Docker-registret er et Docker-billedlager. I lighed med operativsystemet har Docker et offentligt standardregister - dockerhub. Men du kan bygge dit eget lager, dit eget Docker-register.

Container - hvad der lanceres fra billedet. Vi byggede et billede i henhold til instruktionerne fra Dockerfilen, og derefter starter vi det fra dette billede. Denne beholder er isoleret fra andre beholdere og skal indeholde alt det nødvendige for, at applikationen kan fungere. I dette tilfælde en beholder - en proces. Det sker, at du skal lave to processer, men det er lidt i modstrid med Docker-ideologien.

Kravet til "én beholder, én proces" er relateret til PID-navneområdet. Når en proces med PID 1 starter i Namespace, hvis den pludselig dør, dør hele containeren også. Hvis to processer kører der: den ene er i live og den anden er død, så vil beholderen stadig fortsætte med at leve. Men dette er et spørgsmål om bedste praksis, vi vil tale om dem i andre materialer.

For at studere funktionerne og det fulde program for kurset mere detaljeret, følg venligst linket: "Docker video kursus'.

Forfatter: Marcel Ibraev, certificeret Kubernetes-administrator, praktiserende ingeniør hos Southbridge, foredragsholder og udvikler af Slurm-kurser.

Kilde: www.habr.com

Tilføj en kommentar