hub - docker ubuntu
Docker y--userns-remap, ¿cómo administrar los permisos de volumen para compartir datos entre el host y el contenedor? (3)
En Docker, los archivos creados dentro de los contenedores tienden a tener una propiedad impredecible al inspeccionarlos desde el host. El propietario de los archivos en un volumen es root (uid 0) de forma predeterminada, pero tan pronto como las cuentas de usuario no root están involucradas en el contenedor y escriben en el sistema de archivos, los propietarios se vuelven más o menos aleatorios desde la perspectiva del host.
Es un problema cuando necesita acceder a datos de volumen desde el host utilizando la misma cuenta de usuario que está llamando a los comandos del acoplador.
Las soluciones típicas son
- Obligar a los usuarios de UID en el momento de la creación en Dockerfiles (no portátil)
-
pasar el UID del usuario host al comando
docker run
como una variable de entorno y luego ejecutar algunos comandoschown
en los volúmenes en un script de punto de entrada.
Ambas soluciones pueden dar cierto control sobre los permisos reales fuera del contenedor.
Esperaba que los espacios de nombres de usuario fueran la solución final a este problema. He realizado algunas pruebas con la versión 1.10 recientemente lanzada y --userns-remap configurada en mi cuenta de escritorio. Sin embargo, no estoy seguro de que pueda facilitar el manejo de la propiedad de archivos en volúmenes montados, me temo que podría ser todo lo contrario.
Supongamos que comienzo este contenedor básico
docker run -ti -v /data debian:jessie /bin/bash
echo ''hello'' > /data/test.txt
exit
Y luego inspeccione el contenido del host:
ls -lh /var/lib/docker/100000.100000/volumes/<some-id>/_data/
-rw-r--r-- 1 100000 100000 6 Feb 8 19:43 test.txt
Este número ''100000'' es un sub-UID de mi usuario host, pero como no corresponde al UID de mi usuario, todavía no puedo editar test.txt sin privilegios. Este subusuario no parece tener ninguna afinidad con mi usuario habitual fuera de Docker. No está mapeado de vuelta.
Las soluciones mencionadas anteriormente en esta publicación, que consistían en alinear los UID entre el host y el contenedor, ya no funcionan debido a la
UID->sub-UID
que ocurre en el espacio de nombres.
Entonces, ¿hay alguna manera de ejecutar Docker con el espacio de nombres de usuario habilitado (para mejorar la seguridad), y al mismo tiempo hacer posible que el usuario host que ejecuta Docker sea el propietario de los archivos generados en los volúmenes?
Puede evitar problemas de permisos utilizando el
comando
docker cp
.
La propiedad se establece para el usuario y el grupo primario en el destino. Por ejemplo, los archivos copiados en un contenedor se crean con
UID:GID
del usuario raíz. Los archivos copiados en la máquina local se crean con elUID:GID
del usuario que invocó el comandodocker cp
.
Aquí está su ejemplo cambiado para usar
docker cp
:
$ docker run -ti -v /data debian:jessie /bin/bash
root@e33bb735a70f:/# echo ''hello'' > /data/test.txt
root@e33bb735a70f:/# 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
$
Sin embargo, si solo desea leer archivos de un contenedor, no necesita el volumen con nombre. Este ejemplo utiliza un contenedor con nombre en lugar de un volumen con nombre:
$ docker run -ti --name sandbox1 debian:jessie /bin/bash
root@93d098233cf3:/# echo ''howdy'' > /tmp/test.txt
root@93d098233cf3:/# 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
$
Encuentro que los volúmenes con nombre son útiles cuando quiero copiar archivos en un contenedor, como se describe en esta pregunta .
Si puede preorganizar a los usuarios y grupos de antemano, entonces es posible asignar UID y GID de manera específica para que los usuarios host se correspondan con los usuarios con espacios de nombres dentro de los contenedores.
Aquí hay un ejemplo (Ubuntu 14.04, Docker 1.10):
-
Cree algunos usuarios con ID numéricos fijos:
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
-
Edite manualmente los rangos de ID subordinados generados automáticamente en los archivos
/etc/subuid
y/etc/subgid
:ns1:500000:65536
(tenga en cuenta que no hay registros para
ns1-root
yns1-user1
debido a los límitesMAX_UID
yMAX_GID
en/etc/login.defs
) -
Habilite los espacios de nombres de usuario en
/etc/default/docker
:DOCKER_OPTS="--userns-remap=ns1"
Reinicie el
service docker restart
/var/lib/docker/500000.500000
service docker restart
daemon, asegúrese de que se/var/lib/docker/500000.500000
creado el directorio/var/lib/docker/500000.500000
.Ahora, dentro de los contenedores tiene
root
yuser1
, y en el host -ns1-root
yns1-user1
, con ID coincidentesACTUALIZACIÓN: para garantizar que los usuarios no root tengan ID fijos en los contenedores (por ejemplo, user1 1000: 1000), créelos explícitamente durante la creación de la imagen.
Prueba de conducción:
-
Prepare un directorio de volúmenes
mkdir /vol1 chown ns1-root:ns1-root /vol1
-
Pruébalo desde un contenedor
docker run --rm -ti -v /vol1:/vol1 busybox sh echo "Hello from container" > /vol1/file exit
-
Probar desde el anfitrión
passwd ns1-root login ns1-root cat /vol1/file echo "can write" >> /vol1/file
No es portátil y parece un truco, pero funciona.
Una solución alternativa es asignar dinámicamente el uid del usuario en el tiempo de compilación para que coincida con el host.
Dockerfile
ejemplo:
FROM ubuntu
# Defines argument which can be passed during build time.
ARG UID=1000
# Create a user with given UID.
RUN useradd -d /home/ubuntu -ms /bin/bash -g root -G sudo -u $UID ubuntu
# Switch to ubuntu user by default.
USER ubuntu
# Check the current uid of the user.
RUN id
# ...
Luego construir como:
docker build --build-arg UID=$UID -t mycontainer .
y correr como:
docker run mycontainer
Si tiene un contenedor existente, cree un contenedor contenedor con el siguiente
Dockerfile
:
FROM someexistingcontainer
ARG UID=1000
USER root
# This assumes you''ve the existing user ubuntu.
RUN usermod -u $UID ubuntu
USER ubuntu
Esto se puede envolver en
docker-compose.yml
como:
version: ''3.4''
services:
myservice:
command: id
image: myservice
build:
context: .
volumes:
- /data:/data:rw
Luego compila y ejecuta como:
docker-compose build --build-arg UID=$UID myservice; docker-compose run myservice