Миграция с Docker на rootless Podman: шаг — АйТи Фреш
Москва, Щёлковское шоссе, д. 92, корп. 7 · Пн–Пт 9:00–19:00 · +7 903 729-62-41
· 18 мин чтения

Миграция с Docker на rootless Podman: когда оправдано и как сделать

Миграция с Docker на rootless Podman: когда оправдано и как сделать

На восьми серверах Dell Xeon Platinum 8280 в московском дата-центре МТС одновременно работают сотни клиентских контейнеров. Последние два года мы переводим часть продакшн-нагрузки с Docker на rootless Podman — не повсеместно, а там, где это даёт реальные преимущества в безопасности и бесшовной интеграции с systemd. Дальше — опыт этой миграции: что прошло гладко, а где споткнулись.

Зачем вообще менять Docker

У Docker есть одна архитектурная проблема: демон работает от root. Любой пользователь, состоящий в группе docker, фактически получает root-доступ к хосту — может через -v /:/mnt смонтировать файловую систему и писать куда угодно. Для мультитенантных серверов это бесполезный уровень изоляции.

Podman rootless работает иначе:

Когда НЕ надо мигрировать

Вот что я сразу хочу сказать всем нашим клиентам: нет никакого смысла затевать миграцию просто ради самой миграции. Зачем что-то менять, если и так всё отлично работает? Смело оставайтесь на Docker, если:

Так когда же мигрировать? Если ваш сервер общий для разных разработчиков и вам нужна надёжная изоляция. Или когда без компромиссов есть жёсткие требования по безопасности, например, по ФСТЭК/ISO. И, конечно, если вы уже используете RHEL/Rocky 9 — там Podman буквально "родной", встроен в систему.

Установка Podman

# Rocky Linux 9 / RHEL 9
sudo dnf install -y podman podman-compose

# Ubuntu 24.04
sudo apt install -y podman podman-compose

# Проверка
podman version
podman info | grep -i rootless

Для rootless нужны /etc/subuid и /etc/subgid. В свежих дистрибутивах заводятся автоматически при создании пользователя. Проверить:

grep $USER /etc/subuid /etc/subgid
# Должно быть что-то вроде
# /etc/subuid:operator:100000:65536

Docker → Podman: словарь команд

DockerPodmanКомментарий
docker runpodman runСовместимо на 99%
docker pspodman psОдинаково
docker buildpodman buildИспользуется buildah внутри
docker-compose uppodman-compose upИли quadlet-файлы
docker networkpodman networkПод капотом netavark/CNI
docker volumepodman volumeХранилище в ~/.local/share/containers

Я всегда делаю в ~/.bashrc:

alias docker=podman
alias docker-compose="podman-compose"
Сравнение команд Docker и Podman для миграции контейнеров
Основные команды Docker и их аналоги в Podman для упрощения миграции.

Миграция compose-проекта

Берём существующий docker-compose.yml. Большинство работает без правок. Что часто ломается:

cd /opt/app
podman-compose up -d
podman-compose ps

Quadlet: systemd-юниты для контейнеров

Это моя любимая фича Podman 4.4+. Вместо compose-файла описываете контейнер в systemd-юните *.container, и systemd сам поднимает его при старте.

# ~/.config/containers/systemd/nginx.container
[Unit]
Description=Nginx reverse proxy
After=network-online.target

[Container]
Image=docker.io/library/nginx:1.27-alpine
PublishPort=8080:80
Volume=/home/operator/nginx/conf:/etc/nginx/conf.d:ro,Z
AutoUpdate=registry

[Service]
Restart=always

[Install]
WantedBy=default.target
systemctl --user daemon-reload
systemctl --user start nginx
journalctl --user -u nginx -f

Плюсы: логи в journalctl, автозапуск через loginctl enable-linger, обновление через podman auto-update по расписанию.

Quadlet для pod: несколько контейнеров в одной сети

Когда сервис состоит из нескольких контейнеров, которым нужна общая сеть и общий порт, удобнее объединить их в pod — как в Kubernetes. Quadlet поддерживает это через файлы .pod и привязку контейнеров к pod.

# /etc/containers/systemd/app.pod
[Pod]
PodName=myapp
PublishPort=8080:80
PublishPort=5432:5432

# /etc/containers/systemd/app-nginx.container
[Container]
Pod=myapp.pod
Image=nginx:alpine
Volume=/opt/app/nginx.conf:/etc/nginx/nginx.conf:ro,Z

# /etc/containers/systemd/app-db.container
[Container]
Pod=myapp.pod
Image=postgres:17-alpine
Environment=POSTGRES_PASSWORD=secret
Volume=app-pgdata.volume:/var/lib/postgresql/data

После создания файлов выполните systemctl daemon-reload и запустите pod: systemctl start myapp. Все контейнеры внутри pod стартуют и останавливаются как единое целое, а логи каждого контейнера по-прежнему доступны через journalctl -u app-nginx -f.

Реальный кейс: мониторинговый стек для производственного холдинга

В октябре 2025 года клиент — металлообработка на 45 рабочих местах — пришёл с задачей: «хотим Grafana + Prometheus + Loki, но служба безопасности запрещает запускать сервисы от root». Идеальный кейс для Podman rootless. Мы создали отдельного пользователя monitor, дали ему subuid 100000:65536, развернули 8 контейнеров через quadlet.

Сроки: 2 рабочих дня на развёртывание, 1 день на интеграцию с экспортёрами на 6 серверах клиента. Стоимость — 54 000 руб. Через полгода заказчик отметил: zero инцидентов безопасности с контейнерами, обновления по расписанию через podman auto-update, единый журнал в journalctl.

Автообновление образов: podman auto-update

Podman умеет автоматически обновлять контейнеры при появлении нового образа в registry. В Quadlet для этого достаточно указать AutoUpdate=registry в секции [Container], либо при ручном запуске добавить метку --label io.containers.autoupdate=registry.

# Проверка обновлений без применения (dry-run)
podman auto-update --dry-run

# Применить обновления
podman auto-update

# Включить systemd-таймер для ежедневной проверки
systemctl enable --now podman-auto-update.timer
# По умолчанию — ежедневно в 00:00

Это удобно для стейтлес-сервисов: nginx, приложения, воркеры. Для баз данных автообновление лучше отключить — обновление PostgreSQL или MySQL требует ручной миграции данных.

Сетевые грабли

В rootless сеть отличается от Docker bridge. Используется slirp4netns или pasta для user-mode networking. Следствия:

Но если мы говорим о высокопроизводительных сервисах — например, о базах данных или видеостримах, тут всё иначе. В таких случаях лучше либо совсем не трогать Docker, либо уж сразу идите на rootful Podman. Полумеры здесь просто не работают.

Проверка user mapping и сканирование образов

Чтобы убедиться, что rootless-изоляция действительно работает, проверьте маппинг UID внутри user namespace:

podman unshare cat /proc/self/uid_map
#          0       1000          1   ← root в контейнере = uid 1000 на хосте
#          1     100000      65536   ← остальные uid-ы замаплены в безопасный диапазон

Для контроля безопасности образов интегрируйте сканер уязвимостей Trivy:

# Получить digest образа
podman image inspect --format '{{.Digest}}' myapp:latest

# Сканирование на CVE
trivy image myapp:latest

В rootless-режиме SELinux и AppArmor работают из коробки, а seccomp-профили по умолчанию блокируют опасные системные вызовы — дополнительная настройка не требуется.

Миграционный чек-лист

  1. Что ещё важно? Инвентаризация контейнеров. Нужно чётко понимать, что запущено, какие ресурсы потребляет и какие порты открыты.
  2. Наш совет: прежде чем делать что-то глобально, обязательно протестируйте миграцию на одном второстепенном сервисе. Поможет выявить большинство проблем заранее.
  3. Сначала самое главное: ставим Podman. Да, прямо рядом с вашим Docker, пусть пока поживут вместе. Это позволит нам всё протестировать безболезненно. А чтобы всё работало без лишних прав, обязательно создаём нового пользователя для rootless-режима. Безопасность — это важно, не так ли?
  4. Теперь займёмся файлами `compose`. Просто так перенести их не получится. Нужно адаптировать настройки — особенно внимательно посмотрите на порты, опции `privileged` и `bind-mounts`. В Podman они работают немного иначе, поэтому придётся кое-что подправить, чтобы всё встало на свои места. Это как переезд в новую квартиру: мебель та же, но расставлять надо по-другому.
  5. Переезд образов (podman pull) и данных (томов).
  6. Итак, всё готово к запуску! Используем `podman-compose` или современный `quadlet` — смотря что вам ближе. Но главное, не торопитесь. Мы рекомендуем запускать Podman параллельно с Docker на 3–5 дней. За это время вы сможете убедиться, что все сервисы работают стабильно, а ошибок нет. Ведь спешка здесь ни к чему.
  7. Отлично, тестовый период пройден? Всё работает как часы? Тогда можно с чистой совестью отключать Docker-контейнеры. И, пожалуйста, не забудьте про архивацию данных! Это как собрать вещи после переезда — вдруг что-то понадобится. Лучше перестраховаться, чем потом кусать локти.
  8. Удаление Docker (если больше не нужен).
  9. Всё, миграция завершена. Но работа на этом не заканчивается! Чтобы система жила долго и счастливо, настройте автообновление, регулярные бэкапы и, конечно, мониторинг. Мы же не хотим сюрпризов, правда? Пусть всё будет под контролем. Надёжность и стабильность — вот к чему мы стремимся.

FAQ — переход с Docker на Podman

Чем rootless Podman безопаснее Docker?
Docker-демон запускается от root и эффективно даёт root-доступ всем, кто в группе docker. Podman rootless работает под обычным пользователем с user namespaces — уязвимость в контейнере даёт права пользователя, не root. Нет демона — нет единой точки отказа.
Podman совместим с Docker CLI?
Да, alias docker=podman работает для 90% команд: pull, run, ps, exec, logs, build. Отличия — в сетевых командах (podman использует netavark/slirp4netns) и в рабочих каталогах. Скрипты обычно переезжают с минимальными правками.
Нужен ли podman-compose или лучше сразу quadlet?
Для быстрой миграции — podman-compose, он читает docker-compose.yml. Для продакшна рекомендую quadlet — systemd-юниты с описанием контейнеров, чистая интеграция с journalctl, автозапуск при перезагрузке.
Можно ли пробросить порты 80 и 443 в rootless?
По умолчанию нет — rootless пользователь не имеет права на привилегированные порты. Решения: net.ipv4.ip_unprivileged_port_start=80 в sysctl, setcap, либо reverse proxy (nginx/haproxy) на хосте, а контейнеры слушают 8080/8443.
Podman поддерживает GPU и CUDA?
Да, через CDI (Container Device Interface). NVIDIA предоставляет nvidia-container-toolkit с поддержкой Podman. Настраивается чуть сложнее Docker, но работает стабильно на RHEL 9, Rocky 9, Ubuntu 24.04.

Столкнулись с похожей задачей? Обращайтесь — решим

Если у вас происходит что-то из описанного в этой статье — или любая другая проблема с ИТ-инфраструктурой, — обращайтесь в любое время. Мои специалисты и я лично разберём ситуацию, найдём настоящую причину и доведём до решения.

Возьмёмся и за разовую задачу, и за постоянное обслуживание. Первичная консультация — бесплатно и без обязательств.

📞 +7 903 729-62-41 ✈ Telegram @ITfresh_Boss

С уважением, Семёнов Евгений Сергеевич, директор «АйТи Фреш» — IT-аутсорсинг для компаний до 50 рабочих мест, 15+ лет практики

📄
Скачайте подробный разбор в PDF Кейсы, статистика, типовые ошибки и чек-лист самопроверки — 12 страниц
Скачать PDF

Подпишитесь на рассылку ITfresh

Каждую неделю мы готовим для вас свежие, практические гайды. Специально для IT-руководителей и сисадминов. Внутри: безопасность, тонкости 1С, миграции, надёжные резервные копии и, конечно, лайфхаки, собранные из наших реальных проектов.

Письмо придёт в течение минутыНе нашли его во «Входящих» — загляните в папку «Спам» или «Промоакции» и нажмите «Не спам». Так все следующие выпуски будут приходить прямо в основную почту.
Реквизиты оператора персональных данных

ООО «АЙТИ-ФРЕШ», ИНН 7719418495, КПП 771901001. Юридический адрес: 105523, г. Москва, Щёлковское шоссе, д. 92, корп. 7. Контакт: info@itfresh.ru, +7 903 729-62-41. Оператор обрабатывает e-mail подписчика в целях рассылки информационных и рекламных материалов до момента отзыва согласия.