Rootless Podman запускает контейнеры от обычного пользователя: без демона, без членства в группе docker и без прав root на хосте. Для домашней лаборатории это снимает главный риск: ошибка или уязвимость в контейнере уже не означает компромисс всей машины. Вместе с безопасностью приходят ограничения — нельзя занять порт 80, сложнее с правами на тома, а половина ошибок выглядит как «operation not permitted» без объяснений. Разберём, как rootless-режим устроен, как подготовить систему и что делать, когда Podman отказывается запускать контейнер.

Как работает rootless-режим

В обычном режиме Podman общается с ядром от root, и процессы внутри контейнера с UID 0 соответствуют UID 0 хоста. В rootless всё иначе: Podman стартует от вашего пользователя, создаёт новое user namespace и внутри него действительно становится root. Ядро подменяет идентификаторы — ваш UID 1000 снаружи внутри выглядит как 0, а остальные номера берутся из диапазона, выделенного в /etc/subuid.

Диапазон нужен не только для красоты. Именно он позволяет запускать процессы с разными UID внутри одного контейнера: например, master и worker PostgreSQL или nginx с отдельным пользователем. Если дополнительных диапазонов нет, доступен единственный UID, и образы, которые меняют пользователя через USER в Dockerfile, падают с permission denied.

Запись в uid_map выполняет не сам Podman, а небольшие setuid-хелперы newuidmap и newgidmap из пакета uidmap. Они проверяют, что запрошенные диапазоны выделены именно этому пользователю, и только потом пишут в /proc/PID/uid_map. Поэтому бит setuid на этих файлах — обязательное условие, а не случайность.

Проверка и подготовка системы

Сначала убедитесь, что диапазоны выделены. Обычно это делает useradd, но в минимальных образах и после ручного создания пользователя записи может не быть.

grep "$USER" /etc/subuid /etc/subgid
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 "$USER"
sudo apt install uidmap passt
podman info --format '{{.Host.Security.Rootless}}'

Команда должна вернуть true. Если диапазоны пришлось добавлять, выполните podman system migrate: он пересоздаст отображение для уже существующего хранилища. Следите, чтобы диапазоны разных пользователей не пересекались — это частая причина ошибки write to uid_map failed. Проверить занятые диапазоны можно через sort -t: -k2 -n /etc/subuid.

Хранилище и права на тома

Rootless-контейнеры живут не в /var/lib/containers, а в ~/.local/share/containers/storage. Драйвер хранения по умолчанию — overlay поверх fuse-overlayfs, если ядро и дистрибутив не разрешают непривилегированный overlayfs. Проверить, что реально используется, можно так:

podman info --format '{{.Store.GraphDriverName}}'
podman system df
podman unshare chown -R 1000:1000 ~/data
podman unshare ls -ln ~/data

Если в выводе vfs, каждый слой копируется целиком: место расходуется заметно быстрее, а сборка образов становится медленной. fuse-overlayfs медленнее нативной overlay, но предсказуем и не требует прав root.

С томами есть тонкость. Флаг :U при монтировании рекурсивно меняет владельца каталога на пользователя контейнера, а :Z перемаркирует его для SELinux. В rootless-режиме chown внутри контейнера попадает в subuid-диапазон, поэтому на хосте владельцем каталога окажется, например, UID 100999. Это нормально. Чтобы посмотреть на файлы «глазами контейнера», используйте podman unshare — он входит в то же пространство идентификаторов.

Сеть без привилегий

Контейнер получает собственный network namespace, а трафик наружу проходит через pasta (в Podman 5) или slirp4netns. Внутри контейнера 127.0.0.1 — это сам контейнер, а не хост; для обращения к сервисам хоста есть имя host.containers.internal. Проброс портов выполняет rootlessport: Podman слушает порт от вашего имени и пересылает соединения внутрь.

podman run -d --name web -p 8080:80 docker.io/library/nginx:alpine
curl -I http://127.0.0.1:8080
podman port web
ss -lntp | grep 8080

Порты ниже 1024 в rootless-режиме недоступны: -p 80:80 вернёт bind: permission denied. Вариантов три: поставить обратный прокси на высоком порту, разрешить непривилегированные порты через sysctl net.ipv4.ip_unprivileged_port_start=80 (это делает администратор хоста) или использовать systemd-сокет с передачей дескриптора. Для домашней лаборатории почти всегда достаточно прокси.

Несколько контейнеров удобнее объединить в пользовательскую сеть: podman network create app. В ней работает разрешение имён через aardvark-dns, и контейнеры находят друг друга по имени, а не по IP.

Автозапуск и лимиты

Главная ловушка rootless-режима — сессия пользователя. Без включённого linger systemd завершает пользовательские службы при выходе из системы и останавливает контейнеры. Включить постоянную сессию нужно один раз:

sudo loginctl enable-linger "$USER"
loginctl show-user "$USER" --property=Linger
systemctl --user daemon-reload
systemctl --user enable --now container-web.service

Юнит удобнее не писать руками, а описывать через Quadlet: файл .container в ~/.config/containers/systemd/ превращается в службу при daemon-reload. Генератор podman generate systemd устарел, и в новых версиях на него не стоит опираться. Не передавайте в ExecStart флаг --restart=always: перезапуском управляет systemd, а не Podman, иначе получите борьбу двух менеджеров.

Типичные ошибки и диагностика

  • cannot clone: Operation not permitted — user namespaces запрещены ядром или отсутствует newuidmap. Проверьте sysctl user.max_user_namespaces и права на хелперы.
  • newuidmap: write to uid_map failed — диапазон пересекается с другим пользователем либо с бинарников снят бит setuid.
  • permission denied на томе — владелец каталога не совпадает с UID внутри контейнера; помогут :U или podman unshare chown.
  • short write и странные ошибки слоёв — кончилось место или сбой fuse-overlayfs; смотрите podman system df.
podman unshare cat /proc/self/uid_map
ls -l /usr/bin/newuidmap /usr/bin/newgidmap
journalctl --user -u container-web.service -n 50 --no-pager
podman system prune --all --volumes

Перед очисткой проверьте, что в podman system df занимает место: часто виноваты не образы, а остановленные контейнеры и неиспользуемые тома. И помните, что --volumes удаляет данные безвозвратно.

Итог

Rootless Podman — это не флаг, а другой способ работы с ядром: user namespace, диапазоны subuid, fuse-overlayfs и rootlessport. Если подготовить /etc/subuid, включить linger и заранее решить вопрос с портами и правами на тома, ограничения перестают мешать. Вы получаете контейнеры, которые не могут незаметно переписать системные файлы, и стек, который одинаково работает на ноутбуке и на сервере без демона с правами root.

Насколько публикация полезна?

Нажмите на звезду, чтобы оценить!

Средняя оценка 0 / 5. Количество оценок: 0

Оценок пока нет. Поставьте оценку первым.

Поделиться: Telegram ВКонтакте