Как правило, проблемы с разрешениями при монтировании тома хоста связаны с тем, что uid / gid внутри контейнера не имеет доступа к файлу в соответствии с разрешениями uid / gid файла на хосте. Однако этот конкретный случай отличается.
Точка в конце строки разрешения drwxr-xr-x.
указывает, что SELinux настроен. При использовании монтирования хоста с SELinux вам необходимо передать дополнительную опцию в конец определения тома:
z
Параметр указывает на то, что содержание привязка смонтированного распределяется между несколькими контейнерами.
- Параметр
Z
указывает, что содержимое подключения bind является частным и не общим.
Ваша команда монтирования тома будет выглядеть так:
sudo docker run -i -v /data1/Downloads:/Downloads:z ubuntu bash
Подробнее о монтировании хоста с помощью SELinux читайте по адресу: https://docs.docker.com/storage/#configure-the-selinux-label.
Для других, которые видят эту проблему с контейнерами, работающими как другой пользователь, вы должны убедиться, что uid / gid пользователя внутри контейнера имеют разрешения на файл на хосте. На производственных серверах это часто делается путем управления uid / gid в процессе построения образа, чтобы соответствовать uid / gid на хосте, который имеет доступ к файлам (или, что еще лучше, не использовать монтирование хоста в рабочей среде).
Именованный том часто предпочтительнее для хостов монтирования, потому что он инициализирует каталог тома из каталога образа, включая любое владение файлом и разрешения. Это происходит, когда том пуст и контейнер создается с указанным томом.
У пользователей MacOS теперь есть OSXFS которая автоматически обрабатывает uid / gid между хостом Mac и контейнерами. Единственное место, где это не помогает, это файлы из встроенной виртуальной машины, которые монтируются в контейнер, например /var/lib/docker.sock.
В средах разработки, где uid / gid хоста может меняться в зависимости от разработчика, мое предпочтительное решение состоит в том, чтобы запустить контейнер с точкой входа, работающей от имени пользователя root, исправить uid / gid пользователя внутри контейнера в соответствии с uid / gid тома хоста и затем используйте gosu
для перехода от пользователя root к пользователю контейнера, чтобы запустить приложение внутри контейнера. Важный сценарий для этого есть fix-perms
в моих сценариях для базовых изображений, которые можно найти по адресу: https://github.com/sudo-bmitch/docker-base
Важный бит из fix-perms
сценария:
# update the uid
if [ -n "$opt_u" ]; then
OLD_UID=$(getent passwd "${opt_u}" | cut -f3 -d:)
NEW_UID=$(stat -c "%u" "$1")
if [ "$OLD_UID" != "$NEW_UID" ]; then
echo "Changing UID of $opt_u from $OLD_UID to $NEW_UID"
usermod -u "$NEW_UID" -o "$opt_u"
if [ -n "$opt_r" ]; then
find / -xdev -user "$OLD_UID" -exec chown -h "$opt_u" {} \;
fi
fi
fi
Это получает пользовательский идентификатор внутри контейнера и пользовательский идентификатор файла, и, если они не совпадают, вызывает usermod
настройку пользовательского идентификатора. Наконец, он делает рекурсивный поиск, чтобы исправить любые файлы, которые не изменили uid. Мне это нравится больше, чем запуск контейнера с -u $(id -u):$(id -g)
флагом, потому что приведенный выше код точки входа не требует от каждого разработчика запуска сценария для запуска контейнера, и для любых файлов вне тома, принадлежащих пользователю, будут исправлены их разрешения.
Вы также можете сделать так, чтобы docker инициализировал каталог хоста из образа, используя именованный том, который выполняет подключение. Этот каталог должен существовать заранее, и вам необходимо указать абсолютный путь к каталогу хоста, в отличие от томов хоста в файле составления, которые могут быть относительными путями. Каталог также должен быть пустым, чтобы докер мог его инициализировать. Три различных варианта определения именованного тома для монтирования привязки выглядят так:
# create the volume in advance
$ docker volume create --driver local \
--opt type=none \
--opt device=/home/user/test \
--opt o=bind \
test_vol
# create on the fly with --mount
$ docker run -it --rm \
--mount type=volume,dst=/container/path,volume-driver=local,volume-opt=type=none,volume-opt=o=bind,volume-opt=device=/home/user/test \
foo
# inside a docker-compose file
...
volumes:
bind-test:
driver: local
driver_opts:
type: none
o: bind
device: /home/user/test
...
Наконец, если вы попытаетесь использовать пользовательские пространства имен, то обнаружите, что у томов хоста есть проблемы с разрешениями, потому что значения uid / gid контейнеров смещены. В этом случае, вероятно, проще всего избежать томов хоста и использовать только именованные тома.