Текст и данные · Инструкция
Docker userns-remap: как настроить UID/GID mapping
Docker userns-remap полезен, когда root внутри контейнера не должен соответствовать настоящему root на хосте.
Короткий ответ
userns-remap в Docker переносит root внутри контейнера на непривилегированный высокий UID хоста, но сам Docker daemon продолжает работать как root. Включайте remap через daemon.json только после резервной копии конфигурации и проверки bind mounts, потому что меняется видимость данных и владельцы файлов.
Как работает userns-remap
User namespace позволяет контейнеру считать процесс UID 0 «root» внутри своего пространства, но на хосте этот UID отображается в непривилегированный subordinate диапазон. Например, запись testuser:231072:65536 означает, что контейнерный UID 0 может быть сопоставлен с 231072, UID 1 — с 231073 и так далее. В результате процесс, который выбрался из контейнерного namespace, не получает настоящий UID 0 хоста. Это полезный дополнительный слой защиты, но он не отменяет необходимость минимальных capabilities, безопасных образов и ограничения доступа к Docker socket. В отличие от Rootless mode, dockerd при userns-remap остаётся root-процессом. Поэтому выбирать между режимами следует по модели угроз и совместимости, а не только по названию «user namespace».
Совет: Сначала протестируйте remap на отдельном хосте или тестовом daemon, если у вас много bind mounts с жёстко заданными UID/GID.
Безопасная последовательность включения userns-remap
- Для простого сценария можно использовать значение default: Docker создаёт пользователя dockremap и subordinate диапазоны, либо заранее создать отдельного пользователя и проверить его записи в /etc/subuid и /etc/subgid.
- Добавьте параметр "userns-remap": "default" или имя выбранного пользователя в конфигурацию daemon и перезапустите Docker. Перед изменением сохраните копию daemon.json и убедитесь, что JSON валиден.
- После включения Docker начинает использовать namespaced data под /var/lib/docker. Существующие images и containers могут выглядеть как исчезнувшие, потому что прежнее содержимое маскируется новым namespace; не удаляйте старые данные в панике.
- Запустите тестовый контейнер и создайте файл в bind-mounted каталоге. UID 0 контейнера должен отображаться на хосте как высокий subordinate UID, поэтому заранее настройте права каталогов, с которыми контейнеру нужно работать.
Предупреждение: Включение userns-remap на уже заполненном Docker host может сделать старые images и containers невидимыми для активного daemon до отката настройки.
Почему ломаются bind mounts и права файлов
Проблема возникает не в Docker-команде как таковой, а в разных числовых UID по обе стороны namespace. Контейнер может писать файл как root, но на хосте владельцем будет высокий subordinate UID, а не root. Если bind-mounted каталог принадлежит конкретному локальному пользователю и имеет строгие права, контейнер может получить Permission denied. Исправлять это chmod 777 — плохая идея: вы снимаете ограничения у всех пользователей хоста. Лучше определить, какой UID реально нужен приложению, какие каталоги должны быть writable, и выдать разрешения целевому remapped диапазону или поменять архитектуру хранения. Named volumes часто проще в эксплуатации, потому что Docker контролирует их размещение, но они не заменяют bind mount там, где приложению нужен конкретный путь хоста.
Совет: Перед изменением прав используйте stat или ls -ln: числовые UID/GID объясняют проблему точнее, чем имена пользователей.
userns-remap или Rootless: в чём разница
- userns-remap: daemon остаётся root, контейнерные UID/GID переназначаются на subordinate диапазоны; подходит, когда нужен дополнительный namespace-барьер при сохранении обычного rootful daemon. Rootless: и daemon, и контейнеры работают без root-привилегий пользователя хоста; модель безопаснее в отношении самого dockerd, но совместимость с некоторыми низкоуровневыми функциями уже. В обоих случаях важны /etc/subuid и /etc/subgid, однако mapping отличается. Нельзя считать эти режимы взаимозаменяемыми настройками одного флажка: они по-разному влияют на сокет daemon, сеть, владельцев файлов и административную модель.
Важно: Решение принимайте по требованиям workloads, а не по принципу «включим оба и станет безопаснее»: совместимость должна быть проверена отдельно.
Что проверить до переноса production workloads
- Есть резервная копия daemon.json; известны активные bind mounts; записаны UID/GID приложений; /etc/subuid и /etc/subgid корректны; тестовый container видит нужные каталоги; старые данные Docker не удалены после первого «исчезновения»; критичные сервисы перезапущены в тестовой среде; права не расширены до 777; есть понятный план отката параметра userns-remap.
Практический тест прав после включения remap
После перезапуска daemon создайте отдельный тестовый каталог на хосте и подключите его bind mount в минимальный контейнер. Внутри контейнера создайте файл от UID 0, затем на хосте выполните ls -ln и посмотрите числового владельца. Он должен быть высоким subordinate UID, а не настоящим root хоста. Затем повторите операцию от непривилегированного пользователя внутри контейнера и сравните mapping. Если production-приложение пишет в заранее созданный каталог, выдайте доступ конкретному remapped диапазону или используйте управляемый volume; не расширяйте каталог до 0777 только ради исчезновения ошибки. Отдельно проверьте резервное копирование: инструмент на хосте должен иметь права читать новые владельцы. Такой тест заранее выявляет две самые неприятные проблемы userns-remap — неожиданные Permission denied и backup job, который внезапно перестал видеть файлы. Только после этого переносите stateful-сервис с реальными данными.
Совет: Если после включения список образов стал пустым, сначала проверьте namespaced каталог Docker: документация прямо предупреждает, что старые объекты маскируются.
Как подготовить откат userns-remap без потери данных
Перед включением remap зафиксируйте текущее состояние: сохраните `daemon.json`, список важных контейнеров и volumes, а для stateful-сервисов сделайте прикладную резервную копию данных. Docker предупреждает, что userns-remap маскирует существующие image и container layers в `/var/lib/docker/`, потому что namespaced данные хранятся отдельно. Поэтому пустой `docker image ls` сразу после включения — ожидаемый эффект, а не повод удалять старые каталоги. Для теста поднимите один новый контейнер, проверьте его bind mounts и числовые UID через `ls -ln`. Если приложение не может читать или писать данные, откат должен начинаться с остановки тестовых workloads и возврата прежнего параметра daemon, а не с массового `chown` всего `/var/lib/docker`. Учтите обратную сторону: объекты, созданные при включённом remap, также перестают быть доступны после отключения режима. Поэтому не смешивайте рабочую миграцию и эксперимент на единственном экземпляре данных. Сначала подтвердите права и backup/restore на тестовом сервисе, затем переносите постоянные volumes. Это превращает userns-remap из рискованного переключателя в контролируемую миграцию с понятной точкой возврата.
Что учитывать
Проблема возникает не в Docker-команде как таковой, а в разных числовых UID по обе стороны namespace. Контейнер может писать файл как root, но на хосте владельцем будет высокий subordinate UID, а не root. Если bind-mounted каталог принадлежит конкретному локальному пользователю и имеет строгие права, контейнер может получить Permission denied. Исправлять это chmod 777 — плохая идея: вы снимаете ограничения у всех пользователей хоста. Лучше определить, какой UID реально нужен приложению, какие…
Источники и проверка
Фактическая часть сверена по первичным источникам (в т.ч. Isolate containers with a user namespace). Пример и формулировки — редакция N1RO на 2026-09-21.