He estado jugando con Docker por un tiempo y sigo encontrando el mismo problema cuando trato con datos persistentes.
Creo mi Dockerfile
y expongo un volumen o lo uso --volumes-from
para montar una carpeta de host dentro de mi contenedor .
¿Qué permisos debo aplicar al volumen compartido en el host?
Se me ocurren dos opciones:
Hasta ahora les he dado a todos acceso de lectura / escritura, para poder escribir en la carpeta desde el contenedor Docker.
Asigne los usuarios del host al contenedor, para que pueda asignar permisos más granulares. Sin embargo, no estoy seguro de que esto sea posible y no he encontrado mucho al respecto. Hasta ahora, todo lo que puedo hacer es ejecutar el contenedor como un usuario:
docker run -i -t -user="myuser" postgres
pero este usuario tiene un UID diferente que mi hostmyuser
, por lo que los permisos no funcionan. Además, no estoy seguro si mapear a los usuarios planteará algunos riesgos de seguridad.
¿Hay otras alternativas?
¿Cómo están ustedes / chicas lidiando con este problema?
Respuestas:
ACTUALIZACIÓN 2016-03-02 : A partir de Docker 1.9.0, Docker ha nombrado volúmenes que reemplazan los contenedores de solo datos . La respuesta a continuación, así como mi publicación de blog vinculada, todavía tiene valor en el sentido de cómo pensar sobre los datos dentro de la ventana acoplable, pero considere usar volúmenes con nombre para implementar el patrón que se describe a continuación en lugar de los contenedores de datos.
Creo que la forma canónica de resolver esto es mediante el uso de contenedores solo de datos . Con este enfoque, todo el acceso a los datos del volumen es a través de contenedores que usan
-volumes-from
el contenedor de datos, por lo que el host uid / gid no importa.Por ejemplo, un caso de uso dado en la documentación es hacer una copia de seguridad de un volumen de datos. Para hacer esto, se usa otro contenedor para hacer la copia de seguridad a través
tar
, y también se usa-volumes-from
para montar el volumen. Entonces, creo que el punto clave para asimilar es: en lugar de pensar en cómo obtener acceso a los datos en el host con los permisos adecuados, piense en cómo hacer lo que necesite: copias de seguridad, navegación, etc., a través de otro contenedor . Los contenedores en sí mismos necesitan usar uid / gids consistentes, pero no necesitan mapearse a nada en el host, por lo que permanecen portátiles.Esto también es relativamente nuevo para mí, pero si tiene un caso de uso en particular, no dude en comentar y trataré de ampliar la respuesta.
ACTUALIZACIÓN : para el caso de uso dado en los comentarios, es posible que tenga una imagen
some/graphite
para ejecutar grafito y una imagensome/graphitedata
como contenedor de datos. Entonces, ignorando los puertos y demás, laDockerfile
imagensome/graphitedata
es algo así como:Construye y crea el contenedor de datos:
El
some/graphite
Dockerfile también debería obtener los mismos uid / gids, por lo tanto, podría verse así:Y se ejecutaría de la siguiente manera:
Ok, ahora eso nos da nuestro contenedor de grafito y el contenedor de solo datos asociados con el usuario / grupo correcto (tenga en cuenta que también puede reutilizar el
some/graphite
contenedor para el contenedor de datos, anulando el entradapoing / cmd cuando lo ejecute, pero tenerlos como imágenes separadas IMO es más claro).Ahora, supongamos que desea editar algo en la carpeta de datos. Entonces, en lugar de vincular el montaje del volumen al host y editarlo allí, cree un nuevo contenedor para hacer ese trabajo. Vamos a llamarlo
some/graphitetools
. También creemos el usuario / grupo apropiado, al igual que lasome/graphite
imagen.Puede hacer esto SECO heredando de
some/graphite
osome/graphitedata
en el Dockerfile, o en lugar de crear una nueva imagen, simplemente reutilice una de las existentes (anulando el punto de entrada / cmd según sea necesario).Ahora, simplemente ejecutas:
y luego
vi /data/graphite/whatever.txt
. Esto funciona perfectamente porque todos los contenedores tienen el mismo usuario de grafito con uid / gid coincidentes.Como nunca monta
/data/graphite
desde el host, no le importa cómo el uid / gid del host se asigna al uid / gid definido dentro de los contenedoresgraphite
ygraphitetools
. Esos contenedores ahora se pueden implementar en cualquier host y continuarán funcionando perfectamente.Lo bueno de esto es que
graphitetools
podría tener todo tipo de utilidades y scripts útiles, que ahora también puede implementar de manera portátil.ACTUALIZACIÓN 2 : Después de escribir esta respuesta, decidí escribir una publicación de blog más completa sobre este enfoque. Espero que ayude.
ACTUALIZACIÓN 3 : Corrigí esta respuesta y agregué más detalles. Anteriormente contenía algunas suposiciones incorrectas sobre la propiedad y los permisos: la propiedad generalmente se asigna en el momento de la creación del volumen, es decir, en el contenedor de datos, porque es cuando se crea el volumen. Ver este blog . Sin embargo, esto no es un requisito: puede usar el contenedor de datos como "referencia / identificador" y establecer la propiedad / permisos en otro contenedor a través de chown en un punto de entrada, que termina con gosu para ejecutar el comando como el usuario correcto. Si alguien está interesado en este enfoque, comente y puedo proporcionar enlaces a una muestra utilizando este enfoque.
fuente
/data/newcontainer
? Supongo que se ejecutadocker
como root (¿es posible no hacerlo?) Además, ¿hay alguna diferencia en esos permisos si los datos se montan directamente en el contenedor principal o mediante un contenedor de solo datos ?/var/lib/docker
algún lugar pero aún serán un gran dolorSe puede ver una solución muy elegante en la imagen oficial de redis y, en general, en todas las imágenes oficiales.
Descrito en el proceso paso a paso:
Como se ve en los comentarios de Dockerfile:
Gosu es una alternativa de
su
/sudo
para bajar fácilmente del usuario root. (Redis siempre se ejecuta con elredis
usuario)/data
volumen y configúrelo como workdirAl configurar el volumen de datos / con el
VOLUME /data
comando ahora tenemos un volumen separado que puede ser un volumen acoplable o montado en un directorio host.Configurarlo como workdir (
WORKDIR /data
) lo convierte en el directorio predeterminado desde donde se ejecutan los comandos.Esto significa que todas las ejecuciones de contenedores se ejecutarán a través de la secuencia de comandos docker-entrypoint y, de forma predeterminada, el comando que se ejecutará es redis-server.
docker-entrypoint
es un script que realiza una función simple: cambiar la propiedad del directorio actual (/ datos) y descender deroot
unredis
usuario a otro para ejecutarloredis-server
. (Si el comando ejecutado no es redis-server, ejecutará el comando directamente).Esto tiene el siguiente efecto
Si el directorio / data está montado en enlace al host, el punto de entrada de docker preparará los permisos de usuario antes de ejecutar redis-server bajo
redis
user.Esto le da la tranquilidad de que hay una configuración cero para ejecutar el contenedor en cualquier configuración de volumen.
Por supuesto, si necesita compartir el volumen entre diferentes imágenes, debe asegurarse de que usen el mismo ID de usuario / ID de grupo; de lo contrario, el último contenedor secuestrará los permisos de usuario del anterior.
fuente
chown
Es dentro delENTRYPOINT
guión?Podría decirse que esta no es la mejor manera para la mayoría de las circunstancias, pero aún no se ha mencionado, por lo que quizás ayude a alguien.
Volumen de host de montaje de enlace
Host folder FOOBAR is mounted in container /volume/FOOBAR
Modifique el script de inicio de su contenedor para encontrar el GID del volumen que le interesa
$ TARGET_GID=$(stat -c "%g" /volume/FOOBAR)
Asegúrese de que su usuario pertenezca a un grupo con este GID (puede que tenga que crear un nuevo grupo). Para este ejemplo, fingiré que mi software se ejecuta como el
nobody
usuario cuando está dentro del contenedor, por lo que quiero asegurarme de quenobody
pertenece a un grupo con una identificación de grupo igual aTARGET_GID
Me gusta esto porque puedo modificar fácilmente los permisos de grupo en mis volúmenes de host y sé que esos permisos actualizados se aplican dentro del contenedor acoplable. Esto sucede sin ningún permiso o modificaciones de propiedad de mis carpetas / archivos de host, lo que me hace feliz.
No me gusta esto porque supone que no hay peligro en agregarse a un grupo arbitrario dentro del contenedor que está usando un GID que desea. No se puede usar con una
USER
cláusula en un Dockerfile (a menos que ese usuario tenga privilegios de root, supongo). Además, grita trabajo de pirateo ;-)Si quiere ser hardcore, obviamente puede extender esto de muchas maneras, por ejemplo, buscar todos los grupos en cualquier subarchivo, múltiples volúmenes, etc.
fuente
$TARGET_GID
sería mejor usar grepgrep ':$TARGET_GID:'
, de lo contrario, si el contenedor tiene, por ejemplo, gid 10001 y su host es 1000, esta verificación pasará pero no debería.Ok, esto ahora está siendo rastreado en el docker número 7198
Por ahora, estoy lidiando con esto usando su segunda opción:
Dockerfile
CLI
ACTUALIZACIÓN Actualmente estoy más inclinado a responder Hamy
fuente
id -u <username>
,id -g <username>
,id -G <username>
para obtener el ID de usuario y grupo de un usuario específico en lugarIntenta agregar un comando a Dockerfile
los créditos van a https://github.com/denderello/symfony-docker-example/issues/2#issuecomment-94387272
fuente
Al igual que usted, estaba buscando una forma de asignar usuarios / grupos desde el host a los contenedores acoplables y esta es la forma más corta que he encontrado hasta ahora:
Este es un extracto de mi docker-compose.yml.
La idea es montar (en modo de solo lectura) listas de usuarios / grupos desde el host al contenedor, por lo tanto, después de que el contenedor se inicie, tendrá las mismas coincidencias uid-> username (así como para grupos) con el host. Ahora puede configurar los ajustes de usuario / grupo para su servicio dentro del contenedor como si estuviera funcionando en su sistema host.
Cuando decide mover su contenedor a otro host, solo necesita cambiar el nombre de usuario en el archivo de configuración del servicio a lo que tiene en ese host.
fuente
-u $( id -u $USER ):$( id -g $USER )
y ya no tienes que preocuparte por el nombre de usuario. Esto funciona bien para entornos de desarrollo local donde desea generar archivos (binarios, por ejemplo) a los que tiene acceso de lectura / escritura de forma predeterminada.Aquí hay un enfoque que todavía usa un contenedor de solo datos pero no requiere que se sincronice con el contenedor de la aplicación (en términos de tener el mismo uid / gid).
Presumiblemente, desea ejecutar alguna aplicación en el contenedor como un $ USER no root sin un shell de inicio de sesión.
En el Dockerfile:
Luego, en entrypoint.sh:
fuente
Para la raíz y el cambio seguro para el envase de una ventana acoplable anfitrión intento utilización ventana acoplable
--uidmap
y--private-uids
opcioneshttps://github.com/docker/docker/pull/4572#issuecomment-38400893
También puede eliminar varias capacidades (
--cap-drop
) en el contenedor docker por seguridadhttp://opensource.com/business/14/9/security-for-docker
El soporte de ACTUALIZACIÓN debería venir
docker > 1.7.0
Versión ACTUALIZADA
1.10.0
(2016-02-04) agregar--userns-remap
bandera https://github.com/docker/docker/blob/master/CHANGELOG.md#security-2fuente
--uidmap
ni las--private-uids
opciones. Parece que el RP no lo logró y no se fusionó."We apparently do have so some of conflicting designs between libnetwork and user namespaces ... and something we'd like to get in for 1.8.0. So don't think we're dropping this, we're definitely going to take a break after all these, and see how we need to reconsider the current design and integration of libnetwork to make this possible. Thanks!"
github.com/docker/docker/pull/12648 Así que creo que deberíamos esperar la próxima versión estable.Mi enfoque es detectar el UID / GID actual, luego crear dicho usuario / grupo dentro del contenedor y ejecutar el script debajo de él. Como resultado, todos los archivos que creará coincidirán con el usuario en el host (que es el script):
fuente
Imagen base
Utilice esta imagen: https://hub.docker.com/r/reduardo7/docker-host-user
o
Importante: esto destruye la portabilidad del contenedor entre los hosts .
1)
init.sh
2)
Dockerfile
3) run.sh
4) Construir con
docker
4) ¡Corre!
fuente
En mi caso específico, estaba tratando de construir mi paquete de nodos con la imagen del acoplador de nodos para no tener que instalar npm en el servidor de implementación. Funcionó bien hasta que, fuera del contenedor y en la máquina host, intenté mover un archivo al directorio node_modules que había creado la imagen del acoplador de nodo, para lo cual se me negaron los permisos porque era propiedad de root. Me di cuenta de que podía solucionar esto copiando el directorio del contenedor en la máquina host. A través de docker docs ...
Este es el código bash que utilicé para cambiar la propiedad del directorio creado por y dentro del contenedor acoplable.
Si es necesario, puede eliminar el directorio con un segundo contenedor acoplable.
fuente
Para compartir la carpeta entre el host de Docker y el contenedor de Docker, pruebe el siguiente comando
El indicador -v monta el directorio de trabajo actual en el contenedor. Cuando el directorio de host de un volumen montado en enlace no existe, Docker creará automáticamente este directorio en el host para usted,
Sin embargo, hay 2 problemas que tenemos aquí:
Solución:
Contenedor: cree un usuario que diga 'testuser', por defecto la identificación del usuario comenzará desde 1000,
Anfitrión: cree un grupo que diga 'testgroup' con la identificación de grupo 1000 y asigne el directorio al nuevo grupo (testgroup
fuente
Si usa Docker Compose, inicie el contenedor en modo anterior:
fuente