Začnem s tým, čo všetci poznáme - Docker. Konkrétne jeho architektúrou. Tá je pre mňa výbornou mapou vo svete kontajnerov. Pomáha mi zorientovať sa, ktorá technológia, kde zapadá.
Ako prvé si treba uvedomiť, že Docker je celý ekosystém pre kontajnery. Docker, ktorý mame nainštalovaný, je z pohľadu kódu kompozícia niekoľkých veľkých projektov: Moby, Containerd a Runc.
Klientska aplikácia a Dockerd server
Klientska aplikácia a Dockerd server sú súčasťou projektu Moby. Na prvý pohľad to vyzerá ako klasická klient-server architektúra. Klientom je známy docker
príkaz a serverom je Dockerd, s ktorým klient komunikuje cez REST API.
Dockerd pôvodne zastrešoval všetko potrebné ako zostavovanie obrazov z Dockerfie a ich distribúciu, nastavenie siete, životný cyklus kontajnerov. Neskôr však došlo k oddeleniu životného cyklu kontajnerov do samostatného projektu - Containerd.
Containerd server
Containerd je dnes v úlohe akéhosi režiséra. Jeho hlavnou úlohou je starať sa o kontajnery. Udržuje si dáta a metadáta o každom kontajneri a pripravuje všetko potrebné pre ich beh. Treba zdôrazniť, že Containerd však nie je zodpovedný za samotný beh jedného kontajnera. O to sa stará iná časť - tzv. Behové prostredie (runtime).
Containerd chce byť neutrálny a držať sa tzv. OCI štandardu. Preto neprebral všetku funkcionalitu od Dockerd. Príkadom je zostavenie obrazu z Dockerfile súboru. Táto funkcionalita je výhradne záležitosť Dockerd.
Containerd používa na integrácie gRCP protokol a unix soket /var/run/containerd.sock
. S Containerd vieme komunikovať aj
priamo pomocou príkazu ctr
.
$ ctr image pull docker.io/library/postgres:latest
$ ctr run -d -env POSTGRES_PASSWORD=pwd docker.io/library/postgres:latest pg
$ ctr container list
CONTAINER IMAGE RUNTIME
pg docker.io/library/postgres:latest io.containerd.runc.v2
Práve pri prvom príkaze som si všimol mierne “schizofrenickú” situáciu. Tento obraz totižto neuvidíme cez príkaz:
$ docker images --all
Toto je spôsobené tým, že distribúcia obrazov je implementovana dnes v Dockerd a aj Containerd. Keď som sa
hrabal v kóde Containerd, zistil som že pull
a push
je implementovaná priamo v ctr
. Prakticky nie je súčasťou Containerd servera.
Behové prostrenie - runtime
Behové prostredie je zodpovedné za beh jedného konkrétneho kontajnera. Je to miesto, kde sa odohráva celá ta izolačná mágia. Referenčnou implementáciou behového prostredia je Runc projekt. Runc je dostupná po nainštalovaní Dockeru na Linux systémoch.
$ runc --root /run/docker/runtime-runc/moby list
Runc nevie pracovať s obrazmi. Je na príliš nízkej úrovni. Ak chceme naštartovať kontajner cez Runc, musíme mu pripraviť celý súborový systém kontajnera a konfiguráciu behového prostredia. Poďme si vytvoriť ručne svoj kontajner:
$ mkdir mojkontajner
$ cd mojkontajner
$ mkdir rootfs
Cez Docker vyexportujeme obsah obrazu a skopírujeme celý obsah do rootfs
adresára:
$ docker create --name pg2 postgres:latest
$ docker export pg2 | tar -xvf ./rootfs2.tar --directory ./rootfs
Už len vytvoríme konfiguráciu behového prostredia config.json
a môžeme spustiť náš
prvý ručne vytvorený kontajner:
$ runc spec
$ runc run mojkontajner
Voilà! Výsledkom by mal byť spustený shell
kontajnera. To je spôsobené práve konfiguráciou config.json
,
v ktorom je časť:
"args": [
"sh"
],
Podložka behového prostredia - shim
Runc je klasická terminálová aplikácia. Aby ju mohol Containerd používať pohodlne, tak sa začala používať
malá integračná podložka - shim. Podložky sú obľúbeny koncept vo svete kontajnerov. Konrétne sa používa containerd-shim-runc-v2
. Jej úlohou je prepojiť Containerd a Runc skrz gRPC. Samotná podložka nie je súčasťou Runc projektu, ale Containerd projektu - toto bolo pre mňa zo
začiatku mätúce.
Register
Register je úložisko, ktoré slúži na distribúciu obrazov a je dostupný cez svoje REST API. Register je v podstate HTTP server, kde sú uložené obrazy.
Aby to nebolo až také jednoduché, tak obraz z pohľadu registra nie je jeden monolitický súbor. Obraz je rozdelený na manifest obrazu a bulk dáta. Získanie obrazu tak prebieha nasledovným spôsobom.
K tomu, aby sme vôbec mohli použiť API, musíme mať autorizačný token. V prípade verejných registrov Dockeru nie je potreba mať účet. Token je vystavený autorizačným serverom. Potom môžeme získať manifest obrazu. Z manifestu sa vyčíta zoznam bulk-ov a tie sa začnú sťahovať do systému. Dôvodom je vrstvenie, ktorému sa budem venovať v samostatnom článku. Súčasťou Moby projektu je skript download-frozen-image-v2.sh, v ktorom je tento proces pekne vidieť.
Záver
Pre nás programátorov má Docker architektúra veľmi zaujímavý príbeh evolúcie systému. Docker začínal ako Python skript. Neskôr bol prepísaný do Go a jeho architektúra pripomínala monolit. Až v poslednej fáze došlo k jeho štiepeniu na niekoľko menších “mikro-služieb”. To štiepenie nenastalo, lebo si niekto zmyslel, že je to takto architektonicky krajšie. Nastalo z dôvodu urýchlenia vývoja kontajnerových technológii a zachovania neutrality v rámci OpenSource sveta. Každá časť dnes predstavuje osobitnú doménu s osobitnou komunitou.
Už len pikoška na záver. Mena kontajnerov ako busy-allen
alebo sad-batrik
su dielom generátora pkg/namesgenerator/names-generator.go v Moby projekte.