Docker без Docker: Podman, containerd, nerdctl, Buildah

Рейтинг: 59.6% · 10 голосов
Практический курс по Docker: образы, контейнеры, тома, сети, Compose и продакшен. Уроки по главам с обсуждением.
Ответить
Аватара пользователя
Marina_DevOps
Сообщения: 54
Зарегистрирован: 11 май 2026, 05:31

Docker без Docker: Podman, containerd, nerdctl, Buildah

Сообщение Marina_DevOps »

Оглавление курса (46)
  1. Что такое Docker и какие задачи он решает
  2. Установка Docker и запуск первого контейнера
  3. Образы: слои, теги и реестр Docker Hub
  4. Пишем свой Dockerfile
  5. Тома и хранение данных: volumes и bind mounts
  6. Сети в Docker: связываем контейнеры между собой
  7. Переменные окружения и конфигурация контейнеров
  8. Docker Compose: поднимаем многоконтейнерное приложение
  9. Оптимизация образов: multi-stage сборка, размер и кэш слоёв
  10. Логи, отладка и мониторинг контейнеров
  11. Базовая безопасность контейнеров
  12. Подготовка к продакшену: что важно учесть
  13. Dockerfile глубже: ENTRYPOINT и CMD, HEALTHCHECK, .dockerignore, запуск не от root
  14. Реестры образов: приватные registry, push и pull, теги и digest, imagePullSecrets
  15. BuildKit и buildx: multi-arch сборки, секреты сборки, экспорт кэша
  16. Docker в CI/CD: автосборка, сканирование образов (Trivy, Docker Scout), публикация
  17. Итоговый проект и куда расти: от Dockerfile до прода, обзор оркестрации (Kubernetes, Podman, OCI)
  18. Архитектура Docker: dockerd, containerd, runc и OCI
  19. Как работает изоляция: namespaces и cgroups
  20. Образы изнутри: слои, OverlayFS и storage driver
  21. Жизненный цикл контейнера и политики перезапуска
  22. Отладка контейнеров: exec, attach, nsenter, debug
  23. Сети Docker глубже: bridge, overlay, macvlan и iptables
  24. Docker Compose глубже: profiles, healthcheck-зависимости, override
  25. Данные и тома глубже: драйверы, бэкап, права
  26. Секреты и конфигурация: как не светить пароли
  27. Ограничение ресурсов: CPU, память, OOM и cgroups
  28. Здоровье и автозапуск: HEALTHCHECK, init и сигналы
  29. Логирование контейнеров: драйверы, ротация, сбор
  30. Мониторинг контейнеров: stats, cAdvisor, Prometheus
  31. Безопасность глубже: rootless, user namespaces, seccomp, capabilities
  32. Supply chain: сканирование, SBOM и подпись образов
  33. Глубокая оптимизация образов: distroless, scratch, кэш
  34. Multi-arch и сборка под ARM: buildx и эмуляция
  35. Реестры в продакшене: Harbor и облачные registry
  36. Docker без Docker: Podman, containerd, nerdctl, Buildah (вы здесь)
  37. От Compose к оркестрации: когда контейнеров становится много
  38. Docker Swarm: встроенная оркестрация
  39. Сборка образов в CI без демона: kaniko, BuildKit, Buildah
  40. Траблшутинг Docker: типичные ошибки и как чинить
  41. Производительность и эксплуатация Docker-хоста
  42. Docker Desktop, WSL2 и альтернативы на Windows и Mac
  43. Контейнеризация приложений: бэкенд, фронтенд, БД
  44. Docker и Kubernetes: containerd, миграция, kompose
  45. Лучшие практики и антипаттерны Docker
  46. Сквозной проект: production-ready стек и путь дальше
Зачем вообще учить альтернативы Docker

Представь типичную картину. Ты годами набивал руку на Docker, у тебя в голове намертво прошиты docker run, docker build, docker compose. И тут приходишь в enterprise на RHEL, а там никакого Docker-демона нет вообще, есть podman. Или поднимаешь кластер Kubernetes - и узнаешь, что Docker оттуда выпилили еще в 1.24, а под капотом крутится containerd, к которому ты лезешь через nerdctl. Или security-отдел запрещает запускать что-либо от root, и привычный демон, висящий root-процессом на сокете, просто не проходит аудит.

Хорошая новость: паниковать не надо. Docker - это давно не единственный способ работать с контейнерами, а лишь один из игроков в большой OCI-экосистеме. И главное, что нужно усвоить с самого начала: образ, который ты собрал Docker-ом, без проблем запустится в Podman, в containerd, в Kubernetes и наоборот. Потому что все они говорят на одном стандартизированном языке - OCI. Запрос "docker альтернатива" в Яндексе стабильно растет не от хайпа, а потому что в реальном проде эти инструменты уже стоят. Этот урок - про то, как устроена экосистема вокруг Docker и почему "Docker без Docker" в 2026 году звучит абсолютно нормально.

Изображение

OCI: почему образы взаимозаменяемы

Чтобы понять, как одна и та же картинка работает в пяти разных движках, надо разобрать слово, которое ты будешь слышать постоянно - OCI (Open Container Initiative). Это не программа, это набор спецификаций. Их три, и их полезно держать в голове:
  • image-spec - как устроен образ: манифест, конфиг, набор слоев (tar-архивы с файлами), хэши-дайджесты. Любой образ, который ты тянешь с Docker Hub, - это просто набор слоев плюс JSON-конфиг по этой спеке.
  • runtime-spec - как из распакованного образа сделать запущенный контейнер: какой rootfs, какие namespaces, cgroups, capabilities, точки монтирования. Эту спеку реализует runc - низкоуровневый рантайм, который непосредственно дергает системные вызовы Linux и создает процесс.
  • distribution-spec - как образы лежат в реестре и как их по HTTP качать и пушить. Поэтому Docker Hub, Yandex Container Registry, VK Cloud Container Registry, Harbor, GHCR работают по одному протоколу.
Ключевая мысль: Docker сам по себе ничего магического с образом не делает. Он использует те же runc и containerd под капотом. Когда ты делаешь docker run, демон dockerd передает работу в containerd, тот - в shim, который запускает runc, а runc уже создает namespaces и стартует процесс. Все альтернативы просто берут разные куски этой цепочки и собирают их иначе. Кто-то выкидывает демон, кто-то меняет CLI, но фундамент - OCI, runc, namespaces, cgroups - один и тот же. Именно поэтому миграция между ними - это вопрос привычек и пайплайнов, а не переписывания образов.

Podman: daemonless и rootless по умолчанию

Podman - самая известная альтернатива, и тема "podman vs docker" в обсуждениях всплывает чаще всего. Главное архитектурное отличие звучит так: Podman daemonless, то есть без постоянного демона. В Docker есть процесс dockerd, который висит всегда, владеет всеми контейнерами и слушает сокет. Падает демон - падает (в худшем случае) управление всем зоопарком. В Podman демона нет вообще. Команда podman run - это обычный процесс: он напрямую готовит namespaces, запускает через conmon (монитор контейнера) нужный рантайм (по умолчанию crun или runc) и завершается. Контейнер при этом живет дальше как потомок conmon, а не висит на демоне.

Что это дает на практике:
  • Rootless по умолчанию. Ты запускаешь контейнеры от своего обычного юзера, без root. Под капотом - user namespaces: твой UID 1000 внутри контейнера маппится в root (UID 0), а наружу остается непривилегированным. Диапазон субординатных UID/GID берется из /etc/subuid и /etc/subgid. Это огромный плюс для безопасности: даже если из контейнера сбежит злоумышленник, снаружи он останется обычным юзером без прав.
  • Нет единой точки отказа. Обновил Podman - бегущие контейнеры не падают, потому что их держит conmon, а не общий демон.
  • Прозрачность для systemd. Раз нет своего демона, контейнеры можно отдать под управление systemd как нормальные сервисы (об этом ниже).
Podman сделан как drop-in replacement: CLI почти один-в-один как у Docker. На многих системах прямо ставят alias docker=podman, и большая часть скриптов едет без изменений.

Код: Выделить всё

# Алиас, который делает большинство привычных команд рабочими
alias docker=podman

# Запуск - флаги те же
podman run -d --name web -p 8080:80 docker.io/library/nginx:alpine

# Проверяем, что rootless: смотрим маппинг UID
podman unshare cat /proc/self/uid_map
#          0       1000          1
#          1     100000      65536
Разберем вывод uid_map. Первая строка "0 1000 1" значит: внутри контейнера UID 0 (root) - это снаружи твой UID 1000, на длину 1 идентификатор. Вторая строка: внутренние UID начиная с 1 маппятся на хостовые начиная со 100000 на 65536 штук. То есть никакого настоящего root наружу не торчит - вот она, изоляция rootless на пальцах.

Важный нюанс портов: rootless-процесс не может слушать привилегированные порты ниже 1024 без донастройки sysctl net.ipv4.ip_unprivileged_port_start. Поэтому в примерах обычно видишь 8080, а не 80 наружу. Это типичная грабля при переезде с Docker, где демон-то был под root и порт 80 биндился спокойно.

Pods и Quadlet: чего нет в чистом Docker

Podman принес две фишки, ради которых его многие и берут.

Первая - pods (отсюда и имя, Podman = Pod Manager). Pod - это группа контейнеров, делящих общий network namespace: они видят друг друга по localhost, как поды в Kubernetes. Это не случайно - Podman умеет генерировать Kubernetes YAML из запущенных подов командой podman kube generate и наоборот поднимать поды из YAML через podman kube play. Локально потестил - и почти готовый манифест для кластера.

Код: Выделить всё

podman pod create --name app -p 8080:80
podman run -d --pod app --name api myapi:latest
podman run -d --pod app --name cache docker.io/library/redis:7
# api и cache теперь общаются по localhost внутри пода
Вторая, и в 2026 году куда более важная, - Quadlet. Это способ описать контейнер декларативно в простом ini-файле, а systemd сам сгенерирует из него полноценный сервис. По сути это родная замена restart-политикам Docker и самописным unit-файлам. Кладешь файл в /etc/containers/systemd/ (или для rootless в ~/.config/containers/systemd/), и Quadlet при загрузке превращает его в .service.

Код: Выделить всё

# /etc/containers/systemd/web.container
[Container]
Image=docker.io/library/nginx:alpine
PublishPort=8080:80

[Install]
WantedBy=multi-user.target default.target

Код: Выделить всё

systemctl daemon-reload
systemctl start web.service   # имя сервиса = имя файла без расширения
Почему это любят в RHEL и enterprise: Red Hat выпилила Docker из RHEL еще в версии 8 и сделала ставку на Podman, Buildah и Skopeo. В мире, где все уже завязано на systemd, Quadlet ложится идеально - контейнер становится обычным юнитом, с journald-логами, зависимостями, авто-рестартом и health-чеками средствами самого systemd. Это и есть ответ на вопрос "почему его выбирают в enterprise": не потому что моднее, а потому что бесшовно встраивается в существующую инфраструктуру управления сервисами и проходит требования безопасности (rootless, без демона под root).

containerd и nerdctl: то, на чем стоит Kubernetes

Теперь самый важный для DevOss кусок. containerd - это тот самый низкоуровневый менеджер контейнеров, который Docker использует у себя внутри. Это демон, но не такой увесистый, как dockerd: он отвечает за жизненный цикл контейнеров, образы, снапшоты, передачу образов из реестра. Высокоуровневых удобств (build из Dockerfile, compose, удобный CLI) у него штатно нет - это намеренно, containerd создан как кирпич для платформ, а не как инструмент для человека за терминалом.

Именно поэтому Kubernetes в свое время ушел от dockershim. dockershim - это была прослойка-переходник, через которую kubelet общался с Docker. Но Docker под капотом все равно вызывал containerd - получалась лишняя ступенька (kubelet -> dockershim -> dockerd -> containerd). Когда у k8s появился стандартный интерфейс CRI (Container Runtime Interface), оказалось, что containerd реализует его напрямую, а Docker - нет, для него и держали shim. Поддерживать костыль ради совместимости стало невыгодно, и в Kubernetes 1.24 dockershim удалили. Никакой драмы для образов это не вызвало: твои Docker-образы как были OCI, так и остались, кластер их прекрасно тянет через containerd. Поменялся рантайм узлов, а не формат.

Вот тут и появляется nerdctl - contaiNERD CTL, Docker-совместимый CLI для containerd. Он закрывает ровно ту дыру, про которую я сказал: дает человеку привычный docker-like интерфейс поверх голого containerd.

Код: Выделить всё

# Те же команды, что в Docker, только бинарь другой
nerdctl run -d --name web -p 8080:80 nginx:alpine
nerdctl ps
nerdctl build -t myapp:1.0 .
nerdctl compose up -d        # да, compose тоже поддерживается
nerdctl умеет почти все то же, что docker CLI: build (через BuildKit), compose, rootless-режим, плюс продвинутые штуки вроде lazy-pulling образов через eStargz (контейнер стартует, не дожидаясь загрузки всех слоев) и шифрование образов через OCIcrypt. По умолчанию свежий nerdctl ставится в rootless-режиме. Когда тебе надо на узле Kubernetes посмотреть, что реально происходит с образами и контейнерами на уровне рантайма, nerdctl - твой инструмент. Альтернатива - crictl, но это чисто диагностический CRI-клиент, неудобный для повседневной работы. Помни про namespaces containerd: Kubernetes держит свои контейнеры в неймспейсе k8s.io, поэтому смотреть их надо с флагом, иначе nerdctl ps покажет пусто.

Код: Выделить всё

nerdctl --namespace k8s.io ps
Buildah: сборка образов без демона и без Dockerfile

Последний кит экосистемы Red Hat - Buildah, инструмент именно для сборки OCI-образов. Podman внутри для build вызывает как раз Buildah. Зачем отдельный инструмент, если есть docker build? Две причины.

Первая - сборка без привилегированного демона. Классический docker build идет через root-демон, что в CI и в кластере - дыра в безопасности. Buildah собирает образы в rootless-режиме, не требуя демона вообще. Это давняя боль "как собрать образ внутри Kubernetes-пода, не дав ему root и доступ к docker.sock" - Buildah (и BuildKit) ее закрывают.

Вторая, более интересная, - Buildah умеет собирать образы скриптом, без Dockerfile. Ты получаешь полный контроль: монтируешь рабочий контейнер как обычную файловую систему и правишь его шелл-командами. Это спасает, когда логика сборки сложнее, чем линейный список RUN, и ее удобнее выразить циклом на bash.

Код: Выделить всё

#!/bin/bash
ctr=$(buildah from alpine:3.20)            # создаем рабочий контейнер из базового образа
buildah run $ctr apk add --no-cache curl   # выполняем команды как RUN
buildah copy $ctr ./app /app               # копируем файлы как COPY
buildah config --entrypoint '["/app"]' $ctr
buildah commit $ctr myapp:1.0              # фиксируем результат как образ
При этом Buildah спокойно умеет и обычный путь: buildah bud (build-using-dockerfile) собирает из существующего Dockerfile, так что переезжать не больно. А получившийся образ можно тут же запушить через Skopeo - третий инструмент этой связки, который копирует образы между реестрами и хранилищами, не запуская их (удобно для зеркалирования в Yandex/VK Container Registry).

Когда мигрировать, а когда не трогать

Без фанатизма. Docker - отличный инструмент, и для локальной разработки на ноуте он часто остается самым удобным, особенно на Mac/Windows через Docker Desktop с WSL2. Менять шило на мыло без причины не надо. Реальные триггеры миграции:
  • Требования безопасности. Нужен rootless, запрет демона под root, прохождение аудита - смотри в сторону Podman. Это самый частый мотив в enterprise.
  • RHEL и systemd-инфраструктура. Если все на Red Hat и systemd - Podman с Quadlet родной, Docker там лишний.
  • Kubernetes-узлы. Там Docker уже не нужен в принципе: рантайм - containerd, диагностика - nerdctl/crictl. Образы продолжаешь собирать чем угодно.
  • CI-сборка без docker.sock. Buildah или BuildKit/buildx в rootless-режиме безопаснее, чем монтировать сокет демона в раннер.
Антипаттерны, на которых спотыкаются:
  • Слепо ставить alias docker=podman и ждать 100% совместимости. 90% команд совпадают, но края разные: сеть (Podman использует Netavark и Aardvark-DNS вместо bridge-демона Docker), порты ниже 1024 в rootless, отсутствие живого демона для интеграций, которые лезут в docker.sock.
  • Забыть про namespace k8s.io в nerdctl и решить, что контейнеров на узле нет.
  • Думать, что "альтернатива Docker" означает несовместимые образы. Нет. OCI-образ один на всех - это и есть главный вывод урока.
Мини-лаба: собери и запусти без Docker

Если есть Linux (или WSL2), повтори руками:
  • Поставь podman и проверь rootless: podman run --rm docker.io/library/alpine id, затем podman unshare cat /proc/self/uid_map - убедись, что внутренний root маппится на твой обычный UID.
  • Подними nginx через Podman на порту 8080 и проверь curl localhost:8080. Обрати внимание, что ты не использовал root.
  • Опиши этот же nginx через Quadlet-файл в ~/.config/containers/systemd/, выполни systemctl --user daemon-reload и подними как сервис. Посмотри логи через journalctl --user.
  • Собери простой образ через Buildah-скрипт (from/run/copy/commit) без всякого Dockerfile и запусти его подом.
  • Если есть containerd - поставь nerdctl и собери тот же образ через nerdctl build, сравни вывод nerdctl images и podman images: дайджесты слоев совпадут, потому что формат один.
Контрольные вопросы
  • Почему Docker-образ без переделки запускается в Podman, containerd и Kubernetes? Какие три спецификации OCI это обеспечивают?
  • Что значит "Podman daemonless и rootless по умолчанию" и какой механизм Linux дает rootless-изоляцию?
  • Почему Kubernetes отказался от dockershim в 1.24 и при чем тут CRI и containerd?
  • В каких двух случаях Buildah выигрывает у docker build и зачем рядом нужен Skopeo?
Итог

"Docker без Docker" - это не экзотика, а нормальная реальность 2026 года. Под капотом у всех один фундамент: OCI-образы, runc/crun, namespaces, cgroups. Podman дает daemonless и rootless с pods и Quadlet и царит в RHEL/enterprise. containerd с nerdctl - то, на чем стоит Kubernetes после ухода от dockershim. Buildah собирает образы без демона и даже без Dockerfile. Главное помни: образ один на всех, а инструмент выбирай под задачу и требования безопасности, а не по привычке.
👍2 ❤️8 🔥1 😄 🤔1
Аватара пользователя
overclockedgoblin
Сообщения: 1
Зарегистрирован: 01 июн 2026, 22:02

Re: Docker без Docker: Podman, containerd, nerdctl, Buildah

Сообщение overclockedgoblin »

Топ урок. Долго не мог понять почему k8s 'выкинул docker' и не сломал образы - вот этот момент про CRI и shim наконец уложился в голове. Спасибо!
👍1 ❤️ 🔥 😄 🤔
Аватара пользователя
nginxmain
Сообщения: 1
Зарегистрирован: 14 май 2026, 21:13

Re: Docker без Docker: Podman, containerd, nerdctl, Buildah

Сообщение nginxmain »

А Podman Desktop на маке нормально живет вместо Docker Desktop или там тоже своя виртуалка под капотом и тормоза? Кто гонял в проде - rootless по сети сильно медленнее bridge?
👍 ❤️ 🔥 😄 🤔
Ответить
← Предыдущая глава
Реестры в продакшене: Harbor и облачные registry
Следующая глава →
От Compose к оркестрации: когда контейнеров становится много

Все главы курса «Docker: контейнеризация от основ до продакшена»

Поделиться темой: ✈ Telegram VK
Похожие запросы: как установить docker на ubuntu и linuxdocker команды шпаргалка для новичкаdocker run как запустить контейнер с флагамиdocker images как посмотреть и удалить образыdocker desktop и wsl2 на windows как настроитьdocker контейнер падает сразу после запуска как найти причину

Вернуться в «Docker с нуля»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость