Що таке containerd і яка його роль в Docker-екосистемі?
containerd це production-grade container-runtime, що живе між high-level оркестраторами (Docker, Kubernetes) і low-level OCI-runtime (runc). Це один з найуспішніших infrastructure-компонентів, про який ніхто не говорить, тихо крутить більшість container у світі.
Теорія
TL;DR
- containerd = container-daemon. Керує container-life-cycle: pull image, unpack, run, monitor, network-setup.
- Спочатку витягнутий з Docker у 2017 як окремий компонент, тоді donated CNCF у 2019. CNCF graduated проект.
- Використовується Docker (daemon-стек:
dockerd → containerd → runc). - Використовується Kubernetes напряму (з 1.24, dockershim видалено).
- Tooling:
ctr(low-level admin),nerdctl(Docker-CLI-сумісний). - runc нижче containerd, runc створює один container на invocation; containerd керує long-running orchestration.
Де containerd сидить
+----------------------------------------+
| User-facing tools |
| docker / kubectl / podman / |
| ctr / nerdctl |
+----------------------------------------+
| |
+---------v-----+ +------v-----------+
| dockerd | | kubelet |
| (Docker only) | | (Kubernetes only)|
+---------------+ +------------------+
| |
+----+ +----+
v v
+---------------+
| containerd |
| (CRI server) |
+---------------+
|
+---------------+
| OCI-runtime |
| runc / kata |
| gVisor / etc |
+---------------+
|
+---------------+
| Container |
| (процес) |
+---------------+Docker-користувачі б'ють dockerd, що делегує containerd. Kubernetes-користувачі б'ють kubelet, що використовує containerd напряму через CRI (Container Runtime Interface). Обидва врешті у тому самому containerd, потім runc.
Чому containerd було витягнуто
У 2014-2016 Docker був монолітом, що робив усе. Два тиски виникли:
- Kubernetes хотів runtime без решти Docker (без
docker build, без Docker CLI, без Swarm). Просто «керувати container». - Стандартизація — OCI-ініціатива хотіла чіткий контракт для runtime. Внутрішній код Docker не мав чистої абстракції.
Docker (компанія) витягнув containerd у 2017, donate'нув CNCF і reshape'нув Docker daemon, щоб використовувати containerd внутрішньо. Результат: той самий Docker, але runtime-шар тепер reusable будь-ким.
Що containerd реально робить
- Image-management: pull з registry, зберігання шарів, підготовка rootfs.
- Container-life-cycle: create, start, stop, pause, resume, kill, delete.
- Snapshot-management: використовує storage-drivers (overlayfs, btrfs тощо) для управління filesystem-snapshot.
- Process-supervision: через
containerd-shim(один shim на container, переживає рестарти daemon). - Networking-handoff: САМ networking не робить; делегує CNI-плагінам (Kubernetes) або callback-API (Docker).
- Метрики і події: експозить container-метрики; емітить події, на які оркестратори підписуються.
Що не робить:
- Білд image (це buildkit / docker build / kaniko).
- Дає CLI для end-users (бери
ctrабоnerdctl). - Network-policy / orchestration (це Kubernetes / Swarm / Cilium / Calico).
- High-level UX (Docker дає це Docker-користувачам).
ctr — low-level admin-tool
Шиппиться з containerd. Говорить з gRPC API containerd напряму:
# List image
ctr images list
# Pull image
ctr images pull docker.io/library/alpine:3.21
# Запуск container
ctr run --rm docker.io/library/alpine:3.21 mytest /bin/sh
# Список running-task
ctr tasks listНе user-friendly; задумано для debug або low-level admin. Зверни увагу: containerd використовує namespaces для розділення клієнтів, Docker використовує moby, Kubernetes k8s.io. Щоб побачити Docker-container через ctr: ctr -n moby containers list.
nerdctl — Docker-сумісний CLI
nerdctl run --rm hello-world # як docker run
nerdctl ps
nerdctl images
nerdctl compose up -d # Compose-підтримка тежnerdctl говорить Docker-style командами, але говорить з containerd напряму (без dockerd). Корисно у K8s-node, де Docker не встановлено, але container running.
containerd у Kubernetes (post-dockershim)
Kubernetes 1.24 (квітень 2022) видалив dockershim, compatibility-шар, що давав kubelet говорити з dockerd. Тепер kubelet говорить з containerd напряму через CRI:
# /etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sockПряміше, простіше, менше moving-parts. crictl це Kubernetes-flavored CLI для debug на цьому шарі.
Типові помилки
Плутати containerd з runc
Люди часто думають, що вони взаємозамінні. Не так.
- runc це one-shot CLI, що створює один container на invocation, тоді виходить. Реалізує OCI Runtime Spec.
- containerd це long-running daemon, що керує life-cycle багатьох container. Викликає runc як tool.
Сприймати containerd як Docker-специфічний
Не так. Kubernetes використовує containerd без Docker. Те саме podman (через crun, схоже, але інше). containerd це незалежна інфраструктура, що Docker випадково теж використовує.
Спроба використати Docker-image на Kubernetes через маніпуляцію /var/lib/docker
Kubernetes containerd використовує /var/lib/containerd/, НЕ Docker /var/lib/docker/. Вони ізольовані. Щоб переміщати image, push у registry і pull на іншій стороні, або бери nerdctl save/load.
Плутати ctr -n moby і ctr -n k8s.io
Namespace containerd (moby, k8s.io, default) це ізоляція між клієнтами. Docker-container живуть у moby, K8s у k8s.io. Дефолтні ctr-команди query'їть default і нічого не знаходить.
Реальне застосування
- Усі великі cloud-Kubernetes (EKS, GKE, AKS) беруть containerd як runtime.
- Docker Engine використовує containerd внутрішньо (з Docker 18.09).
- Edge / IoT: lightweight-footprint containerd робить його популярним на resource-constrained пристроях.
- CRI-O (альтернатива containerd, використовується деякими OpenShift-деплоями) — та сама роль, інша реалізація. Обидва реалізують CRI Kubernetes.
Питання для поглиблення
Q: Яка різниця між containerd і Docker?
A: Docker це повна платформа: CLI, daemon (dockerd), build-tools, registry-client, networking, image-management. containerd це лише container-runtime частина — pull image, run container, manage life-cycle. Docker використовує containerd внутрішньо.
Q: Яка різниця між containerd і CRI-O?
A: Обидва реалізують Container Runtime Interface (CRI) Kubernetes. containerd ширший, використовується і Docker. CRI-O K8s-специфічний, легший. Функціонально еквівалентні для K8s; різні спільноти і design-філософії.
Q: Як containerd взаємодіє з OCI-runtime?
A: Через runtime-spec інтерфейс. containerd пише config.json (OCI Runtime Spec) і просить runtime (runc, kata, gVisor) створити container. Runtime викликається раз на container-старт; containerd-shim тоді supervise'їть.
Q: Що таке containerd-shim?
A: Малий процес на container, що тримає container stdin/stdout/stderr і переживає рестарт containerd. Якщо containerd помирає, shim тримає container живим; коли containerd повертається, він reconnect'ується через shim.
Q: (Senior) Як мігрувати workload з Docker на containerd-direct (без Docker-daemon)?
A: Kubernetes-managed: зміни kubelet-config показувати на containerd; видали dockershim-бінари (сучасний K8s уже це робить). Image-формат OCI, без конверсії. Image-pull працюють ідентично (той самий registry-протокол). Volume через CSI-плагіни. Networking через CNI-плагіни. Міграція переважно audit: що залежало від Docker-специфічної поведінки (Docker-socket-mounts у pod, посилання на /var/lib/docker)? Refactor цього. Для non-K8s сценаріїв заміни docker run на nerdctl run або podman run, ті самі флаги, інша daemon-модель.
Приклади
Inspecting Docker containerd
# List Docker container через ctr
sudo ctr -n moby containers list
CONTAINER IMAGE RUNTIME
a3f9d2b8c1e4f3a2... - io.containerd.runc.v2
# Те саме для K8s
sudo ctr -n k8s.io containers listNamespace-вибір (-n) направляє query у правильний slice стану containerd.
Використання nerdctl замість docker
# nerdctl працює рівно як docker
nerdctl run -d --name web -p 8080:80 nginx
nerdctl ps
nerdctl logs web
nerdctl compose up -d
# Але під капотом, без dockerd — лише containerd.
ps -ef | grep dockerd
# (нічого)
ps -ef | grep containerd
containerd ...Корисно у середовищах, де Docker свідомо не встановлено (деякі K8s-node, hardened-host).
Розгляд handoff containerd → runc
# Коли container стартує, можна побачити ланцюг
$ ps -ef | grep -E 'containerd|runc' | grep -v grep
root 1235 1 /usr/bin/containerd
root 4567 1235 containerd-shim-runc-v2 -id abc123 ...
# Сам runc не у списку, він пробіг і вийшов
# Процес container parent'нутий shim'ом (4567)runc-invocation короткий; shim це що залишається. containerd це long-running daemon, що orchestrate'ить усе.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.
Коментарі
Ще немає коментарів