Перейти к основному содержимому
  1. Posts/
  2. Podman/

Podman: современная альтернатива Docker

··1964 слов·10 минут· loading · loading · ·
Stilicho2011
Автор
Stilicho2011
Пишу о homelab, self-hosting, автоматизации и open-source решениях
Оглавление
Podman - This article is part of a series.
Part : This Article

Введение
#

Если вам понравилась настоящая статья, то можете поддержать автора став спонсором на бусти (ссылка в разделе контакты).

Когда речь заходит про контейнеры, девять человек из десяти по умолчанию имеют в виду Docker. Он действительно долгие годы был синонимом контейнеризации: docker run, docker-compose up и Dockerfile - это тот минимальный набор, который знает практически любой, кто хоть раз разворачивал сервис не на голом железе. Но у Docker есть архитектурная особенность, из-за которой у части сообщества, включая меня, к нему постепенно накопились вопросы - это постоянно работающий демон с root-правами.

Podman - это попытка решить именно эту проблему, причём не косметически, а на уровне архитектуры. Это контейнерный движок без демона, с полноценным rootless-режимом из коробки и нативной интеграцией с systemd. В моем homelab он давно заменил Docker, и в этой статье я хочу разобрать, откуда Podman взялся, как он устроен внутри, чем принципиально отличается от Docker, и что такое поды, Quadlet и Podlet - термины, которые обычно и вызывают больше всего путаницы.

Откуда взялся Podman
#

История у Podman не самая очевидная, и знать её полезно, чтобы понимать, почему проект устроен именно так.

Всё началось в 2017 году внутри проекта CRI-O (container runtime для Kubernetes) с небольшой утилиты под рабочим названием kpod - её делали инженеры Red Hat, которым нужен был способ отлаживать и инспектировать контейнеры, созданные CRI-O, без необходимости поднимать полноценный Docker. Имя kpod никому в команде не нравилось, и через несколько месяцев разработки инструмент выделили в отдельный проект - библиотеку libpod, которая отвечала за управление подами и контейнерами без демона. А ещё через несколько месяцев, в начале 2018 года, вышел первый публичный релиз уже под новым именем - Podman, что расшифровывается как “POD MANager”.

Важный нюанс: Podman - это не форк Docker. Это независимая реализация, написанная с нуля, которая при этом использует те же низкоуровневые стандарты и во многом те же компоненты экосистемы, что и Docker:

  • runc или crun - низкоуровневый OCI-runtime, который непосредственно запускает контейнер;
  • conmon - лёгкий супервизор, следящий за процессом контейнера;
  • containers/storage - библиотека для хранения образов и слоёв;
  • containers/image - работа с реестрами и форматами образов.

Сегодня Podman разрабатывается под эгидой Red Hat, входит в состав проекта containers на GitHub и является контейнерным движком по умолчанию в RHEL, Fedora, CentOS Stream и ряде других дистрибутивов, где Docker в принципе не поставляется из коробки уже несколько лет.

Для каких задач нужен Podman
#

По сути Podman закрывает те же задачи, что и Docker - сборка образов, запуск контейнеров, работа с реестрами - но с прицелом на другие сценарии использования:

  • локальная разработка и тестирование контейнеризованных приложений;
  • запуск контейнеров и подов на серверах и в homelab, особенно там, где хочется обойтись без демона;
  • эксплуатация контейнеров без root-доступа, что критично для multi-tenant окружений;
  • генерация Kubernetes-манифестов прямо из работающих контейнеров - удобно, если Kubernetes только планируется;
  • замена Docker в CI/CD, где Podman может запускаться внутри самого CI-раннера без привилегированного демона.

На практике чаще всего Podman выбирают для домашних лабораторий и небольших серверов с повышенными требованиями к безопасности, для edge-устройств с ограниченными ресурсами, и там, где Kubernetes уже используется или явно стоит в планах - генерация манифестов сильно упрощает миграцию.

Архитектура: почему нет демона
#

Ключевая архитектурная особенность Podman - daemonless-модель. У Docker есть dockerd, постоянно работающий в фоне процесс с root-правами, который принимает команды от клиента и управляет жизненным циклом всех контейнеров. У Podman такого процесса нет вообще: команда podman run напрямую, без посредников, вызывает conmon и runc/crun, которые и запускают контейнер как обычный дочерний процесс системы.

Из этого вытекает несколько практических следствий:

  • контейнер Podman в ps виден как самостоятельный процесс, а не как что-то, спрятанное внутри демона - это заметно упрощает отладку;
  • если что-то упало в одном контейнере, это не затрагивает остальные и уж тем более не требует перезапуска общего демона;
  • пропадает единая точка отказа: не станет демона - не станет и всех контейнеров разом, как иногда бывает с Docker после сбойного обновления dockerd.
  • systemd воспринимает такие процессы естественно, без обходных путей вроде docker run внутри ExecStart - об этом подробнее поговорим в разделе про Quadlet.

Rootless-контейнеры и сеть
#

Rootless-режим в Podman - не костыль поверх существующей архитектуры, а то, ради чего проект во многом и затевался. Контейнер можно запустить от обычного, непривилегированного пользователя, и при этом внутри контейнера у процесса всё равно будет “свой” root - просто это не настоящий root хостовой системы.

Технически это реализовано через:

  • user namespaces - подмену UID/GID внутри контейнера на непривилегированные диапазоны на хосте;
  • subuid/subgid - диапазоны идентификаторов, которые администратор выделяет пользователю для этой подмены (/etc/subuid, /etc/subgid);
  • сетевой стек в user space, который не требует привилегий на хосте.

Тут стоит сделать отдельную ремарку про сеть, потому что она за последние пару лет заметно изменилась. Раньше rootless-сеть в Podman почти всегда означала slirp4netns - рабочее, но довольно медленное решение. Начиная с Podman 5.x в качестве современной замены продвигается pasta - она заметно быстрее, полноценно поддерживает IPv6 и, что особенно приятно, “отражает” сетевую конфигурацию хоста прямо в контейнер вместо классического NAT. В актуальных версиях Podman pasta уже используется как бэкенд для rootless-сети по умолчанию, а поддержка slirp4netns в новых релизах постепенно сворачивается. Если у вас старый конфиг с явным указанием slirp4netns - самое время свериться с man podman-network для своей версии и по возможности перейти на pasta.

Итог такого подхода: даже если контейнер скомпрометируют, атакующий окажется не в root-окружении хоста, а в изолированном namespace обычного пользователя - потенциальный ущерб принципиально меньше.

Чем Podman отличается от Docker
#

Сравнение по ключевым параметрам
#

КритерийDockerPodman
АрхитектураКлиент-демон (dockerd)Без демона
Права демонаrootдемона нет
RootlessЕсть, но требует отдельной настройки и имеет ограниченияПолноценный режим “из коробки”
Интеграция с systemdЧерез обходные путиНативная (Quadlet)
Kubernetes-манифестыНужны сторонние инструментыВстроенная генерация YAML
ПодыНет как первичной сущностиЕсть, как в Kubernetes
CLIDocker CLIСовместим с Docker CLI

Совместимость с Docker
#

Пожалуй, лучшая новость для тех, кто переходит с Docker - переучиваться почти не придётся. CLI Podman намеренно сделан максимально похожим:

alias docker=podman

После такого алиаса подавляющее большинство привычных команд просто продолжает работать:

podman run -d -p 8080:80 nginx
podman build -t myapp .
podman pull docker.io/library/redis
podman push myapp registry.example.com/myapp

Формат Dockerfile тоже поддерживается без каких-либо изменений - Podman умеет собирать образы из обычных Dockerfile, дополнительно предлагая свой более гибкий формат Containerfile (по сути то же самое, просто другое имя файла).

Поды (Pods) в Podman
#

Что такое под
#

Под (pod) - это группа из одного или нескольких контейнеров, которые:

  • разделяют один сетевой namespace, то есть общий IP-адрес и общее пространство портов;
  • при желании могут совместно использовать IPC-namespace;
  • логически представляют собой одно приложение, которое удобно запускать и останавливать как единое целое.

Концепция полностью заимствована из Kubernetes, и это не случайность, а осознанное архитектурное решение - Podman изначально проектировался так, чтобы модель локальной разработки была максимально близка к тому, как приложение потом будет вести себя в кластере. Типичный под - это, например, контейнер с приложением, контейнер с reverse-proxy перед ним и sidecar-контейнер для логирования или метрик, которые вместе образуют один логический сервис.

Пример: создаём под руками
#

podman pod create --name web-pod -p 8080:80
podman run -d --pod web-pod nginx
podman run -d --pod web-pod busybox sleep infinity

Все контейнеры внутри web-pod получают один общий IP-адрес и видят друг друга через localhost, как процессы на одной машине - можно смело обращаться друг к другу по 127.0.0.1:<порт> без настройки отдельной docker-сети, как пришлось бы делать в Docker.

Из практических плюсов такого подхода: сетевое взаимодействие внутри пода становится тривиальным, конфигурация ближе к модели Kubernetes, а сами контейнеры логически группируются, что удобно и для мониторинга, и для последующей миграции.

Генерация Kubernetes-манифестов
#

Отдельная сильная сторона Podman - умение прямо из работающего пода сгенерировать готовый Kubernetes YAML:

podman generate kube web-pod > pod.yaml

Это позволяет собрать и обкатать архитектуру приложения локально на одной машине, а потом перенести конфигурацию в кластер без переписывания с нуля - Podman в этом смысле неплохо работает как “локальный Kubernetes” для разработки и тестирования.

Podman и systemd
#

Podman нативно умеет интегрироваться с systemd - и делать это можно двумя способами.

Первый, более старый - генерация unit-файла из уже созданного контейнера или пода:

podman generate systemd --name nginx --files --new

Команда создаёт .service-файл, который можно положить в systemd-юниты и управлять контейнером стандартными systemctl start/stop/enable. Этот способ рабочий, но требует, чтобы контейнер уже существовал, и плохо подходит для декларативного описания инфраструктуры “с нуля”.

Второй, современный и рекомендуемый способ - Quadlet.

Что такое Quadlet
#

Quadlet - это встроенный в Podman механизм, который позволяет описывать контейнеры, поды, сети, volume’ы и образы декларативно, обычными systemd unit-файлами специального формата. systemd на старте сам транслирует такие файлы в полноценные .service-юниты и запускает их через Podman - вручную ничего генерировать не нужно.

Всего Quadlet поддерживает несколько типов файлов:

РасширениеЧто описывает
.containerотдельный контейнер
.podпод (группу контейнеров)
.volumeименованный volume
.networkсеть
.imageобраз, который нужно заранее подтянуть
.buildсборку образа из Containerfile
.kubeразвёртывание из Kubernetes YAML (podman kube play)
.artifactOCI-артефакт

Файлы размещаются в одном из стандартных путей, в зависимости от того, нужен ли системный (root) или пользовательский (rootless) сервис:

/etc/containers/systemd/            # системные квадлеты, root
~/.config/containers/systemd/       # пользовательские, rootless

Пример .container-файла
#

[Container]
Image=docker.io/library/nginx:latest
PublishPort=8080:80
Volume=nginx-data:/usr/share/nginx/html:Z

[Service]
Restart=always

[Install]
WantedBy=multi-user.target

После создания файла достаточно перечитать конфигурацию systemd и запустить сервис:

systemctl daemon-reload
systemctl start nginx.container

Дальше это уже полноценный systemd-сервис: автозапуск при загрузке системы через [Install], единый журнал через journalctl -u nginx.container, управление зависимостями через стандартные After=/Requires=. Для homelab, где нет и не планируется Kubernetes, но есть systemd - это, на мой взгляд, оптимальный способ держать инфраструктуру контейнеров.

Podlet: помощник в написании Quadlet-файлов
#

Писать .container-файлы руками не всегда удобно, особенно когда под рукой уже есть рабочая команда docker run или docker-compose.yml, которые не хочется переписывать с нуля. Для этого есть отдельный инструмент - Podlet (не путать с Quadlet, это разные вещи, хотя названия и похожи).

Podlet - самостоятельная утилита на Rust, которая не входит в состав самого Podman, но плотно с ним используется. Она умеет генерировать Quadlet-файлы тремя способами: из команды podman run (или docker run - синтаксис почти идентичен), из существующего compose-файла, и даже из уже запущенного контейнера, пода, сети или volume’а через podlet generate.

podlet podman run -d -p 8080:80 nginx

Команда выше выведет в консоль готовый .container-файл со всеми нужными секциями - остаётся сохранить его в правильную директорию. Для compose-файлов Podlet умеет либо разбивать сервисы на отдельные .container-файлы, либо собирать их в один .pod вместе с сопутствующими контейнерами - в зависимости от того, что ближе к исходной архитектуре приложения.

На практике Podlet особенно полезен именно на этапе миграции с Docker Compose: не нужно вручную разбираться в синтаксисе Quadlet-секций - достаточно скормить существующий docker-compose.yml, а дальше уже донастроить сгенерированный файл под себя.

Когда стоит выбирать Podman
#

Из моего собственного опыта, Podman особенно оправдан, если:

  • для вас важны безопасность и rootless-режим по умолчанию, а не как опция, которую нужно отдельно допиливать;
  • на сервере и так используется systemd, и хочется управлять контейнерами теми же привычными командами systemctl, а не отдельным демоном;
  • Kubernetes уже используется или явно в планах - переносить конфигурацию через podman generate kube удобнее, чем писать манифесты с нуля;
  • нужна daemonless-архитектура без единой точки отказа;
  • вы строите homelab или self-hosted инфраструктуру и не хотите, чтобы всё держалось на одном привилегированном процессе.

Заключение
#

Podman - это не “Docker, но бесплатно” и не клон ради клона. Это отдельная, довольно зрелая на сегодняшний день реализация контейнерного движка, которая решает конкретные архитектурные проблемы Docker: убирает демон с root-правами, делает rootless-режим полноценным, а не опциональным, и нативно встраивается в systemd через Quadlet.

Для homelab и небольших серверов переход с Docker на Podman у меня лично не потребовал почти никаких компромиссов - CLI совместим, Dockerfile работает как есть, а взамен я получил меньше точек отказа и намного более прозрачную интеграцию с systemd. Если вы давно присматриваетесь к Podman, но не решались - лучший способ узнать, подходит ли он вам, это просто попробовать на одном не самом критичном сервисе.


Полезные ссылки:

Podman - This article is part of a series.
Part : This Article

Related

Podman: обратная сторона медали - о каких недостатках стоит знать заранее

·1951 слово·10 минут· loading · loading
Разбираем реальные ограничения Podman: сеть и порты в rootless-режиме, неполная совместимость с Docker Compose, виртуальная машина на macOS/Windows вместо демона, отсутствие оркестрации на несколько хостов, менее зрелая экосистема и более высокий порог входа для новичков.

Quadlet и Podlet в Podman: как перестать писать длинные podman run и завести контейнеры под systemd

··1260 слов·6 минут· loading · loading
Quadlet - декларативный формат systemd-юнитов для Podman, а Podlet - утилита, которая генерирует эти юниты из podman run и docker-compose.yml. Разбираем оба инструмента на практических примерах и сравниваем с Docker Compose.

Docker vs Podman vs Kubernetes: подробное сравнение контейнерных технологий

··1363 слов·7 минут· loading · loading
Сравниваем Docker, Podman и Kubernetes: архитектура, безопасность, накладные расходы и реальные сценарии применения - от homelab до production-кластеров.