tag run remove hub compose docker

remove - docker run



¿Cuál es la(mejor) manera de administrar los permisos para los volúmenes compartidos de Docker? (13)

He estado jugando con Docker por un tiempo y sigo encontrando el mismo problema al tratar con datos persistentes.

Creo mi Dockerfile y Dockerfile un volumen o uso --volumes-from para montar una carpeta de host dentro de mi contenedor .

¿Qué permisos debo aplicar al volumen compartido en el host?

Puedo pensar en dos opciones:

  • Hasta ahora, les he dado a todos acceso de lectura / escritura, por lo que puedo escribir en la carpeta desde el contenedor de Docker.

  • Asigne los usuarios del host al contenedor, de modo que pueda asignar más permisos granulares. Aunque 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 algún usuario: docker run -i -t -user="myuser" postgres , pero este usuario tiene un UID diferente al de mi host myuser , por lo que los permisos no funcionan. Además, no estoy seguro si el mapeo de los usuarios planteará algunos riesgos de seguridad.

¿Hay otras alternativas?

¿Cómo están manejando este asunto chicos / chicas?


Imagen base

Utilice esta imagen: https://hub.docker.com/r/reduardo7/docker-host-user

o

Importante: esto destruye la portabilidad de contenedores a través de hosts .

1) init.sh

#!/bin/bash if ! getent passwd $DOCKDEV_USER_NAME > /dev/null then echo "Creating user $DOCKDEV_USER_NAME:$DOCKDEV_GROUP_NAME" groupadd --gid $DOCKDEV_GROUP_ID -r $DOCKDEV_GROUP_NAME useradd --system --uid=$DOCKDEV_USER_ID --gid=$DOCKDEV_GROUP_ID / --home-dir /home --password $DOCKDEV_USER_NAME $DOCKDEV_USER_NAME usermod -a -G sudo $DOCKDEV_USER_NAME chown -R $DOCKDEV_USER_NAME:$DOCKDEV_GROUP_NAME /home fi sudo -u $DOCKDEV_USER_NAME bash

2) Dockerfile

FROM ubuntu:latest # Volumes VOLUME ["/home/data"] # Copy Files COPY /home/data/init.sh /home # Init RUN chmod a+x /home/init.sh

3) run.sh

#!/bin/bash DOCKDEV_VARIABLES=(/ DOCKDEV_USER_NAME=$USERNAME/ DOCKDEV_USER_ID=$UID/ DOCKDEV_GROUP_NAME=$(id -g -n $USERNAME)/ DOCKDEV_GROUP_ID=$(id -g $USERNAME)/ ) cmd="docker run" if [ ! -z "${DOCKDEV_VARIABLES}" ]; then for v in ${DOCKDEV_VARIABLES[@]}; do cmd="${cmd} -e ${v}" done fi # /home/usr/data contains init.sh $cmd -v /home/usr/data:/home/data -i -t my-image /home/init.sh

4) Construir con docker

4) ¡Corre!

sh run.sh


Al igual que usted, estaba buscando una forma de asignar usuarios / grupos desde el host a los contenedores de la ventana acoplable y esta es la forma más corta que he encontrado hasta ahora:

version: "3" services: my-service: ..... volumes: # take uid/gid lists from host - /etc/passwd:/etc/passwd:ro - /etc/group:/etc/group:ro # mount config folder - path-to-my-configs/my-service:/etc/my-service:ro .....

Este es un extracto de mi docker-compose.yml.

La idea es montar (en modo de solo lectura) las listas de usuarios / grupos desde el host al contenedor, por lo tanto, una vez que el contenedor se inicie, tendrá las mismas coincidencias de uid-> username (así como para grupos) con el host. Ahora puede configurar las configuraciones de usuario / grupo para su servicio dentro del contenedor como si estuviera trabajando 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 de servicio a lo que tiene en ese host.


En mi caso específico, intentaba compilar mi paquete de nodos con la imagen de la ventana acoplable 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 nodo docker, al que 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 el equipo host. A través de documentos docker ...

Los archivos copiados a la máquina local se crean con el UID: GID del usuario que invocó el comando docker cp.

Este es el código bash que utilicé para cambiar la propiedad del directorio creado por y dentro del contenedor docker.

NODE_IMAGE=node_builder docker run -v $(pwd)/build:/build -w="/build" --name $NODE_IMAGE node:6-slim npm i --production # node_modules is owned by root, so we need to copy it out docker cp $NODE_IMAGE:/build/node_modules build/lambda # you might have issues trying to remove the directory "node_modules" within the shared volume "build", because it is owned by root, so remove the image and its volumes docker rm -vf $NODE_IMAGE || true

Si es necesario, puede eliminar el directorio con un segundo contenedor de ventana acoplable.

docker run -v $(pwd)/build:/build -w="/build" --name $RMR_IMAGE node:6-slim rm -r node_modules


Este es un enfoque que aún utiliza un contenedor de datos solamente pero no requiere que esté sincronizado 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 USUARIO no root $ sin un shell de inicio de sesión.

En el Dockerfile:

RUN useradd -s /bin/false myuser # Set environment variables ENV VOLUME_ROOT /data ENV USER myuser ... ENTRYPOINT ["./entrypoint.sh"]

Luego, en entrypoint.sh:

chown -R $USER:$USER $VOLUME_ROOT su -s /bin/bash - $USER -c "cd $repo/build; $@"



Mi enfoque es detectar el UID / GID actual y luego crear dicho usuario / grupo dentro del contenedor y ejecutar el script debajo de él, de modo que todos los archivos que creará coincidirán con el usuario que ejecuta el script:

# get location of this script no matter what your current folder is, this might break between shells so make sure you run bash LOCAL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # get current IDs USER_ID=$(id -u) GROUP_ID=$(id -g) echo "Mount $LOCAL_DIR into docker, and match the host IDs ($USER_ID:$GROUP_ID) inside the container." docker run -v $LOCAL_DIR:/host_mount -i debian:9.4-slim bash -c "set -euo pipefail && groupadd -r -g $GROUP_ID lowprivgroup && useradd -u $USER_ID lowprivuser -g $GROUP_ID && cd /host_mount && su -c ./runMyScriptAsRegularUser.sh lowprivuser"


Ok, esto ahora se está rastreando en el problema # 7198

Por ahora, estoy lidiando con esto usando tu segunda opción:

Mapear los usuarios del host en el contenedor

Dockerfile

#======= # Users #======= # TODO: Idk how to fix hardcoding uid & gid, specifics to docker host machine RUN (adduser --system --uid=1000 --gid=1000 / --home /home/myguestuser --shell /bin/bash myguestuser)

CLI

# DIR_HOST and DIR_GUEST belongs to uid:gid 1000:1000 docker run -d -v ${DIR_HOST}:${DIR_GUEST} elgalu/myservice:latest

ACTUALIZACIÓN Actualmente estoy más inclinado a la answer Hamy


Para asegurar y cambiar la raíz del contenedor de la --uidmap acoplable, un host de la --uidmap acoplable intente usar --uidmap y --private-uids

https://github.com/docker/docker/pull/4572#issuecomment-38400893

También puede eliminar varias capacidades ( --cap-drop ) en el contenedor de la --cap-drop acoplable para mayor seguridad

http://opensource.com/business/14/9/security-for-docker

El soporte de ACTUALIZACIÓN debería venir en la docker > 1.7.0

ACTUALIZACIÓN Versión 1.10.0 (2016-02-04) agregue --userns-remap flag https://github.com/docker/docker/blob/master/CHANGELOG.md#security-2


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.

  1. Bind mount host volumen

    Host folder FOOBAR is mounted in container /volume/FOOBAR

  2. Modifique el script de inicio de su contenedor para encontrar el GID del volumen que le interesa

    $ TARGET_GID=$(stat -c "%g" /volume/FOOBAR)

  3. Asegúrese de que su usuario pertenezca a un grupo con este GID (es posible que tenga que crear un nuevo grupo). Para este ejemplo, pretendo que mi software se ejecuta como el usuario nobody cuando está dentro del contenedor, por lo que quiero asegurarme de que nobody pertenece a un grupo con una ID de grupo igual a TARGET_GID

EXISTS=$(cat /etc/group | grep $TARGET_GID | wc -l) # Create new group using target GID and add nobody user if [ $EXISTS == "0" ]; then groupadd -g $TARGET_GID tempgroup usermod -a -G tempgroup nobody else # GID exists, find group name and add GROUP=$(getent group $TARGET_GID | cut -d: -f1) usermod -a -G $GROUP nobody fi

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 de la ventana acoplable. Esto sucede sin ningún permiso o modificación de propiedad en mis carpetas / archivos del host, lo que me hace feliz.

No me gusta esto porque asume que no hay peligro de agregarse a un grupo arbitrario dentro del contenedor que está utilizando un GID que usted desea. No se puede utilizar con una cláusula USER en un Dockerfile (a menos que ese usuario tenga privilegios de root, supongo). Además, grita hackear trabajo ;-)

Si quiere ser un hardcore, obviamente puede extender esto de muchas maneras, por ejemplo, busque todos los grupos en cualquier subarchivo, volúmenes múltiples, etc.


Se puede ver una solución muy elegante en la imagen redis oficial y, en general, en todas las imágenes oficiales.

Descrito en el proceso paso a paso:

  • Crea redis usuario / grupo antes que nada

Como se ve en los comentarios de Dockerfile:

agregue nuestro usuario y grupo primero para asegurarse de que sus ID se asignen de manera consistente, independientemente de las dependencias que se agreguen

  • Instalar gosu con Dockerfile

gosu es una alternativa de su / sudo para una fácil reducción del usuario root. (Redis siempre se ejecuta con redis usuario)

  • Configurar /data volumen de /data y configurarlo como direccion de trabajo

Al configurar el volumen de / data con el comando VOLUME /data ahora tenemos un volumen separado que puede ser un volumen acoplable o montado en enlace a un directorio de host.

Configurarlo como el directorio de trabajo ( WORKDIR /data ) lo convierte en el directorio predeterminado desde donde se ejecutan los comandos.

  • Agregue el archivo Docker-entrypoint y configúrelo como ENTRYPOINT con el servidor redis CMD predeterminado

Esto significa que todas las ejecuciones de contenedores se ejecutarán a través del script docker-entrypoint y, de forma predeterminada, el comando que se ejecutará es redis-server.

docker-entrypoint es una secuencia de comandos que realiza una función simple: cambiar la propiedad del directorio actual (/ data) y bajar de la root al usuario redis para ejecutar redis-server . (Si el comando ejecutado no es redis-server, ejecutará el comando directamente).

Esto tiene el siguiente efecto.

Si el directorio / data está enlazado al host, el docker-entrypoint preparará los permisos de usuario antes de ejecutar redis-server bajo redis user.

Esto le brinda la tranquilidad de que no hay ninguna configuración 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.


Si utiliza Docker Compose, inicie el contenedor en modo privilegiado:

wordpress: image: wordpress:4.5.3 restart: always ports: - 8084:80 privileged: true


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, aún tiene valor en el sentido de cómo pensar acerca de los datos dentro de la ventana acoplable, pero considera el uso de volúmenes con nombre para implementar el patrón descrito 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 de solo datos . Con este enfoque, todo el acceso a los datos del volumen se realiza a través de contenedores que utilizan -volumes-from contenedor de datos, por lo que el uid / gid del host no importa.

Por ejemplo, un caso de uso dado en la documentación es la copia de seguridad de un volumen de datos. Para hacer esto, se utiliza otro contenedor para hacer la copia de seguridad a través de tar , y también utiliza -volumes-from para montar el volumen. Así que creo que el punto clave para grok es: en lugar de pensar cómo obtener acceso a los datos en el host con los permisos adecuados, piense cómo hacer lo que necesite: copias de seguridad, navegación, etc., a través de otro contenedor . Los contenedores en sí necesitan usar uid / gids consistentes, pero no necesitan mapear 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 hacer comentarios e intentaré ampliar la respuesta.

ACTUALIZACIÓN : Para el caso de uso dado en los comentarios, es posible que tenga una imagen de some/graphite para ejecutar grafito y una imagen de some/graphitedata para el contenedor de datos. Por lo tanto, ignorando los puertos y Dockerfile , el Dockerfile de image some/graphitedata es algo así como:

FROM debian:jessie # add our user and group first to make sure their IDs get assigned consistently, regardless of other deps added later RUN groupadd -r graphite / && useradd -r -g graphite graphite RUN mkdir -p /data/graphite / && chown -R graphite:graphite /data/graphite VOLUME /data/graphite USER graphite CMD ["echo", "Data container for graphite"]

Construye y crea el contenedor de datos:

docker build -t some/graphitedata Dockerfile docker run --name graphitedata some/graphitedata

El archivo Docker de some/graphite también debería tener los mismos uid / gids, por lo tanto, podría verse algo como esto:

FROM debian:jessie # add our user and group first to make sure their IDs get assigned consistently, regardless of other deps added later RUN groupadd -r graphite / && useradd -r -g graphite graphite # ... graphite installation ... VOLUME /data/graphite USER graphite CMD ["/bin/graphite"]

Y se ejecutaría de la siguiente manera:

docker run --volumes-from=graphitedata some/graphite

Bien, ahora eso nos da nuestro contenedor de grafito y el contenedor de datos asociados con el usuario / grupo correcto (tenga en cuenta que también puede reutilizar el contenedor de some/graphite para el contenedor de datos, anulando el protocolo de entrada / cmd al ejecutarlo, pero tenerlos como imágenes separadas IMO es más claro).

Ahora, digamos 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 creamos el usuario / grupo apropiado, al igual que la imagen de some/graphite .

FROM debian:jessie # add our user and group first to make sure their IDs get assigned consistently, regardless of other deps added later RUN groupadd -r graphite / && useradd -r -g graphite graphite VOLUME /data/graphite USER graphite CMD ["/bin/bash"]

Puede hacer esto SECO heredando de some/graphite o some/graphitedata en el Dockerfile, o en lugar de crear una nueva imagen, simplemente reutilice una de las existentes (sobrescribiendo entrypoint / cmd según sea necesario).

Ahora, simplemente ejecuta:

docker run -ti --rm --volumes-from=graphitedata some/graphitetools

y luego vi /data/graphite/whatever.txt . Esto funciona perfectamente porque todos los contenedores tienen el mismo usuario de grafito con el uid / gid correspondiente.

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 contenedores de graphite y graphitetools . 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 container42.com/2014/11/18/data-only-container-madness . Sin embargo, esto no es un requisito: puede usar el contenedor de datos como "referencia / manejador" y configurar la propiedad / perms en otro contenedor mediante 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.


Para compartir una carpeta entre el servidor de la ventana acoplable y el contenedor de la ventana acoplable, intente con el siguiente comando

$ docker run -v "$ (pwd): $ (pwd)" -i -t ubuntu

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í:

  1. No puede escribir en el volumen montado si no era usuario root porque el archivo compartido será propiedad de otro usuario en el host,
  2. No debe ejecutar el proceso dentro de sus contenedores como root, pero incluso si se ejecuta como un usuario codificado, no coincidirá con el usuario de su computadora portátil / Jenkins.

Solución:

Contenedor: cree un usuario diga ''testuser'', por defecto, la identificación del usuario comenzará a partir de 1000,

Anfitrión: cree un grupo, diga ''grupo de prueba'' con el ID de grupo 1000, y agregue el directorio al nuevo grupo (grupo de prueba