Docker и --userns-remap, как управлять разрешениями томов для обмена данными между хостом и контейнером?
В докере файлы, созданные внутри контейнеров, как правило, имеют непредсказуемое владение при проверке их с хоста. Владельцем файлов на томе является root (uid 0) по умолчанию, но как только учетные записи пользователей, не принадлежащие root, участвуют в контейнере и записываются в файловую систему, владельцы становятся более или менее случайными с точки зрения хоста.
Это проблема, когда вам необходимо получить доступ к данным тома с хоста, используя ту же учетную запись пользователя, которая вызывает команды докера.
Типичные обходные пути
- принуждение пользователей uID во время создания файлов Dockerfiles (не переносимых)
- передача UID хост-пользователя команде
docker run
в качестве переменной среды, а затем запуск некоторых команд chown
на томах в точке входа script.
Оба этих решения могут дать некоторый контроль над фактическими разрешениями за пределами контейнера.
Я ожидал, что пространство имен пользователей станет окончательным решением этой проблемы. Я провел несколько тестов с недавно выпущенной версией 1.10 и --userns-remap установлен на мою учетную запись рабочего стола. Тем не менее, я не уверен, что это может облегчить работу с файлами на смонтированных томах, я боюсь, что это может быть наоборот.
Предположим, что я запускаю этот базовый контейнер
docker run -ti -v /data debian:jessie /bin/bash
echo 'hello' > /data/test.txt
exit
Затем проверьте содержимое с хоста:
ls -lh /var/lib/docker/100000.100000/volumes/<some-id>/_data/
-rw-r--r-- 1 100000 100000 6 Feb 8 19:43 test.txt
Этот номер "100000" является суб-идентификатором моего хост-пользователя, но поскольку он не соответствует моему пользовательскому UID, я все равно не могу редактировать test.txt без привилегий. Этот подпользователь, похоже, не имеет никакого отношения к моему фактическому постоянному пользователю за пределами докера. Он не отображается назад.
Обходные пути, упомянутые ранее в этом сообщении, которые состоят в выравнивании UID между хостом и контейнером, больше не работают из-за сопоставления UID->sub-UID
, которое происходит в пространстве имен.
Затем, есть ли способ запустить докер с включенным пространством имен пользователей (для повышения безопасности), но при этом все еще позволяя хост-пользователю, работающему с докером, владеть файлами, созданными на томах?
Ответы
Ответ 1
Если вы заранее можете заранее настроить пользователей и группы, тогда можно назначить UID и GID таким образом, чтобы хост-пользователи соответствовали пользователям с именами внутри контейнеров.
Вот пример (Ubuntu 14.04, Docker 1.10):
-
Создайте пользователей с фиксированными числовыми идентификаторами:
useradd -u 5000 ns1
groupadd -g 500000 ns1-root
groupadd -g 501000 ns1-user1
useradd -u 500000 -g ns1-root ns1-root
useradd -u 501000 -g ns1-user1 ns1-user1 -m
-
Вручную отредактировать автоматически сгенерированные диапазоны подчиненных идентификаторов в файлах /etc/subuid
и /etc/subgid
:
ns1:500000:65536
(обратите внимание, что для ns1-root
и ns1-user1
нет записей из-за ограничений MAX_UID
и MAX_GID
в /etc/login.defs
)
-
Включить пространства имен пользователей в /etc/default/docker
:
DOCKER_OPTS="--userns-remap=ns1"
Restart daemon service docker restart
, убедитесь, что создан каталог /var/lib/docker/500000.500000
.
Теперь внутри контейнеров есть root
и user1
, а на хосте - ns1-root
и ns1-user1
, с соответствующими идентификаторами
UPDATE:, чтобы гарантировать, что пользователи, не являющиеся пользователями root, имеют фиксированные идентификаторы в контейнерах (например, user1 1000: 1000), создавайте их явно во время сборки изображения.
Тест-драйв:
-
Подготовьте каталог тома
mkdir /vol1
chown ns1-root:ns1-root /vol1
-
Попробуйте в контейнере
docker run --rm -ti -v /vol1:/vol1 busybox sh
echo "Hello from container" > /vol1/file
exit
-
Попробуйте у хоста
passwd ns1-root
login ns1-root
cat /vol1/file
echo "can write" >> /vol1/file
Не переносится и выглядит как хак, но работает.
Ответ 2
Вы можете избежать проблем с разрешением, используя команду docker cp
.
Собственность устанавливается для пользователя и основной группы в пункте назначения. Например, файлы, скопированные в контейнер, создаются с помощью UID:GID
пользователя root. Файлы, скопированные на локальный компьютер, создаются с помощью UID:GID
пользователя, который вызвал команду docker cp
.
Вот ваш пример, который переключился на использование docker cp
:
$ docker run -ti -v /data debian:jessie /bin/bash
[email protected]:/# echo 'hello' > /data/test.txt
[email protected]:/# exit
exit
$ docker volume ls
DRIVER VOLUME NAME
local f073d0e001fb8a95ad8d919a5680e72b21a457f62a40d671b63c62ae0827bf93
$ sudo ls -l /var/lib/docker/100000.100000/volumes/f073d0e001fb8a95ad8d919a5680e72b21a457f62a40d671b63c62ae0827bf93/_data
total 4
-rw-r--r-- 1 100000 100000 6 Oct 6 10:34 test.txt
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e33bb735a70f debian:jessie "/bin/bash" About a minute ago Exited (0) About a minute ago determined_hypatia
$ docker cp determined_hypatia:/data/test.txt .
$ ls -l test.txt
-rw-r--r-- 1 don don 6 Oct 6 10:34 test.txt
$ cat test.txt
hello
$
Однако, если вы просто хотите читать файлы из контейнера, вам не нужен именованный том. В этом примере вместо именованного тома используется именованный контейнер:
$ docker run -ti --name sandbox1 debian:jessie /bin/bash
[email protected]:/# echo 'howdy' > /tmp/test.txt
[email protected]:/# exit
exit
$ docker cp sandbox1:/tmp/test.txt .
$ ls -l test.txt
-rw-r--r-- 1 don don 6 Oct 6 10:52 test.txt
$ cat test.txt
howdy
$
Я нахожу имена томов полезными, когда я хочу скопировать файлы в контейнер, как описано в этот вопрос.