Normalmente, los problemas de permisos con un montaje de volumen de host se deben a que el uid / gid dentro del contenedor no tiene acceso al archivo de acuerdo con los permisos uid / gid del archivo en el host. Sin embargo, este caso específico es diferente.
El punto al final de la cadena de permiso drwxr-xr-x.
, indica que SELinux está configurado. Al usar un montaje de host con SELinux, debe pasar una opción adicional al final de la definición de volumen:
- La
z
opción indica que el contenido de montaje de enlace se comparte entre varios contenedores.
- La
Z
opción indica que el contenido de montaje de enlace es privado y no compartido.
Su comando de montaje de volumen se vería así:
sudo docker run -i -v /data1/Downloads:/Downloads:z ubuntu bash
Vea más sobre los montajes de host con SELinux en: https://docs.docker.com/storage/#configure-the-selinux-label
Para otros que ven este problema con los contenedores que se ejecutan como un usuario diferente, debe asegurarse de que el uid / gid del usuario dentro del contenedor tenga permisos para el archivo en el host. En los servidores de producción, esto a menudo se realiza controlando el uid / gid en el proceso de creación de imágenes para que coincida con un uid / gid en el host que tiene acceso a los archivos (o mejor aún, no use montajes de host en producción).
A menudo se prefiere un volumen con nombre a los montajes de host porque inicializará el directorio del volumen desde el directorio de la imagen, incluidos los permisos y la propiedad del archivo. Esto sucede cuando el volumen está vacío y el contenedor se crea con el volumen con nombre.
Los usuarios de MacOS ahora tienen OSXFS que maneja uid / gid automáticamente entre el host de Mac y los contenedores. Un lugar con el que no ayuda son los archivos del interior de la VM incorporada que se montan en el contenedor, como /var/lib/docker.sock.
Para entornos de desarrollo donde el uid / gid del host puede cambiar por desarrollador, mi solución preferida es iniciar el contenedor con un punto de entrada que se ejecute como root, arreglar el uid / gid del usuario dentro del contenedor para que coincida con el volumen del host uid / gid, y luego use gosu
para soltar desde la raíz al usuario del contenedor para ejecutar la aplicación dentro del contenedor. El guión importante para esto está fix-perms
en mis guiones de imágenes base, que se pueden encontrar en: https://github.com/sudo-bmitch/docker-base
Lo importante del fix-perms
script es:
# 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
Eso lleva el uid del usuario dentro del contenedor y el uid del archivo, y si no coinciden, llama usermod
para ajustar el uid. Por último, realiza una búsqueda recursiva para corregir cualquier archivo que no haya cambiado los uid. Me gusta más que ejecutar un contenedor con un -u $(id -u):$(id -g)
indicador porque el código del punto de entrada anterior no requiere que cada desarrollador ejecute un script para iniciar el contenedor, y cualquier archivo fuera del volumen que sea propiedad del usuario tendrá sus permisos corregidos.
También puede hacer que Docker inicialice un directorio de host desde una imagen utilizando un volumen con nombre que realiza un montaje de enlace. Este directorio debe existir de antemano y debe proporcionar una ruta absoluta al directorio del host, a diferencia de los volúmenes del host en un archivo de composición que pueden ser rutas relativas. El directorio también debe estar vacío para que Docker lo inicialice. Se ven tres opciones diferentes para definir un volumen con nombre para un montaje de enlace:
# 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
...
Por último, si intenta usar espacios de nombres de usuario, encontrará que los volúmenes de host tienen problemas de permisos porque los uid / gid de los contenedores están desplazados. En ese escenario, probablemente sea más fácil evitar los volúmenes de host y solo usar volúmenes con nombre.