Подтвердить что ты не робот

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, которое происходит в пространстве имен.

Затем, есть ли способ запустить докер с включенным пространством имен пользователей (для повышения безопасности), но при этом все еще позволяя хост-пользователю, работающему с докером, владеть файлами, созданными на томах?

4b9b3361

Ответ 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
$ 

Я нахожу имена томов полезными, когда я хочу скопировать файлы в контейнер, как описано в этот вопрос.