🟡 Intermediate

containerd — runtime pre produkčné Kubernetes

containerd je priemyselný štandard pre kontajnerový runtime. Je to CNCF Graduated projekt, ktorý dnes poháňa väčšinu produkčných Kubernetes klastrov na svete — od spravovaných služieb ako EKS, GKE a AKS až po vlastnú on-premise infraštruktúru. Na rozdiel od Dockera ako celku je containerd minimalistický daemon zameraný čisto na správu životného cyklu kontajnerov, pull a správu obrazov a ich ukladanie.


Vznik a história

Docker Engine, ktorý prišiel na scénu v roku 2013, bol spočiatku monolitická aplikácia. S rastúcim ekosystémom sa ukázalo, že je potrebné vyčleniť nízkoúrovňový runtime do samostatnej, znovu použiteľnej knižnice. V roku 2016 Docker Inc. vyextrahoval jadro runtime logiky do projektu containerd a v marci 2017 ho daroval CNCF (Cloud Native Computing Foundation). Projekt dosiahol CNCF Graduated status v roku 2019 — čím sa zaradil po bok Kubernetes, Prometheus a Envoy ako zrelá produkčná technológia.

Dôvod vzniku bol prostý: Kubernetes potreboval štandardizované rozhranie pre komunikáciu s runtime (CRI — Container Runtime Interface, definované v roku 2016). Docker nebol CRI-kompatibilný, pretože vznikol skôr. Riešením bol dočasný adaptér dockershim priamo v kóde kubeletu. Tento workaround bol problematický — udržiavanie dockershimu bolo záťažou pre core Kubernetes tím a každá nová funkcia CRI sa musela duplicitne implementovať aj pre dockershim. Výsledkom bolo rozhodnutie dockershim odstrániť.


Architektúra containerd

containerd nie je len jednoduchý wrapper nad runc. Je to plnohodnotný daemon s pluginovým modelom, ktorý zabezpečuje celý životný cyklus kontajnera.

┌─────────────────────────────────────────────────────────────┐
│  Kubernetes kubelet / ctr / nerdctl                          │
└────────────────────────┬────────────────────────────────────┘
                         │ gRPC (CRI alebo containerd API)
┌────────────────────────▼────────────────────────────────────┐
│  containerd daemon (/run/containerd/containerd.sock)         │
│                                                              │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────────┐   │
│  │  CRI Plugin  │  │ Content Store│  │  Snapshotter     │   │
│  │ (io.cri.v1)  │  │ (blobs, OCI) │  │ (overlayfs, ...)  │   │
│  └──────────────┘  └──────────────┘  └──────────────────┘   │
│                                                              │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────────┐   │
│  │  Sandbox API │  │  Task Service│  │  Transfer Service│   │
│  └──────────────┘  └──────────────┘  └──────────────────┘   │
└────────────────────────┬────────────────────────────────────┘
                         │ exec + shim API
┌────────────────────────▼────────────────────────────────────┐
│  containerd-shim-runc-v2 (per-kontajner proces)              │
│  └──► runc / crun (OCI runtime — spúšťa kontajner)           │
└─────────────────────────────────────────────────────────────┘

containerd daemon — centrálny long-running proces. Počúva na Unix sockete, spravuje metadáta (uložené v bolt DB), orchestruje snapshoty, pull obrazov a lifecycle kontajnerov.

containerd-shim — ľahký proces sprostredkovateľa, ktorý existuje pre každý bežiaci kontajner. Jeho úlohou je odizolovat containerd daemon od životného cyklu konkrétneho kontajnera — ak containerd reštartuje, kontajnery naďalej bežia. Shim tiež spravuje stdio streamy a exit status.

runc / crun — OCI runtime, ktorý skutočne vytvára kontajner — namespaces, cgroups, seccomp, capabilities. runc je referenčná implementácia v Go. crun je rýchlejšia alternatíva v C, odporúčaná pri vysokej hustote podov (nižšia spotreba pamäte, rýchlejší start).

Content Store — imutabilná blob store pre vrstvy obrazov a manifesty. Organizovaná podľa OCI distribution spec — každý blob adresovaný SHA256 digestom.

Snapshotters — pluginy pre správu filesystémov kontajnerov:

Snapshotter Popis
overlayfs Predvolený na Linuxe, vyžaduje kernel 4.0+, väčšina produkcie
btrfs Native COW snapshoty na btrfs filesystéme
zfs Native ZFS snapshoty, vhodné pre storage-heavy workloady
stargz Lazy-pull — kontajner štartuje skôr, ako sa stiahne celý obraz
native Fallback bez COW, iba pre testovanie

CRI Plugin — vstavaný plugin io.containerd.cri.v1.runtime implementuje Kubernetes Container Runtime Interface. Cez neho kubelet komunikuje s containerd pomocou gRPC.


Vzťah k iným runtimem

Docker a containerd

Docker Desktop a Docker Engine dnes interne používajú containerd ako runtime. Keď spustíte docker run, Docker CLI komunikuje s Docker Engineom, ktorý deleguje prácu na containerd. Inými slovami, ak používate Docker, containerd už beží pod kapotou.

CRI-O

CRI-O je alternatívny runtime implementujúci CRI, vytvorený priamo pre Kubernetes spoločnosťami Red Hat, IBM a Intel. Je úzko špecializovaný — neobsahuje nič, čo nie je potrebné pre Kubernetes. Je predvoleným runtimem na OpenShift. Na rozdiel od containerd neposkytuje standalone CLI na správu kontajnerov mimo K8s.

Mirantis cri-dockerd

Po odstránení dockershimu vydali Mirantis a Docker komunitný nástroj cri-dockerd — adaptér, ktorý implementuje CRI a deleguje volania na Docker Engine. Je to spôsob, ako zachovať Docker ako runtime v Kubernetes bez dockershimu. Pre nové nasadenia sa neodporúča.

Podman

Podman je daemonless nástroj pre správu kontajnerov kompatibilný s Docker CLI. Používa libcontainer (rovnaká knižnica ako runc), ale nepotrebuje bežiaci daemon. Neimplementuje CRI — pre Kubernetes sa bežne nepoužíva ako runtime (existuje experimentálny podman-remote pre niektoré prípady).

Kata Containers, gVisor, youki

Tieto projekty sú alternatívne OCI runtime implementácie:

  • Kata Containers — každý kontajner beží v ľahkej VM (qemu/firecracker), silná izolácia.
  • gVisor — Google sandbox runtime, interceptuje syscally v user space.
  • youki — runc-kompatibilná implementácia v Ruste.

Všetky môžu byť nakonfigurované ako RuntimeClass v Kubernetes a containerd ich orchestruje rovnako ako runc — cez shim vrstvu.


Prečo Kubernetes opustil dockershim

Kubernetes 1.20 (december 2020) označil dockershim ako deprecated. Kubernetes 1.24 (máj 2022) ho definitívne odstránil.

Hlavné dôvody:

  1. Udržiavacia záťaž — dockershim bol špecifický kód v kubelete, ktorý musel sledovať každú verziu Docker Engine.
  2. Redundantná vrstva — Docker → dockershim → containerd. Kubernetes takto komunikoval s containerd cez dve medzivrstvy. Priame CRI volanie na containerd odstraňuje jednu vrstvu.
  3. Funkcionálna parita — CRI definuje štandardné rozhranie; Docker prinášal funkcie (volumes, networking) ktoré Kubernetes nepotreboval a spravoval si vlastné.
  4. Bezpečnosť — dockerd beží ako root a má širší attack surface.

Po migrácii na containerd nahlásili operátori typicky zrýchlenie pod start time, nižšiu spotrebu pamäte a jednoduchší debug (jeden daemon menej).


Inštalácia a CLI nástroje

Inštalácia na Ubuntu/Debian

# Pridanie Docker APT repozitára (obsahuje aj containerd.io)
apt-get install -y ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
  -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
  https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
  > /etc/apt/sources.list.d/docker.list

apt-get update
apt-get install -y containerd.io

# Generovanie predvolenej konfigurácie
containerd config default > /etc/containerd/config.toml

systemctl enable --now containerd

ctr — low-level CLI

ctr je vstavaný CLI nástroj containerd. Je nízkoúrovňový a nie je určený na bežné každodenné použitie — hlavne pre debugging a administráciu.

# Zoznam namespace
ctr namespaces list

# Pull obrazu (do namespace "default")
ctr image pull docker.io/library/nginx:alpine

# Zoznam stiahnutých obrazov
ctr images list

# Spustenie kontajnera (jednoduchý, nie v poda)
ctr run --rm docker.io/library/nginx:alpine mynginx

# Zoznam bežiacich taskov
ctr tasks list

# Exec do bežiaceho kontajnera
ctr tasks exec --exec-id myshell mynginx sh

# Vymazanie obrazu
ctr images rm docker.io/library/nginx:alpine

Dôležitý koncept: containerd používa namespaces na izoláciu kontajnerov a obrazov. Kubernetes používa namespace k8s.io, Docker používa moby. Pri debugovaní K8s podov je preto potrebné:

ctr -n k8s.io tasks list
ctr -n k8s.io images list

nerdctl — Docker-compatible CLI

nerdctl (contaiNERD CTL) je Docker-kompatibilný CLI pre containerd vytvorený komunitou. Pokrýva väčšinu docker príkazov vrátane Compose, rootless a lazy pull.

# Inštalácia nerdctl (full bundle obsahuje aj BuildKit, CNI pluginy)
wget https://github.com/containerd/nerdctl/releases/latest/download/nerdctl-full-2.1.3-linux-amd64.tar.gz
tar -C /usr/local -xzf nerdctl-full-2.1.3-linux-amd64.tar.gz

# Teraz nerdctl funguje ako docker
nerdctl pull nginx:alpine
nerdctl run -d -p 8080:80 --name web nginx:alpine
nerdctl ps
nerdctl logs web
nerdctl exec -it web sh
nerdctl stop web && nerdctl rm web

# nerdctl compose — Docker Compose kompatibilita
nerdctl compose up -d
nerdctl compose down

nerdctl v2.x (2025) je kompatibilný s containerd 1.7 až 2.2 (verzia 1.6 prešla na EOL).


Konfigurácia: /etc/containerd/config.toml

containerd 2.0 zaviedol config version 3 s reorganizovanými plugin cestami. Kritická zmena: CRI plugin premenoval z io.containerd.grpc.v1.cri na io.containerd.cri.v1.runtime.

# /etc/containerd/config.toml
# Platí pre containerd 2.x (config version 3)
version = 3

[plugins.'io.containerd.cri.v1.runtime']
  # Sandbox (pause) kontajner
  sandbox_image = "registry.k8s.io/pause:3.10"

  [plugins.'io.containerd.cri.v1.runtime'.containerd]
    default_runtime_name = "runc"

    [plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc]
      runtime_type = "io.containerd.runc.v2"

      [plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc.options]
        # DÔLEŽITÉ: systemd driver musí byť zarovnaný s kubelet --cgroup-driver
        SystemdCgroup = true

[plugins.'io.containerd.cri.v1.images']
  # Registry mirrors — pull-through cache (napr. lokálne zrkadlo)
  [plugins.'io.containerd.cri.v1.images'.registry]
    [plugins.'io.containerd.cri.v1.images'.registry.mirrors]
      [plugins.'io.containerd.cri.v1.images'.registry.mirrors."docker.io"]
        endpoint = ["https://registry-mirror.example.internal"]
      [plugins.'io.containerd.cri.v1.images'.registry.mirrors."registry.k8s.io"]
        endpoint = ["https://k8s-mirror.example.internal"]

# Metrics endpoint pre Prometheus scraping
[metrics]
  address = "127.0.0.1:1338"
  grpc_histogram = true

Pre containerd 1.x (config version 2) je syntax odlišná — pluginy sú pod io.containerd.grpc.v1.cri a dvojité úvodzovky sú štandard.

# Verifikácia konfigurácie
containerd config dump | head -50

# Reštart po zmene
systemctl restart containerd

Správa obrazov a content store

containerd implementuje OCI Distribution Spec pri pull/push a OCI Image Spec pri ukladaní. Každý blob (vrstva, manifest, config) je uložený SHA256-adresovateľne v content store:

/var/lib/containerd/io.containerd.content.v1.content/blobs/sha256/

Registry mirrors a pull-through cache

Pull-through cache je kľúčová produkčná optimalizácia: miesto priameho sťahovania z internetu cez Docker Hub (rate-limit 100 pull/6h pre anonymných) alebo registry.k8s.io noody pullujú z interného zrkadla. Sardonic server to má nakonfigurované — interný registry mirror cachuje frekventne používané obrazy a eliminuje závislosť od externých registrov pri štarte nových nodov.

Image garbage collection

containerd automaticky zbiera nepoužívané obrazy (GC). V Kubernetes orchestruje GC kubelet cez CRI ImageFsInfo a RemoveImage. Parametre GC sú konfigurovateľné cez kubelet:

--image-gc-high-threshold=85   # % diskového využitia triggering GC
--image-gc-low-threshold=80    # % cieľové po GC

Image store vs snapshot store

V containerd 2.0 bola zavedená separácia image store (metadáta, manifesty) od snapshot store (rozbalené vrstvy filesystému). Predtým boli úzko previazané — teraz umožňujú nezávislú správu a budúce funkcie ako zdieľanie vrstiev medzi rôznymi sandbox typmi.


Snapshotters — deep dive

Snapshotter je kľúčová abstrakcia: zodpovedá za prípravu rootfs pre každý kontajner. Funguje na princípe COW (Copy-on-Write) — každá vrstva je snapshot predchádzajúcej.

overlayfs (predvolený)

Na väčšine moderných Linux distribúcií (kernel 4.0+) je overlayfs najlepšia voľba. Vrstvová štruktúra obrazu sa mapuje priamo na overlay mount — dolné vrstvy sú read-only, horná vrstva (upperdir) je read-write kontajnerová vrstva. Žiadne kopírovanie dat pri čítaní (COW sa aktivuje iba pri zápise).

# Overenie aktívneho snapshottera
containerd config dump | grep -A5 snapshotter

stargz Snapshotter — lazy pull

eStargz (estargz — enhanced STARGZ) je formát obrazu, ktorý umožňuje lazy pull: kontajner môže štartovať ešte predtým, ako sa stiahol celý obraz. Namiesto toho sa stiahnu iba potrebné súbory (na základe TOC — Table of Contents).

Výhoda pri veľkých ML/AI obrazoch (pytorch, tensorflow) kde sú gigabajty dat, ale kontajner pri štarte potrebuje len zlomok súborov.

# Konvertovanie obrazu do eStargz formátu
nerdctl image convert --estargz --oci \
  nginx:alpine \
  registry.example.com/nginx:alpine-estargz

# Push do registra
nerdctl push registry.example.com/nginx:alpine-estargz

# Pri pull s nerdctl + stargz snapshotter sa lazy pull aktivuje automaticky
nerdctl pull registry.example.com/nginx:alpine-estargz

Stargz Snapshotter je samostatný CNCF projekt dostupný ako plugin pre containerd.


Produkčné tipy

Monitoring

containerd od verzie 1.5+ exponuje Prometheus metriky na konfigurovanom endpointe (predvolene 127.0.0.1:1338). Pre scraping v Prometheus:

# prometheus.yml
scrape_configs:
  - job_name: containerd
    static_configs:
      - targets: ["localhost:1338"]

Kľúčové metriky:

  • container_runtime_containerd_container_* — počty, stavy kontajnerov
  • container_runtime_containerd_task_* — operácie na taskoch
  • container_runtime_containerd_snapshotter_* — výkon snapshottera
  • container_runtime_containerd_image_* — pull latencie

Graceful drain noodu

Pri maintenance noodu v Kubernetes je dôležité nezabiť containerd počas drain-ovania:

# Správny postup
kubectl drain node01 --ignore-daemonsets --delete-emptydir-data
# Počkajte kým sa všetky pody presunú
kubectl cordon node01
# Až potom môžete reštartovať alebo updatovať containerd
systemctl restart containerd

Log rotation

containerd samotný používa journald alebo file logging. Pre kontajnerové logy (stdout/stderr) je log rotation nastaviteľná v Kubernetes cez kubelet konfiguráciu. containerd odovzdáva logy cez shim a kubelet ich spravuje.

Plugin model

containerd 2.0 má plnohodnotný plugin model cez gRPC. NRI (Node Resource Interface) umožňuje externým pluginom reagovať na lifecycle udalosti kontajnerov — napr. NUMA topology hints, CPU pinning, hugepages allocation — bez modifikácie containerd samotného.


Gotchas a časté problémy

Cgroup v1 vs v2 driver mismatch

Toto je najčastejší produkčný problém pri migrácii alebo nových nasadeniach. Pravidlo je jednoduché: ak systém používa cgroup v2 (overíte cez stat -fc %T /sys/fs/cgroup/) a init systém je systemd, vždy nastavte SystemdCgroup = true v containerd aj --cgroup-driver=systemd v kubelete. Nesúlad sa prejavuje náhodným zabíjaním kontajnerov alebo OOM errory bez skutočného OOM.

# Overenie verzie cgroup na node
stat -fc %T /sys/fs/cgroup/
# tmpfs = cgroup v1
# cgroup2fs = cgroup v2

# Overenie aktuálneho drivera
containerd config dump | grep SystemdCgroup

Kernel version requirements

  • overlayfs vyžaduje minimálne kernel 4.0 (väčšina distribúcií ho má)
  • Pre niektoré seccomp/apparmor profily sú potrebné novšie kernely
  • btrfs a zfs snapshottery vyžadujú príslušné kernel moduly
  • rootless containerd vyžaduje kernel 5.11+ (user namespaces s overlayfs)

Image rootfs pinning

V produkčnom Kubernetes je dobrá prax pinnúť digest obrazov namiesto tagov:

image: nginx@sha256:a5127daff3d6f4558be7c9b6e70e3c097b55b7fb2be0f4c3bf66f7f65ebe4b5c

containerd content store zaručuje imutabilitu blobs — rovnaký digest vždy znamená rovnaký obsah.

Config version mismatch po upgrade

Pri upgrade z containerd 1.x na 2.x je potrebné regenerovať config — config version 2 a 3 nie sú spätne kompatibilné v plugin cestách:

# Záloha starého configu
cp /etc/containerd/config.toml /etc/containerd/config.toml.bak

# Generovanie nového
containerd config default > /etc/containerd/config.toml

# Následne manuálne pridajte zmeny (registry mirrors, SystemdCgroup, etc.)

Namespace izolácia pri debugovaní K8s podov

Začiatočníci often zabúdajú, že ctr images list bez -n k8s.io zobrazí prázdny zoznam — K8s pody sú v namespace k8s.io:

# Toto nezobrazí K8s obrazy:
ctr images list

# Toto áno:
ctr -n k8s.io images list
ctr -n k8s.io tasks list

Porovnanie: containerd vs CRI-O vs cri-dockerd

Kritérium containerd CRI-O cri-dockerd
Primárny use case Všeobecný runtime (K8s aj standalone) Výlučne Kubernetes K8s s Docker Engine backend
CRI kompatibilita Plná Plná Plná (adaptér)
Standalone CLI ctr, nerdctl Nie cez Docker CLI
Default na EKS, GKE, AKS, kubeadm, K3s OpenShift (RHEL)
Daemon overhead Stredný (~30 MB RAM) Nízky (~15 MB RAM) Vysoký (Docker + dockerd)
Ekosystém Rozsiahly (Docker, CNCF) Red Hat orientovaný Docker oriented
Pod density (150+ podov) Dobré Mierne lepšie Horšie
Maintenance Aktívny (CNCF) Aktívny (Red Hat) Obmedzený
Odporúčanie Väčšina produkcie OpenShift, Red Hat stack Iba migrácia zo starého Docker setup

Záver porovnania: containerd je správna predvolená voľba pre väčšinu tímov. CRI-O je legitímna alternatíva pri extrémnej pod hustote alebo Red Hat/OpenShift prostredí. cri-dockerd je technologický dlh — ak ho používate, naplánujte migráciu.


containerd 2.x — nová éra

containerd 2.0 (november 2024)

Prvý major release od 1.0 v roku 2017. Kľúčové zmeny:

  • Config version 3 — reorganizácia plugin namespace (breaking change pre config.toml)
  • Transfer Service GA — štabilné API pre presun artefaktov medzi zdrojmi a cieľmi (registry, OCI layout, running container)
  • Sandbox API GA — štabilné rozhranie pre multi-container prostredia (pody, VM sandboxes). Umožňuje runtimem ako Kata definovať sandbox lifetime nezávisle od jednotlivých kontajnerov.
  • NRI GA — Node Resource Interface pre externe pluginy
  • Odstránenie deprecated features z 1.x série (napr. starý image service, legacy plugin API)
  • Minimálny kernel: 4.9+, minimálny Go: 1.21+

containerd 2.1 (máj 2025)

  • OCI Image Volumes — Kubernetes 1.31+ feature; volumes priamo z OCI obrazov bez extra PVC. Veľké datasety (ML modely, statické assets) distribuovateľné ako obrazy a mountovateľné ako volumes bez kopírovania do overlay.
  • Sandbox Update API — modifikovanie atribútov existujúceho sandboxu za behu (spec, runtime, labels).
  • Vylepšený snapshotter plugin system — lepšia izolácia a hot-swap snapshotterov.

Kubernetes kompatibilita

  • containerd 1.6.x — Kubernetes 1.20 – 1.29 (EOL)
  • containerd 1.7.x — Kubernetes 1.24 – 1.31 (LTS do 2026-03)
  • containerd 2.0.x — Kubernetes 1.24+ (LTS do 2027-03)
  • containerd 2.1.x — Kubernetes 1.24+ (aktuálna stablená vetva)

Zhrnutie

containerd prešiel od anonymného Docker internals komponentu k CNCF Graduated projektu, ktorý dnes poháňa majoritnú časť cloudovej infraštruktúry. Jeho architektúra — daemon + shim + OCI runtime — dosahuje správnu rovnováhu medzi flexibilitou a jednoduchosťou. Plugin model cez NRI, snapshottery pre rôzne storage backendy a stabilné Sandbox API v 2.x robia z containerd runtime pripravený na ďalšie roky vývoja kontajnerovej infraštruktúry.

Pre nové Kubernetes nasadenia je containerd jasná prvá voľba. Pre existujúce Docker-based prostredia je migrácia na containerd priamočiara a prináša merateľné zlepšenia výkonu a prevádzkovej jednoduchosti.


Zdroje