10. září 2024

Docker a dominance kontejnerizace backendu

V tomhle článku se budu věnovat historii kontejnerů, kontejnerizaci aplikací a historii orchestrace kontejnerů.

Co je to kontejner?

Než se můžeme vůbec bavit o čemkoliv, pojďme si připomenout, co je vlastně kontejner.

Kontejner je balík, který obsahuje aplikaci a všechny její závislosti. Když spustíme takovou kontejnerizovanou aplikaci, engine nebo runtime (například Docker), ta zajistí že proces aplikace běží izolovaně od ostatních procesů na hostitelském stroji. Izolací se myslí oddělení souborového systému, síťových rozhraní (každý kontejner má svůj vlastní localhost), procesů. A také nám umožňuje limitovat, kolik zdrojů (CPU, RAM, disk) může kontejner využít.

Slovník

V článku budu používat několik českých i anglických výrazů. A protože se tyto pojmy často přetěžují a mývají mnoho významů, chtěl bych je zde definovat, jak je budu používat já:

Síla kontejnerů

Jak jsem psal, kontejnery řeší izolaci aplikace od hostitelského stroje, ale to není všechno.

Díky kontejnerům a jejich build procesu, který se dá spustit znovu a znovu kdekoliv a výsledek je vždy stejný, se kontejnery staly univerzálním řešením problému "It works on my machine".

And that is how Docker was born meme

Cože jsou tedy ty výhody?

Docker

Docker Inc. logo

Docker je: projekt, společnost, container runtime (engine), build tool, image registry a nástroj pro orchestraci.

To je na jedno slovo moc, pojďme si to rozepsat:

Alternativy k Dockeru

Jméno image a tag

Každý image má vlastní jméno, které slouží k například k zvolení registry, kam image cheme uložit pomocí push operace. A tag je identifikátor konkrétního buildu. Může se jednat například o git commit hash, git tag nebo něco jiného.

Image které nemají registry, se automaticky berou z Docker Hubu, které je brané jako výchozí registry.

Dalšími veřejným registry jsou například Quay.io nebo GitHub Container Registry (ghcr.io).

Abychom mohli udělat push například do GHCR, musí název imagu obsahovat jeho URL ghcr.io/vojtechmares/container-images/cikit.

Build a push by pak vypadal takto:

export TAG="some-tag"

docker build -t ghcr.io/vojtechmares/container-images/cikit:$TAG .
docker push ghcr.io/vojtechmares/container-images/cikit:$TAG

Tag

Tag slouží k verzování jednotlivých buildů. Pokud nezvolíme tag, použije se automaticky latest.

Na vývojářské verze stačí typicky git commit hash, ale pro produkční verze doporučuji použít verzi, například git tag, aby bylo vidět, ke které verzi zdrojového kódu konkrétní image patří. Což sice commit hash splňuje taky, ale lidé si je typicky moc nepamatují 😄.

Pro větší přehlednost používám pro vývojové verze tag ve formátu $BRANCH-$SHORT_COMMIT_HASH, tedy například main-09a682bf. A pro release verzi s prefixem v a tagem, tedy například v1.17.4.

Díky tomu snadno nastavím v GitLabu pravidla pro mazání starých tagů, aby mi nezabírali místo, ale nechávám všechny release verze.

A pro build a push v GitLab CI vypadá moje pipeline takto:

stages:
  - build
  # ...

build:docker:
  stage: build
  image: docker:git
  services:
    - docker:dind
  variables:
    IMAGE: $CI_REGISTRY_IMAGE
    TAG: $CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA
  before_script:
    - echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
    - docker info
  script:
    - docker buildx create --name website --use
    - docker buildx build --provenance=false --platform linux/amd64,linux/arm64 -t $IMAGE:$TAG --push .
    - docker manifest inspect $IMAGE:$TAG
# ...

Pokud nechcete používat services, můžete nakonfigurovat runner aby rovnou měl v sobě Docker socket. Což s sebou ale nese bezpečností riziko a je třeba tedy takovou konfiguraci dobře zvážit. Víc se o GitLab CI rozepíšu někdy příště. Pokud vás ale zajímá taková konfigurace, koukněte do dokumentace GitLabu.

Efektivní build kontejneru

Kontejnery jsou sice fajn a všechno se dá nacpat do jednoho Dockerfile a hotovo, nic extra. To je sice cesta, ale ne moc optimální. s Dockerfile se dá pracovat nebo využít jiných nástrojů, pro build imagů, tak aby byl výsledek co nejmenší.

Optimalizace výsledného obrazu

Docker buildx

Docker buildx je nástroj, který umožňuje vytvářet image pro různé platformy (amd64, arm64, armv7, ppc64le, s390x, ...), tedy například pro Raspberry Pi, ale i pro cloudové prostředí, kde běží jiná architektura než na vývojovém stroji.

Je to skvělý způsob, jak buildit tzv. multi-platformní image, pro vícero architektur bez nutnosti dělat build na cílových strojích.

Příklad buildu pomocí docker buildx:

# vytvoříme instanci buildx builderu
docker buildx create --name website --use

# build jako takový s --platform flagem
docker buildx build --platform linux/amd64,linux/arm64 -t $IMAGE:$TAG --push .

Build nástroje

Protože ekosystém světa kontejnerů zažívá už několik let obrovský boom, rozrůstá se i množství nástrojů, které nám pomáhají vytvářet image (obrazy) kontejnerů.

12-factor app

12-factor app je metodologie, jak psát moderní aplikace, které jsou snadno škálovatelné a nasaditelné do cloudu.

Dvanáct bodů, které tvoří "12-factor app":

  1. Codebase - One codebase tracked in revision control, many deploys
  2. Dependencies - Explicitly declare and isolate dependencies
  3. Config - Store config in the environment
  4. Backing services - Treat backing services as attached resources
  5. Build, release, run - Strictly separate build and run stages
  6. Processes - Execute the app as one or more stateless processes
  7. Port binding - Export services via port binding
  8. Concurrency - Scale out via the process model
  9. Disposability - Maximize robustness with fast startup and graceful shutdown
  10. Dev/prod parity - Keep development, staging, and production as similar as possible
  11. Logs - Treat logs as event streams
  12. Admin processes - Run admin/management tasks as one-off processes

Proč o 12-factor píšu? Díky kontejnerům se stalo neskutečně snadné používat tuto metodologii. A díky její přímočarosti platí totéž i pro kontejnerizaci, jde to prakticky ruku v ruce. A zároveň dnešní nástroje pro provoz kontejnerů, jako Kubernetes, umožňují přesně takto aplikace provozovat.

Orchestrace

Síla kontejnerů ale není jen v jejich přenositelnosti a univerzálnosti. Kontejnery se neskutečně rozmohly díky rozvoji nástrojů pro jejich orchestraci. Neboli softwaru, který se stará o provoz kontejnerů napříč několika stroji. A to i v řádu tisíců strojů v clusteru!

Jedním z průkopníků orchestrace kontejnerů byl Google, který v roce 2003 začal tvořit interní nástroj Borg, kterým spravovali všechny své clustery a provozovali v něm všechny aplikace. Z Borgu následně vychází open-source projekt Kubernetes, který založili v Googlu v roce 2014. Více o historii Kubernetes jsem psal v čláku Proč Kubernetes?.

Níže jsem se rozepsal o populárních nástrojích pro orchestraci, od managovaných služeb až po řešení, které si můžete provozovat sami.

Docker Swarm

Swarm byl jedním z prvních veřejně dostupných řešeních pro provoz kontejnerizovaných apliací na více strojích zároveň.

Je to velice jednoduchý nástroj, ale nikdy se úplně neprosadil. Pokud chcete provozovat více kontejnerů, pro jeden stroj si vystačíte s Docker Compose. A pro více strojů, je lepší zvolit něco jiného, například Kubernetes které je flexibilnější a umožňuje větší kontrolu a snadnou škálovatelnost.

Apache Mesos

Mesos není úplně nástroj pro orchestraci, spíše by se dal přirovnat k "operačnímu systému pro datacentrum", který umožňuje spouštět různé aplikace, včetně kontejnerů, na více strojích zároveň.

Mesos je letitý projekt, který vznikl v roce 2009 a první release měl v roce 2010. Projekt v byl v roce 2021 málem opuštěn, ale nakonec se tak nestalo, kvůli jeho rozšířenosti u legacy řešení.

Dnes je ale spíš otázkou času, než Mesos zmizí z produkčních prostředí úplně. Například Apache Spark označil podporu pro Mesos jako deprecated ve verzi 3.2 (2021) a podpora bude kompletně ukončena v blízké budoucnosti.

HashiCorp Nomad

Nomad je nástroj od HashiCorpu, který se snaží být jednoduchý, ale zároveň dostatečně flexibilní pro běh kontejnerizovaných ale i nekontejnerizovaných aplikací. A to ať na vlastním železe nebo v cloudu.

Nomad je celkem oblíbený pro jeho jednoduchost, ale jako všechny nástroje pro orchestraci kontejnerů, byl převálcován Kubernetes.

Kubernetes

Nejznámější, nejrozšířenější a prakticky standard pro orchestraci a provoz kontejnerů. Jak v cloudu tak na vlastních strojích.

Jak jsem psal, Kubernetes vychází z interního nástroje Googlu Borg, který byl vyvíjen od roku 2003 a v roce 2014 se zrodilo Kubernetes jako open-source projekt, který umožňuje komukoliv provozovat aplikace na více strojích zároveň v kontejnerech.

Díky CNCF (Cloud Native Computing Foundation) vznikl kolem Kubernetes a cloud-native aplikací a nástrojů obrovský ekosystém, který celý tento kolotoč posouvá kupředu.

CNCF je nezisková organizace spadající pod Linux Foundation, která se stará o rozvoj cloud-native technologií a nástrojů. Aktuálně její roční rozpočet je přes $150M ročně a díky široké členské základně mnoha firem, je celkem imuní vůči zániku jednotlivých firem. A tedy její projekty jsou dlouhodobě v bezpečí a dá se na ně spolehnout, že ze dne na den nezaniknou. A zároveň všechny CNCF projekty jsou open-source pod licencí Apache 2.0.

Kamal

Kamal (původně MRSK), který vytvořil David Heinemeier Hansson, autor frameworku Ruby on Rails a CTO 37signals.

Hansson založil Kamal, který staví nad Dockerem a několika bash skripty, napříč několika stroji. Vadilo mu, že všechny ostatní nástroje jsou neskutečně komplikované a vyžadují celé týmy lidí, kteří se o ně budou starat, jako třeba Kubernetes. Zároveň s odchodem 37signals z cloudu na vlastní železo, nechtěl žádné šílené řešení a tak vzniknul Kamal.

Více o příběhu Kamalu na blogu Hey Kamal 1.0.

V Českých končinách na Kamalu běží například Fakturoid.

Google Cloud Run

Google Cloud Run je služba od Googlu, která umožňuje spouštět kontejnerizované aplikace na Google Cloud Platform.

Cloud Run je dnes postavený nad Kubernetes a Knative, takže si jej teoreticky můžete postavit sami na vlastním železe, ale to není myšlena Cloud Run. Cloud Run naopak řeší všechny problémy s provozováním kontejnerů za vás. Takže akorát je třeba říct jaký image a kolik replik popř. škálovací pravidla.

Cloud Run je velmi pohodlná služba pro provozování kontejnerizovaných aplikací, ale za takový komfort si také připlatíte.

AWS Fargate

Fargate je služba od Amazonu, která umožňuje spouštět kontejnerizované aplikace na AWS. Prakticky se jedná o alternativu ke Google Cloud Run, ale od Amazonu.

Na rozdíl od Cloud Run ale Fargate stojí na Firecrackeru, což je Amazon technologie pro spouštění takzvaných microVM. Jedná se tedy o kompletní virtualizaci operačního systému, ale extrémě optimalizovanou na rychlost. Firecracker je dnes backendem nejen pro Fargate, ale i pro AWS Lambda.

Fly.io

Fly.io je nový hráč na poli provozování kontejnerizovaných apliakcí. Nabízí jednoduché rozhraní a celkově se jedná o velice pohodlnou službu, na které snadno spustíte i databázi, kterou potřebujete, připojíte storage apod. to vše v kontejnerech.

Fly.io nesází na Kubernetes, ale na vlastní systém, který je komplet postavený od nuly v Rustu a sítě jsou postavené nad WireGuardem.

Docker školení

Chcete provozovat Vaše aplikace v kontejnerech a přestat řešit, že na serveru je třeba aktualizovat knohovnu XY nebo verzi runtimu? Začněte používat Docker. Přijďte na školení o Dockeru a nakopněte Váš vývoj kupředu. Přihlaste se buď na veřejný termín nebo mě kontaktujte ohledně firemního školení.