Hva er Docker: en kort utflukt til historie og grunnleggende abstraksjoner

Startet 10. august i Slurm Docker videokurs, der vi analyserer det fullstendig - fra grunnleggende abstraksjoner til nettverksparametere.

I denne artikkelen vil vi snakke om historien til Docker og dens viktigste abstraksjoner: Image, Cli, Dockerfile. Foredraget er beregnet for nybegynnere, så det er neppe interessant for erfarne brukere. Det vil ikke være blod, blindtarm eller dyp nedsenking. Det helt grunnleggende.

Hva er Docker: en kort utflukt til historie og grunnleggende abstraksjoner

Hva er Docker

La oss se på definisjonen av Docker fra Wikipedia.

Docker er programvare for automatisering av distribusjon og administrasjon av applikasjoner i containeriserte miljøer.

Ingenting er klart fra denne definisjonen. Det er spesielt uklart hva "i miljøer som støtter containerisering" betyr. For å finne ut av det, la oss gå tilbake i tid. La oss starte med epoken som jeg konvensjonelt kaller den "monolittiske epoken."

Monolittisk tid

Den monolittiske epoken er tidlig på 2000-tallet, da alle applikasjoner var monolittiske, med en haug med avhengigheter. Utviklingen tok lang tid. Samtidig var det ikke mange servere; vi kjente dem alle ved navn og overvåket dem. Det er en så morsom sammenligning:

Kjæledyr er husdyr. I den monolittiske epoken behandlet vi serverne våre som kjæledyr, pleiet og elsket, og blåste bort støvflekker. Og for bedre ressursstyring brukte vi virtualisering: vi tok en server og kuttet den i flere virtuelle maskiner, og sikret dermed isolasjon av miljøet.

Hypervisor-baserte virtualiseringssystemer

Alle har sikkert hørt om virtualiseringssystemer: VMware, VirtualBox, Hyper-V, Qemu KVM osv. De gir applikasjonsisolasjon og ressursstyring, men de har også ulemper. For å gjøre virtualisering trenger du en hypervisor. Og hypervisoren er en ressursoverhead. Og selve den virtuelle maskinen er vanligvis en hel koloss – et tungt bilde som inneholder et operativsystem, Nginx, Apache, og muligens MySQL. Bildet er stort og den virtuelle maskinen er upraktisk å betjene. Som et resultat kan det gå tregt å jobbe med virtuelle maskiner. For å løse dette problemet ble virtualiseringssystemer laget på kjernenivå.

Virtualiseringssystemer på kjernenivå

Virtualisering på kjernenivå støttes av OpenVZ, Systemd-nspawn, LXC-systemer. Et slående eksempel på slik virtualisering er LXC (Linux Containers).

LXC er et virtualiseringssystem på operativsystemnivå for å kjøre flere isolerte forekomster av Linux-operativsystemet på en enkelt node. LXC bruker ikke virtuelle maskiner, men lager et virtuelt miljø med eget prosessrom og nettverksstack.

I hovedsak lager LXC containere. Hva er forskjellen mellom virtuelle maskiner og containere?

Hva er Docker: en kort utflukt til historie og grunnleggende abstraksjoner

Beholderen er ikke egnet for å isolere prosesser: sårbarheter finnes i virtualiseringssystemer på kjernenivå som lar dem flykte fra beholderen til verten. Derfor, hvis du trenger å isolere noe, er det bedre å bruke en virtuell maskin.

Forskjellene mellom virtualisering og containerisering kan sees i diagrammet.
Det er maskinvarehypervisorer, hypervisorer på toppen av operativsystemet og containere.

Hva er Docker: en kort utflukt til historie og grunnleggende abstraksjoner

Maskinvarehypervisorer er kule hvis du virkelig ønsker å isolere noe. Fordi det er mulig å isolere på nivå med minnesider og prosessorer.

Det er hypervisorer som et program, og det er containere, og vi skal snakke om dem videre. Containeriseringssystemer har ikke en hypervisor, men det er en containermotor som lager og administrerer containere. Denne tingen er mer lett, så på grunn av å jobbe med kjernen er det mindre overhead eller ingen i det hele tatt.

Hva brukes til containerisering på kjernenivå

Hovedteknologiene som lar deg lage en beholder isolert fra andre prosesser er navneområder og kontrollgrupper.

Navneområder: PID, Nettverk, Montering og Bruker. Det er flere, men for å lette forståelsen vil vi fokusere på disse.

PID-navneområde begrenser prosesser. Når vi for eksempel lager et PID-navneområde og plasserer en prosess der, blir det med PID 1. Vanligvis i systemer er PID 1 systemd eller init. Følgelig, når vi plasserer en prosess i et nytt navneområde, mottar den også PID 1.

Nettverksnavneområde lar deg begrense/isolere nettverket og plassere dine egne grensesnitt inne. Mount er en filsystembegrensning. Bruker – begrensning på brukere.

Kontrollgrupper: Minne, CPU, IOPS, Nettverk - ca 12 innstillinger totalt. Ellers kalles de også C-grupper ("C-grupper").

Kontrollgrupper administrerer ressurser for en beholder. Gjennom Control Groups kan vi si at containeren ikke skal forbruke mer enn en viss mengde ressurser.

For at containerisering skal fungere fullt ut, brukes ytterligere teknologier: Capabilities, Copy-on-write og andre.

Evner er når vi forteller en prosess hva den kan og ikke kan gjøre. På kjernenivå er dette ganske enkelt punktgrafikk med mange parametere. For eksempel har root-brukeren fulle rettigheter og kan gjøre alt. Tidsserveren kan endre systemtiden: den har funksjoner på Time Capsule, og det er det. Ved å bruke privilegier kan du fleksibelt konfigurere begrensninger for prosesser, og dermed beskytte deg selv.

Copy-on-write-systemet lar oss jobbe med Docker-bilder og bruke dem mer effektivt.

Docker har for tiden kompatibilitetsproblemer med Cgroups v2, så denne artikkelen fokuserer spesifikt på Cgroups v1.

Men la oss gå tilbake til historien.

Da virtualiseringssystemer dukket opp på kjernenivå, begynte de å bli aktivt brukt. Overheaden på hypervisoren forsvant, men noen problemer gjensto:

  • store bilder: de skyver et operativsystem, biblioteker, en haug med forskjellig programvare inn i samme OpenVZ, og til slutt viser bildet seg fortsatt å være ganske stort;
  • Det er ingen normal standard for pakking og levering, så problemet med avhengigheter gjenstår. Det er situasjoner når to stykker kode bruker samme bibliotek, men med forskjellige versjoner. Det kan være en konflikt mellom dem.

For å løse alle disse problemene er neste æra kommet.

Container-æra

Da Era of Containers kom, endret filosofien om å jobbe med dem seg:

  • Én prosess - én beholder.
  • Vi leverer alle avhengighetene prosessen trenger til sin container. Dette krever å kutte monolitter til mikrotjenester.
  • Jo mindre bildet er, jo bedre – det er færre mulige sårbarheter, det ruller ut raskere, og så videre.
  • Forekomster blir flyktige.

Husker du hva jeg sa om kjæledyr vs storfe? Tidligere var instanser som husdyr, men nå har de blitt som storfe. Tidligere var det en monolitt - en applikasjon. Nå er det 100 mikrotjenester, 100 containere. Noen beholdere kan ha 2-3 kopier. Det blir mindre viktig for oss å kontrollere hver container. Det som er viktigere for oss er tilgjengeligheten til selve tjenesten: hva dette settet med containere gjør. Dette endrer tilnærmingen til overvåking.

I 2014-2015 blomstret Docker – teknologien vi skal snakke om nå.

Docker endret filosofien og standardiserte applikasjonspakningen. Ved å bruke Docker kan vi pakke en applikasjon, sende den til et depot, laste den ned derfra og distribuere den.

Vi legger alt vi trenger i Docker-beholderen, så avhengighetsproblemet er løst. Docker garanterer reproduserbarhet. Jeg tror mange har møtt irreproduserbarhet: alt fungerer for deg, du presser det til produksjon, og der slutter det å fungere. Med Docker forsvinner dette problemet. Hvis Docker-beholderen din starter og gjør det den trenger, vil den med stor sannsynlighet starte i produksjon og gjøre det samme der.

Digresjon om overhead

Det er alltid uenighet om faste kostnader. Noen mennesker tror at Docker ikke har en ekstra belastning, siden den bruker Linux-kjernen og alle dens prosesser som er nødvendige for containerisering. Som, "hvis du sier at Docker er overhead, så er Linux-kjernen overhead."

På den annen side, hvis du går dypere, er det faktisk flere ting i Docker som, med en strekning, kan sies å være overhead.

Den første er PID-navneområdet. Når vi plasserer en prosess i et navneområde, blir den tildelt PID 1. Samtidig har denne prosessen en annen PID, som ligger på vertsnavneområdet, utenfor containeren. For eksempel lanserte vi Nginx i en container, det ble PID 1 (masterprosess). Og på verten har den PID 12623. Og det er vanskelig å si hvor mye overhead det er.

Den andre tingen er Cgroups. La oss ta Cgroups etter minne, det vil si muligheten til å begrense minnet til en beholder. Når det er aktivert, aktiveres tellere og minneregnskap: kjernen må forstå hvor mange sider som er tildelt og hvor mange som fortsatt er ledige for denne beholderen. Dette er muligens en overhead, men jeg har ikke sett noen presise studier på hvordan det påvirker ytelsen. Og selv la jeg ikke merke til at applikasjonen som kjører i Docker plutselig opplevde et kraftig tap i ytelse.

Og en merknad til om ytelse. Noen kjerneparametere sendes fra verten til beholderen. Spesielt noen nettverksparametere. Derfor, hvis du ønsker å kjøre noe med høy ytelse i Docker, for eksempel, noe som aktivt vil bruke nettverket, så må du i det minste justere disse parameterne. Noen nf_conntrack, for eksempel.

Om Docker-konseptet

Docker består av flere komponenter:

  1. Docker Daemon er den samme containermotoren; lanserer containere.
  2. Docker CII er et Docker-administrasjonsverktøy.
  3. Dockerfile - instruksjoner om hvordan du bygger et bilde.
  4. Bilde — bildet som beholderen rulles ut fra.
  5. Container.
  6. Docker registry er et bildelager.

Skjematisk ser det omtrent slik ut:

Hva er Docker: en kort utflukt til historie og grunnleggende abstraksjoner

Docker daemon kjører på Docker_host og lanserer containere. Det er en klient som sender kommandoer: bygg bildet, last ned bildet, start beholderen. Docker-demonen går til registeret og kjører dem. Docker-klienten kan få tilgang både lokalt (til en Unix-socket) og via TCP fra en ekstern vert.

La oss gå gjennom hver komponent.

Docker-demon - dette er serverdelen, den fungerer på vertsmaskinen: laster ned bilder og starter containere fra dem, lager et nettverk mellom containere, samler logger. Når vi sier «lag et bilde», gjør demonen det også.

Docker CLI — Docker-klientdel, konsollverktøy for å jobbe med daemonen. Jeg gjentar, det kan fungere ikke bare lokalt, men også over nettverket.

Grunnleggende kommandoer:

docker ps - vis containere som for øyeblikket kjører på Docker-verten.
docker-bilder - vis bilder lastet ned lokalt.
docker-søk <> - søk etter et bilde i registret.
docker pull <> - last ned et bilde fra registret til maskinen.
docker build < > - samle bildet.
docker run <> - start beholderen.
docker rm <> - fjern beholderen.
docker logger <> - container logger
docker start/stopp/restart <> - arbeider med containeren

Hvis du mestrer disse kommandoene og er trygg på å bruke dem, anser deg selv som 70 % dyktig i Docker på brukernivå.

Dockerfile - instruksjoner for å lage et bilde. Nesten hver instruksjonskommando er et nytt lag. La oss se på et eksempel.

Hva er Docker: en kort utflukt til historie og grunnleggende abstraksjoner

Dette er hvordan Dockerfilen ser ut: kommandoer til venstre, argumenter til høyre. Hver kommando som er her (og vanligvis skrevet i Dockerfilen) lager et nytt lag i bildet.

Selv om du ser på venstre side, kan du omtrent forstå hva som skjer. Vi sier: "opprett en mappe for oss" - dette er ett lag. "Få mappen til å fungere" er et annet lag, og så videre. Lagkake gjør livet enklere. Hvis jeg oppretter en annen Dockerfil og endrer noe på den siste linjen - jeg kjører noe annet enn "python" "main.py", eller installerer avhengigheter fra en annen fil - så vil de tidligere lagene bli gjenbrukt som en cache.

Bilde - dette er containeremballasje; containere lanseres fra bildet. Hvis vi ser på Docker fra synspunktet til en pakkebehandler (som om vi jobbet med deb- eller rpm-pakker), så er image i hovedsak en rpm-pakke. Gjennom yum install kan vi installere applikasjonen, slette den, finne den i depotet og laste den ned. Det er omtrent det samme her: containere lanseres fra bildet, de lagres i Docker-registeret (i likhet med yum, i et depot), og hvert bilde har en SHA-256-hash, et navn og en tag.

Bildet er bygget i henhold til instruksjonene fra Dockerfilen. Hver instruksjon fra Dockerfilen lager et nytt lag. Lag kan gjenbrukes.

Docker-registeret er et Docker-bildelager. I likhet med operativsystemet har Docker et offentlig standardregister - dockerhub. Men du kan bygge ditt eget depot, ditt eget Docker-register.

Container - hva som lanseres fra bildet. Vi bygde et bilde i henhold til instruksjonene fra Dockerfile, så starter vi det fra dette bildet. Denne beholderen er isolert fra andre beholdere og må inneholde alt som er nødvendig for at applikasjonen skal fungere. I dette tilfellet, en beholder - en prosess. Det hender at du må gjøre to prosesser, men dette er litt i strid med Docker-ideologien.

"én beholder, en prosess"-kravet er relatert til PID-navneområdet. Når en prosess med PID 1 starter i Namespace, hvis den plutselig dør, dør hele beholderen også. Hvis to prosesser kjører der: den ene er i live og den andre er død, vil beholderen fortsatt leve. Men dette er et spørsmål om beste praksis, vi vil snakke om dem i andre materialer.

For å studere funksjonene og hele programmet til kurset mer detaljert, vennligst følg lenken: "Docker videokurs'.

Forfatter: Marcel Ibraev, sertifisert Kubernetes-administrator, praktiserende ingeniør ved Southbridge, foredragsholder og utvikler av Slurm-kurs.

Kilde: www.habr.com

Legg til en kommentar