User Tools

Site Tools


permisos_y_propietarios_en_volumenes_con_docker-compose

Cómo manejar los permisos y propietarios de volumenes / bind mount en docker

Manual rápido y completo de Dockerfile:guia_rapida_de_dockerfile
Manual rápido y completo de Docker (linea de comando):guia_rapida_de_la_linea_de_comandos_de_docker
Manual rápido y completo de Docker Swarm: guia_rapida_de_docker_swarm

En el ecosistema docker se usan volúmenes y bind mounts para guardar datos de forma que no sean eliminados cuando los contenedores finallicen. Los volúmenes pueden ser configurados para que usen un determinado propietario y este coincida con el del punto de montaje. Pero no así los antiguos bind mounts, los cuales montan carpeta del host anfitrión y deberían usarse solo cuando son 100% necesarios, en resumen, cuando se debe acceder a determinado directorio del host anfitrión. Con los bind mounts siempre es necesario que el usuario del contenedor sea compatible con la configuración de la carpeta del host que se quiere montar. En la actualidad solo deberían ser usados para visualizar determinados directorios del host anfitrión, para todo lo demás siempre es mejor usar volúmenes.

Cuando no se usan contenedores que utilizan root para ejecutar el proceso y se quiere hacer uso de “bind mounts” o volúmenes, es común que empiecen los problemas de acceso si no se ha configurado correctamente el tema permisos. La linea de comandos de Docker, Docker-compose o cualquier otra aplicación que implemente bind mounts, no permite configurar sus permisos / propietario. Por lo que hay que apoyarse siempre en algo externo para poder configurar los puntos de montaje como se quiera. Se presentan en esta pequeña guía algunas posibilidades para adaptar el usuario del contenedor al del bind mount.

Ejemplo de montaje de volúmenes y bind mounts (directorios del host anfitrión) desde la linea de comandos usando la sintaxis “mount”.

# Se monta el volumen con el mismo UID y GID del usuario que ejecutó el comando.
docker run --mount source=volumen1,destination=/opt/volumen1 -it -u $UID:$UID alpine sh 
 
# Los bind mounts no permiten configurar el UID/GID y se montará en el contenedor con el UID/GID del anfitrión, exista o no en el contenedor.
docker run -it --mount type=bind,src=/root/,dst=/root -w /root/ alpine sh
# Siempre se puede arranca el contenedor indicando el usuario compatible con el directorio del host (bind mount) a montar.
docker run --user antonio -it --mount type=bind,src=/hme/antonio/,dst=/home/antonio -w /home/antonio/ alpine sh

Cuando se trata de volúmenes, desde la linea de comandos es simple especificar un usuario y grupo como ya vimos (Leer guía rápida de docker.), pero también sería posible hacerlo desde el Dockerfile como veremos a continuación, siendo esta la opción más recomendada al usar docker-compose.

Montar volúmenes (no bind mounts) a partir de un fichero Dockerfile

Al margen de la linea de comandos, este es posiblemente el mejor método de configurar un punto de montaje dentro del contenedor con los permisos deseados cuando se usan aplicaciones estilo docker-compose. El proceso se basa en crear una imagen mediante un fichero Dockerfile donde se define el usuario y los permisos del directorio que monta el volumen. Una vez se monte el volumen, ya sea desde la linea de comandos o docker-compose, el punto de montaje en el contenedor heredará los permisos y propietario definidos previamente en la imagen. No es necesario que el usuario exista en el host, puede perfectamente solo existir en el contenedor.

En el ejemplo se crea una imagen docker llamada “alpine_volumen” que usará un usuario no privilegiado “testuser”.

ARG USR=testuser
FROM alpine
RUN addgroup -S $USR && adduser -S $USR -G $USR           # Se crea el usuario y el grupo para luego aplicarlo al punto de montaje del volumen.
RUN mkdir /VOL_testuser && chown $USR:$USR /VOL_testuser  # Se crea el directorio donde será montado el volumen y su propietario
VOLUME /VOL_testuser                                      # Se hace una referencia al volumen que será montado desde linea de comando o docker-compose.
USER $USR                                                 # Usuario del proceso.

Montar el volumen desde docker-compose, el volumen se crea automáticamente si no existe. El contenedor creado solo ejecutará una shell.

version: "3"
services:
  web:
    image: alpine_volumen  # Imagen creada a partir del Dockerfile mostrado anteriormente.
    stdin_open: true # docker run -i
    tty: true        # docker run -t
    command: /bin/sh
    volumes:
      - XXXX:/VOL_testuser  # El volumen será montado como el usuario testuser.
volumes:
    XXXX:

También se puede montar el volumen desde la linea de comando (se creará el volumen XXXX si no existe).

docker run --rm -it -v XXXX:/VOL_testuser alpine_volumen

Montar directorios (bind mount) conociendo el usuario del contenedor y aplicándolo al directorio host

Obtener el id del usuario que corre en el contenedor.

# docker
docker exec XXXX id
uid=100(testuser) gid=101(testuser) groups=101(testuser)
 
# docker-compose
docker-compose ps --services
web
docker-compose exec web id
uid=100(testuser) gid=101(testuser) groups=101(testuser)

Una vez se conoce el usuario y grupo, se puede usar en el host el comando chown y chmod. Por supuesto el usuario debe existir en el host.

Montar directorios (bind mount) conociendo el usuario del directorio del host y aplicándolo al contenedor

Se crea un fichero .env con el usuario y grupo del directorio se sabe se va a montar en el contenedor.

UID=100
GID=101

En el fichero de docker-compose se define el usuario y grupo que debe correr el proceso para que sea compatible con el directorio montado

version: "3"
services:
  web:
    image: alpine_volumen
    user: "${UID}:${GID}"
    stdin_open: true # docker run -i
    tty: true        # docker run -t
    command: /bin/sh
    volumes:
      - /home/XXXX:/DIR_testuser

Aplicar la configuración de propietario y permisos en el ENTRYPOINT

Se aplica la configuración dentro del ENTRYPOINT. Normalmente se usará un script, pero para el ejemplo se ha usado un comando y una shell como proceso final.

version: "3"
services:
  web:
    image: alpine
    stdin_open: true # docker run -i
    tty: true        # docker run -t
    container_name: test
    volumes:
      - /home/XXXX:/DIR_testuser
    entrypoint: /bin/sh -c "adduser -D testuser && chown -Rv testuser:testuser /DIR_testuser && sh"
permisos_y_propietarios_en_volumenes_con_docker-compose.txt · Last modified: 2021/05/23 01:50 by busindre