Введение#
В статье про Podman я подробно разбирал, почему Podman в моем homelab заменил Docker: daemonless-архитектура, полноценный rootless-режим из коробки, нативная интеграция с systemd через Quadlet. Все это так, и я по-прежнему считаю, что у Podman много преимуществ для того, чтобы считать переход оправданным. Но было бы нечестно рассказывать только о преимуществах и умалчивать о том, с чем реально приходится мириться. Да и в комментариях у меня в тг-канале мне прямо указали, что я не рассказываю о недостатках Podman.
У Podman есть вполне конкретные недостатки - часть из них следствие тех же архитектурных решений, которые в других сценариях становятся плюсами. В этой статье я постараюсь описать недостатки, которые на практике доставляют более чем серьезные неудобства: от особенностей rootless-сети до менее зрелой экосистемы вокруг проекта.
Rootless режим - не только плюсы#
Rootless-режим - главная фишка Podman, но у него есть обратная сторона, и знать о ней стоит до того, как вы с ней столкнетесь.
Порты ниже 1024#
Непривилегированный процесс в Linux не может слушать порты ниже 1024 - это ограничение ядра, а не Podman, но именно rootless-контейнеры с ним и сталкиваются в первую очередь. Опубликовать PublishPort=80:80 из rootless-контейнера напрямую не получится: нужно либо вносить изменения в net.ipv4.ip_unprivileged_port_start через sysctl, либо ставить reverse-proxy на непривилегированном порту повыше и пробрасывать его дальше средствами хоста. При этом надо учитывать, что весь мир ждет веб-сервер или обратный прокси на порту 80 и 443. Смысла разрешать публиковать порты ниже 1024 вроде как нелогично, это же фишка Podman. Я решил это переносом своего обратного прокси в отдельный LXC контейнер, тем самым отвязав его от любого бекэнда в принципе. Однако такой вариант не всем подходит по разным причинам.
Реальный IP клиента теряется#
С портами связана еще одна неприятность, о которой узнаешь обычно уже по факту. По умолчанию опубликованные порты rootless-контейнеров обслуживает отдельный процесс-посредник rootlessport, и до приложения внутри контейнера соединение доходит уже не с адреса реального клиента, а с внутреннего адреса самого Podman. Для обычного сервиса это не так важно, а вот для обратного прокси - очень: в его логах вместо адресов посетителей оказывается один и тот же внутренний IP, а вместе с ним теряют смысл ограничения по IP, rate limit и CrowdSec, который должен банить конкретных атакующих, а не весь трафик разом.
В Podman 6 появился экспериментальный вариант - переключить проброс портов на pasta (параметр rootless_port_forwarder="pasta" в containers.conf), тогда исходный IP клиента сохраняется. Но пока это именно эксперимент, и по умолчанию остается rootlessport. Мой вынесенный в отдельный LXC обратный прокси, о котором я писал выше, заодно снимает и эту проблему: прокси видит реальные адреса клиентов, потому что к rootless-контейнерам он вообще не относится.
Rootless-контейнеры живут, пока вы залогинены#
Rootless-сервисы, в том числе Quadlet-юниты в ~/.config/containers/systemd/, работают в пользовательском экземпляре systemd. А он по умолчанию запускается, только когда пользователь вошел в систему, и останавливается вместе со всеми контейнерами, когда закрыта последняя сессия. В итоге картина такая: днем все работает, вы выходите из SSH - и сервисы тихо умирают, а после перезагрузки хоста не поднимаются вовсе, пока вы снова не залогинитесь.
Лечится это одной командой:
sudo loginctl enable-linger $USERНо это ровно тот случай, когда про команду надо знать заранее. В Docker такой проблемы нет в принципе - демон запускается системой и от пользовательских сессий не зависит.
Аналога Docker Swarm у Podman не существует#
Если вы все еще используете Swarm-режим (или планировали) - в Podman его просто нет, ни в rootless, ни в rootful режиме, и не предвидится. Это осознанное архитектурное решение, так что рассчитывать на него не стоит в принципе. Хотя, правды ради, лично я считаю, что у Docker Swarm все равно нет будущего.
Права на bind-mount и UID-маппинг#
Rootless-контейнеры используют user namespaces: UID 0 внутри контейнера превращается в непривилегированный UID снаружи через subuid/subgid. Звучит элегантно, пока дело не доходит до bind-mount’ов существующих директорий с хоста. Файлы, созданные процессом внутри контейнера, на хосте принадлежат совершенно “инопланетному” UID из диапазона subuid, и обычный chown/chmod руками превращается в отдельное испытание, которое не для слабых духом.
Для этого существует podman unshare, который пускает вас в те же namespace’ы, что видит контейнер - но это еще одна команда, которую нужно знать и объяснять новичкам, тогда как в Docker (особенно при работе от root) такой проблемы почти никогда не возникает.
Есть и более системный обход: флаг --userns=keep-id мапит UID 0 внутри контейнера не на случайный subuid, а на тот же UID, под которым вы залогинены на хосте, - тогда файлы на bind-mount’ах создаются с привычным владельцем без плясок с podman unshare.
В свежих версиях Podman то же самое можно получить точечно, на уровне одного volume, суффиксом :U - Podman сам сделает chown содержимого при монтировании. Но сделано это именно для упрощения обхода ограничений. Тебе не надо учить какие-то новые команды, но тем не менее, ты “обходишь” ограничения технологии, что придает некий налет нелогичности происходящего.
Требования файловой системы к rootless-overlay#
Отдельная, менее очевидная проблема - rootless-overlay для хранилища образов требует от файловой системы поддержки d_type (то есть тип файла должен возвращаться прямо в записи каталога, без отдельного stat()). Без d_type rootless-overlay просто не поднимется - Podman откатится на vfs, который работает надежно, но заметно медленнее и имеет более жесткие требования к месту на диске, так как не может использовать слои между образами так эффективно, как overlay. На практике для домашнего сервера с обычным ext4/XFS (XFS - в случае, если ты адепт Red Hat) d_type есть из коробки, и это редко становится проблемой, но на некоторых сетевых ФС вроде NFS или при переносе на какое-нибудь экзотическое хранилище об этом стоит помнить.
Неполная совместимость с Docker Compose#
Сам Podman CLI действительно почти что называется zero-effort совместим с Docker CLI. Я об этом рассказывал еще в первой статье. А вот с Docker Compose все не так гладко, как хотелось бы.
podman-compose - это отдельный, независимый от самого Podman проект, а не встроенный аналог docker compose.
Участники проекта честно предупреждают в своем README, что цель - запускать docker-compose.yml без изменений, но на практике так получается не всегда (в моем случае никогда):
- у сервисов, подключенных сразу к нескольким пользовательским сетям в одном compose-файле, DNS-резолвинг по имени сервиса не всегда стабильно работает из соседних сетей, к которым сервис был подключен не первым;
external: trueдля уже существующей сети иногда не распознается корректно, потому чтоpodman-composeпо умолчанию добавляет префикс имени проекта к имени сети - и, если имена не совпадают буквально, вместо переиспользования существующей сети получаем попытку создать новую;- имена контейнеров и сетей, которые генерирует
podman-compose, по умолчанию используют другой разделитель (_вместо принятого в новых версиях Docker Compose-) - для части автоматизации и скриптов, которые парсят имена контейнеров, это может сломать логику, хотя разработчики уже добавили отдельный флаг совместимости; - не все версии
docker-compose.yml(в частности сложные healthcheck-конструкции, depends_on с условиями, некоторые профили) поддерживаются идентично - часть фич работает “почти так же”, часть требует правок в самом compose-файле, а часть просто придется удалить.
Есть и промежуточный вариант, о котором многие не знают. Команда podman compose - это тонкая обертка, которая по умолчанию ищет и запускает оригинальный docker-compose, если он установлен, и только при его отсутствии берет podman-compose. При этом обертка сама настраивает окружение так, чтобы docker-compose общался с Docker-совместимым сокетом Podman. То есть ваши compose-файлы обрабатывает эталонная реализация спецификации, а контейнеры при этом запускает Podman. Проблемы на уровне сети и rootless-специфики это, конечно, не отменяет, но разночтения в самом синтаксисе compose-файлов заметно сокращаются.
Формально можно перейти на нативный Quadlet+Podlet, о которых я писал в отдельной статье, и это действительно снимает большинство проблем (причем это самый правильный способ использования Podman) - но это уже не “тот же самый docker-compose.yml без изменений”, а миграция на другой формат конфигурации. Если у вас в проекте десятки готовых compose-файлов из чужих репозиториев (а в self-hosting так всегда), надо быть готовым к тому, что нужны точечные правки.
На macOS и Windows Podman - тоже виртуальная машина#
Один из главных аргументов в пользу Podman - отсутствие демона. Но это верно только для Linux. На macOS и Windows контейнеры в принципе не могут работать нативно (другое ядро), и что Docker Desktop, что podman machine решают эту проблему одинаково - поднимают легкую Linux-VM и уже внутри нее запускают настоящий Podman.
То есть на macOS и Windows daemonless-преимущество отсутствует: у вас снова есть фоновый процесс (просто в этом случае это сама VM), которую нужно запускать, следить за ее ресурсами и обновлять образ этой VM отдельно от самого Podman.
Причем есть и еще один мелкий нюанс. Фоновый процесс не один - на хосте параллельно с VM крутится еще и gvproxy, который через SSH-туннель прокидывает сетевой доступ и Docker-совместимый сокет внутрь машины, так что “просто VM” на практике - это VM плюс обвязка вокруг нее.
Для homelab, где сервер обычно на Linux, это не критично - но если у вас прод, и часть команды работает на маках, часть на Винде, то разница с Docker Desktop по факту куда меньше, чем кажется из маркетинговых сравнений.
Нет встроенной оркестрации на несколько хостов#
Podman отлично закрывает задачи одного хоста - это, что называется, by design. Но если тебе завтра понадобится:
- горизонтальное масштабирование сервиса под нагрузкой;
- HA-кластер из нескольких физических узлов;
- service discovery между узлами “из коробки”;
то готового решения у Podman нет. Генерация Kubernetes-манифестов через podman generate kube облегчает миграцию, но сама миграция все равно означает разворачивание полноценного Kubernetes (k3s, MicroK8s, RKE2 - не суть) со всеми сопутствующими прелестями: etcd или его аналог, control-plane, CNI-плагины.
Docker Swarm при всех своих недостатках хотя бы предлагает в меру простое родное решение по переходу от одного хоста к нескольким - у Podman такой “промежуточной ступеньки” нет вообще и не будет в обозримом будущем.
Экосистема и набор инструментов Podman пока догоняют Docker#
Технически Podman вроде достаточно зрелый проект, но по охвату экосистемы Docker все еще намного впереди, и это всегда ощущается на практике:
- GUI. Podman Desktop активно развивается и уже вполне пригоден для повседневной работы, но по количеству встроенных расширений, готовых интеграций и просто “вылизанности” интерфейса Docker Desktop далеко его обогнал;
- Готовые туториалы. Абсолютное большинство инструкций для self-hosted проектов в интернете по умолчанию написаны под
docker run/docker-compose up. Работать с ними приходится либо черезalias docker=podman(что может помочь в 90% случаев, но все-таки), либо вручную адаптировать под rootless-специфику - Volume-лейблы:Z/:zдля SELinux-систем, например, в оригинальных доках почти никогда не упоминаются, хотя, с моей точки зрения, такое упоминание обязательно. Не все в курсе особенностей SELinux; - Инструменты, которые жестко завязаны на
docker.sock. Часть популярных self-hosted утилит (некоторые дашборды, отдельные CI-раннеры, кое-какие мониторинговые агенты) исторически обращаются напрямую к Docker socket и его API-шке. Podman предоставляет Docker-совместимый REST API черезpodman system service, но решение не идеальное, не все в нем работает как надо, и для нишевых инструментов иногда приходится или искать форк с поддержкой Podman, или оставлять этот конкретный сервис на Docker; - Docker Hub vs реестры Red Hat. Сам Podman по умолчанию не привязан к одному реестру и это скорее плюс, но новичков первое время путает необходимость явно указывать полный путь до образа в реестре (
docker.io/library/nginxвместо простоnginx), если вregistries.confне настроены unqualified-search реестры так, как вам нужно. А на дистрибутивах, не связанных с Red Hat, их прописывать надо. Причем, в реальной жизни, - это даже наверно первая проблема, с которой столкнется каждый, просто по логике статьи указываю ее в конце.
Более высокий порог входа для новичков#
Отдельно стоит сказать про ментальную модель, как любят говорить за рубежом. Docker долгие годы был синонимом контейнеризации именно потому, что скрывал сложные решения под простой оболочкой: один демон, одна команда docker run, и все “просто работает” (как требует большинство новичков) от root, без необходимости разбираться в user namespaces и прочей семиотике. Podman требует намного большего понимания происходящего под капотом и принципов работы системы:
- что такое subuid/subgid и что произойдет, если диапазоны не настроены или пересекаются между пользователями;
- разница между rootless и rootful режимом и когда переключаться на второй оправданно;
- SELinux-лейблы на volume’ах в Fedora/RHEL-семействе, без которых контейнер просто так не увидит примонтированную директорию;
- cgroups v2 - в Podman 6 без них уже никак, поддержку cgroups v1 удалили полностью, так что на старых системах сначала придется разбираться с ними, а потом уже с Podman.
Для человека, который уже не раз настраивал/перестраивал homelab-инфраструктуру и не боится читать man, это не проблема, а скорее естественная часть процесса. Но если ваша цель - просто побыстрее поднять сервис и не тратить несколько уютных вечеров на чтение документации, с последующим вырыванием волос на голове и бросанием их в монитор, то первое знакомство с Podman может ощущаться заметно более болезненным, чем с Docker.
Мажорные версии ломают совместимость#
Docker за последние годы приучил к тому, что обновление движка - событие скучное. У Podman с этим смелее. Летом 2026 года вышел Podman 6, и список того, что в нем просто убрали, впечатляет:
- поддержку cgroups v1;
- iptables - теперь только nftables;
- сетевой стек CNI - теперь только Netavark;
slirp4netnsдля rootless-сети - теперь только pasta;- базу BoltDB - при первом запуске Podman попытается сам перенести ее в SQLite.
Плюс изменилось поведение по умолчанию: изоляция между сетями теперь включена, а podman volume prune удаляет только анонимные volume’ы. По отдельности все эти решения разумные, и большая часть из них даже приближает Podman к поведению Docker. Но в сумме это означает, что мажорное обновление Podman надо планировать как маленькую миграцию, а не нажимать dnf upgrade в пятницу вечером. Особенно если у вас на сервере что-то давно настроено “как-то так” и с тех пор не трогалось.
Обратная сторона той же медали - дистрибутивы с длинным циклом поддержки. На них Podman может отставать на несколько версий, и инструкции из интернета, написанные под свежий релиз, не всегда работают на том, что есть у вас в репозитории.
Когда эти недостатки действительно важны#
Подытоживая все вместе, я бы выделил три ситуации, где минусы Podman перевешивают его архитектурные плюсы:
- нужна оркестрация на несколько хостов здесь и сейчас, а не в перспективе - тогда либо Docker Swarm как временное решение, либо сразу переходить на Kubernetes;
- у тебя инфраструктура, которая завязана исключительно на инструменты, строго требующие доступа к
docker.sock, и альтернатив под Podman нет; - команда разработчиков работает преимущественно на macOS/Windows (а это наверно самый частый случай и лучший пример), а избавиться от VM-прослойки, переходя с Docker Desktop, не получится.
Во всех остальных сценариях - а для homelab и self-hosted серверов на Linux это подавляющее большинство случаев - недостатки скорее про “нужно один раз разобраться и настроить”, чем про “категорически не подходит”.
Выводы#
Ни один из перечисленных пунктов не отменяет того, что я писал в первой статье про преимущества Podman. Но недостатки у него более чем реальные, а не надуманные, как порой пишут в интернете при обсуждении того или иного решения:
- rootless-сеть иногда ограничивает больше, чем хотелось бы, - от портов ниже 1024 до потери реального IP клиента;
- rootless-сервисы без
loginctl enable-lingerживут ровно до выхода из сессии; - совместимость с Docker Compose неполная;
- мажорные обновления ломают совместимость, и к ним нужно готовиться;
- экосистема вокруг проекта пока в роли догоняющего Docker, как по охвату инструментов, так и инструкций.
Если вы планируете переход, разумный подход - не переписывать сразу всю инфраструктуру, а мигрировать по одному не самому критичному сервису за раз, как я и советовал в прошлый раз, и заранее закладывать время на то, чтобы упереться в один-два пункта из списка проблем настоящей статьи. Это не повод отказываться от Podman - это повод не разочаровываться, когда что-то пойдет не так с первого раза. А это “не так” обязательно произойдет.
Полезные ссылки:





