LinuxRuLinux без лишней теории
Контейнеры

Docker Rootless: установка, настройка и ограничения

Редакция LinuxRu7 мин чтенияИнструкции

Docker Rootless запускает демон Docker и контейнеры от обычного пользователя, поэтому взлом контейнера не даёт root на хосте. Настройка занимает несколько минут: пакет uidmap, подчинённые UID, скрипт dockerd-rootless-setuptool.sh и пользовательская служба systemd. Ниже установка, проверка и обход ограничений.

Docker Rootless: установка, настройка и ограничения
Фото: Open Grid Scheduler / Grid Engine, CC BY-SA 4.0, Wikimedia Commons
Содержание
  1. Зачем rootless
  2. Требования
  3. Установка
  4. Запуск и проверка
  5. Ограничения
  6. Порты, ping, лимиты
  7. Права на тома
  8. Ошибки и откат
  9. Частые вопросы

Чем опасен обычный Docker и что меняет rootless

В классической установке демон dockerd работает от root. Чтобы не писать sudo перед каждой командой, пользователя добавляют в группу docker, и с этого момента он фактически получает права root: достаточно запустить контейнер с примонтированным корнем хоста, например docker run -v /:/host, и можно править любые системные файлы. Любая уязвимость в демоне или побег из контейнера тоже дают атакующему root на хосте.

В режиме Rootless и демон, и контейнеры работают от обычного пользователя внутри отдельного пространства имён пользователей. Root внутри контейнера соответствует вашей учётной записи снаружи, а остальные UID контейнера отображаются в диапазон подчинённых идентификаторов из /etc/subuid. Сеть и порты пробрасывает утилита RootlessKit. Итог: взлом контейнера даёт атакующему права вашего пользователя, а не всей системы.

Rootless удобен на рабочей машине разработчика, на общих серверах, где несколько человек запускают свои контейнеры, и в CI. Для продакшена с сетевыми плагинами и тонкой настройкой сети он подходит хуже, ограничения разобраны ниже.

Что должно быть в системе до установки

  • утилиты newuidmap и newgidmap, их даёт пакет uidmap (в Fedora и Arch они входят в shadow-utils и shadow);
  • не меньше 65 536 подчинённых UID и GID для вашего пользователя в /etc/subuid и /etc/subgid;
  • systemd и cgroup v2, если нужны ограничения ресурсов. В Ubuntu 26.04, Debian 13, Fedora 44 и Arch cgroup v2 включены по умолчанию.
# Debian и Ubuntu
sudo apt install uidmap

# есть ли у пользователя подчинённые идентификаторы
grep "^$(whoami):" /etc/subuid /etc/subgid

# если пусто, выдать диапазон вручную
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER

# какая версия cgroup: cgroup2fs означает v2
stat -fc %T /sys/fs/cgroup

Обычно записи в /etc/subuid создаются автоматически при добавлении пользователя через useradd или adduser. Вручную их приходится добавлять для старых учётных записей и пользователей из LDAP. О работе с учётными записями подробнее в статье Пользователи и sudo в Linux.

Установка Docker Rootless по шагам

Шаг 1. Пакеты Docker

Надёжнее всего ставить Docker из официального репозитория docker.com: там есть пакет docker-ce-rootless-extras со скриптом настройки. Если Docker уже установлен из этого репозитория, проверьте, есть ли скрипт:

which dockerd-rootless-setuptool.sh

# Ubuntu и Debian с репозиторием docker.com
sudo apt install docker-ce docker-ce-rootless-extras

# Fedora с репозиторием docker.com
sudo dnf install docker-ce docker-ce-rootless-extras

В Arch rootless-скрипты ставятся отдельным пакетом из AUR. Без пакетного менеджера Docker предлагает установочный скрипт curl -fsSL https://get.docker.com/rootless | sh, бинарники он кладёт в ~/bin.

Шаг 2. Отключить системный демон

Если раньше работал обычный Docker и он вам больше не нужен, остановите его, иначе скрипт попросит параметр --force:

sudo systemctl disable --now docker.service docker.socket
sudo rm /var/run/docker.sock

Образы и контейнеры системного демона в /var/lib/docker при этом не удаляются, но rootless-демон их не увидит: у него своё хранилище.

Шаг 3. Настройка от обычного пользователя

# без sudo, из обычного сеанса пользователя
dockerd-rootless-setuptool.sh install

Скрипт создаёт пользовательскую службу systemd docker.service, запускает её и создаёт контекст Docker с именем rootless. Если чего-то не хватает, он сам выведет, какие пакеты или настройки нужны.

Важно запускать его из полноценного входа в систему, через графический сеанс или SSH. После sudo su - user переменная XDG_RUNTIME_DIR и пользовательский экземпляр systemd обычно не настроены, и установка падает. В таком случае зайдите заново по SSH или используйте machinectl shell user@.

Запуск, автозагрузка и проверка

# управление пользовательским демоном
systemctl --user start docker
systemctl --user enable docker
systemctl --user status docker

# чтобы демон стартовал при загрузке, а не только после входа
sudo loginctl enable-linger $USER

# проверка: должно быть Context: rootless и rootless в Security Options
docker info
docker run --rm hello-world

Без enable-linger пользовательские службы останавливаются, когда вы выходите из последнего сеанса. Для сервера, где контейнеры должны жить постоянно, эта команда обязательна. Подробнее о пользовательских службах и их журналах есть в статье systemctl: управление службами в Linux.

Docker CLI переключается на rootless через контекст, но некоторые программы, например старые плагины IDE или скрипты, смотрят только в переменную окружения. Для них добавьте в ~/.bashrc:

export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock

Docker Compose работает с rootless без изменений, команды те же: docker compose up -d. Про сам плагин и формат файлов читайте в материале Docker Compose plugin: современная работа с compose.yaml.

Что работает иначе, чем в обычном Docker

ВозможностьОбычный DockerRootlessЧто делать
Порты ниже 1024ДаНет по умолчаниюsysctl или setcap для rootlesskit
ping из контейнераДаЗависит от sysctlНастроить ping_group_range
Лимиты CPU и памятиДаТолько с cgroup v2 и systemdДелегировать контроллеры
Профили AppArmor для контейнеровДаНетПолагаться на изоляцию userns
Overlay-сети и SwarmДаНетОбычный Docker или Kubernetes
Checkpoint и SCTP-портыДаНетОбычный Docker
ХранилищеЛюбой драйверoverlay2, fuse-overlayfs, btrfs, vfsНе держать данные на NFS
Каталог данных/var/lib/docker~/.local/share/dockerСледить за местом в домашнем разделе

Конфигурация демона лежит в ~/.config/docker/daemon.json, а не в /etc/docker. Не путайте этот каталог с ~/.docker, где хранит настройки клиент.

Порты 80 и 443, ping и лимиты ресурсов

Привилегированные порты

Rootless-демон не может слушать порты ниже 1024. Есть два способа это обойти. Первый разрешает такие порты только RootlessKit, второй разрешает всем непривилегированным программам в системе:

# вариант 1: capability для rootlesskit
sudo setcap cap_net_bind_service=ep $(which rootlesskit)
systemctl --user restart docker

# вариант 2: снизить порог для всех
echo "net.ipv4.ip_unprivileged_port_start=80" | sudo tee /etc/sysctl.d/90-rootless-ports.conf
sudo sysctl --system

После обновления пакета rootlesskit capability из первого варианта может слететь, проверяйте её командой getcap $(which rootlesskit). Самый простой путь вообще ничего не менять: публиковать сервис на 8080 и 8443, а снаружи поставить обратный прокси.

ping и ограничение ресурсов

# разрешить ICMP echo для всех групп
echo "net.ipv4.ping_group_range = 0 2147483647" | sudo tee /etc/sysctl.d/90-ping.conf
sudo sysctl --system

# делегировать пользователю все контроллеры cgroup
sudo mkdir -p /etc/systemd/system/user@.service.d
printf "[Service]\nDelegate=cpu cpuset io memory pids\n" | sudo tee /etc/systemd/system/user@.service.d/delegate.conf
sudo systemctl daemon-reload

По умолчанию пользователю обычно делегированы только контроллеры memory и pids, поэтому --cpus без этой настройки не сработает. После изменения выйдите из системы и войдите снова.

Права на файлы в томах: самая частая путаница

Внутри контейнера root соответствует вашему UID снаружи, поэтому файлы, созданные root в примонтированном каталоге, на хосте будут принадлежать вам. А вот файлы, которые создаёт непривилегированный пользователь контейнера, например UID 999 у PostgreSQL, на хосте получат UID из подчинённого диапазона вроде 100998. Удалить их обычным rm не получится.

# выполнить команду в пространстве имён rootless-демона
rootlesskit rm -rf ~/projects/db-data

# посмотреть, как UID контейнера отображаются на хост
rootlesskit cat /proc/self/uid_map

Для каталогов с данными приложений используйте именованные тома Docker вместо привязки папок из домашнего каталога. Тома живут в ~/.local/share/docker/volumes, демон сам управляет их правами, и проблема с чужими UID на хосте почти исчезает.

Типичные ошибки, удаление и альтернатива

  • Cannot connect to the Docker daemon. Клиент стучится в системный сокет. Проверьте docker context ls и переменную DOCKER_HOST.
  • newuidmap: write to uid_map failed. Нет записей в /etc/subuid или пакета uidmap.
  • Ошибки AppArmor в Ubuntu 24.04 и новее. Ubuntu ограничивает непривилегированные пространства имён пользователей. Пакеты docker.com приносят нужный профиль, а при установке скриптом профиль для rootlesskit придётся добавить вручную по документации Docker.
  • Демон не запускается после перезагрузки. Не включены systemctl --user enable docker и loginctl enable-linger.

Логи демона смотрите командой journalctl --user -u docker. Если rootless не подошёл, удалите его и верните обычный режим:

dockerd-rootless-setuptool.sh uninstall
rootlesskit rm -rf ~/.local/share/docker
sudo systemctl enable --now docker.service docker.socket

Если хочется контейнеров без root изначально, посмотрите на Podman: он из коробки работает без демона и без root, а с Quadlet контейнеры оформляются как обычные службы systemd. Подробности в статье Podman Quadlet: контейнеры как службы systemd. Полное описание режима есть в официальной документации Docker.

Частые вопросы

Чем Docker Rootless отличается от добавления пользователя в группу docker?

Группа docker даёт доступ к демону, который работает от root, поэтому её участник фактически получает права root на хосте. В режиме Rootless сам демон работает от обычного пользователя, и взлом контейнера ограничен правами этой учётной записи.

Как запустить контейнер на порту 80 в Docker Rootless?

Выдайте rootlesskit capability командой sudo setcap cap_net_bind_service=ep $(which rootlesskit) и перезапустите демон, либо снизьте порог через sysctl net.ipv4.ip_unprivileged_port_start. Можно также публиковать порт 8080 и поставить перед ним обратный прокси.

Работает ли docker compose в режиме Rootless?

Да. Compose обращается к тому же сокету, что и CLI, поэтому команды docker compose работают без изменений.

Где Docker Rootless хранит образы и контейнеры?

В каталоге ~/.local/share/docker. Настройки демона лежат в ~/.config/docker/daemon.json.

Как удалить Docker Rootless?

Выполните dockerd-rootless-setuptool.sh uninstall, затем удалите данные командой rootlesskit rm -rf ~/.local/share/docker. Системный Docker при необходимости включается снова через systemctl enable --now docker.service docker.socket.

Документация и источники

Читайте также

Команды проверены на актуальных версиях дистрибутивов на момент обновления. Перед изменением системных настроек сделайте резервную копию.