¿Cómo puedo agregar un volumen a un contenedor Docker existente?

297

Tengo un contenedor Docker que he creado simplemente instalando Docker en Ubuntu y haciendo:

sudo docker run -i -t ubuntu /bin/bash

Inmediatamente comencé a instalar Java y algunas otras herramientas, pasé un tiempo con él y detuve el contenedor

exit

Luego quise agregar un volumen y me di cuenta de que esto no es tan sencillo como pensé que sería. Si lo uso, sudo docker -v /somedir run ...entonces termino con un nuevo contenedor nuevo, por lo que habría instalado Java y haría lo que ya he hecho antes solo para llegar a un contenedor con un volumen montado.

Toda la documentación sobre el montaje de una carpeta desde el host parece implicar que montar un volumen es algo que se puede hacer al crear un contenedor. Entonces, la única opción que tengo para evitar reconfigurar un nuevo contenedor desde cero es enviar el contenedor existente a un repositorio y usarlo como la base de uno nuevo mientras se monta el volumen.

¿Es esta la única forma de agregar un volumen a un contenedor existente?

mahonya
fuente
1
Después de los Contenedores, estos se convirtieron en una parte integral de los Programadores y, por lo tanto, estas preguntas se publican con mayor frecuencia aquí. Las preguntas publicadas aquí usando la dockeretiqueta son 34k + , que son mucho más que esos dos sitios stackoverflow.com/questions/tagged/docker
MA Hossain Tonu

Respuestas:

394

Puede confirmar su contenedor existente (es decir, crear una nueva imagen a partir de los cambios del contenedor) y luego ejecutarlo con sus nuevas monturas.

Ejemplo:

$ docker ps  -a
CONTAINER ID        IMAGE                 COMMAND                  CREATED              STATUS                          PORTS               NAMES
    5a8f89adeead        ubuntu:14.04          "/bin/bash"              About a minute ago   Exited (0) About a minute ago                       agitated_newton

$ docker commit 5a8f89adeead newimagename

$ docker run -ti -v "$PWD/dir1":/dir1 -v "$PWD/dir2":/dir2 newimagename /bin/bash

Si todo está bien, detenga su contenedor anterior y use este nuevo.

Eso es :)

Leonardo Cuquejo
fuente
22
Y si necesita que el nuevo contenedor tome el nombre anterior por alguna razón, use docker rename después de eliminar el antiguo.
Dirk
10
solo quería señalar lo anterior donde mencionas newnameofcontainerque probablemente debería nombrarse new_image_name, porque docker commitcrea una nueva imagen en tu sistema. Luego, en lo siguiente, cuando haga una docker run, realmente usará el nombre de la imagen desde la que desea ejecutar un nuevo contenedor. Lo anterior funciona, pero solo quería aclarar a los demás que el marcador de posición newnameofcontainer anterior es en realidad el nombre de una nueva imagen. ¡Gracias! respuesta asombrosa oh, puedes ver la imagen recién creada desde el primer comando de confirmación de Docker usandodocker image ls
FireDragon
3
De hecho, no necesita confirmar un nuevo contenedor si desea comenzar desde una imagen. Solo docker run -v /srv/a:/tmp ubuntu:14.04es bueno
YongHao Hu
Ya tengo un contenedor ejecutándose con todos los archivos. Si el método anterior crea un nuevo contenedor, no puedo construir todo de nuevo. ¿Hay alguna manera de evitar esto y montar sin tener que crear un nuevo contenedor o imagen?
dhinar
¿Esto mantendrá las asignaciones de volumen anteriores del contenedor anterior o debería volver a declararlas también con el nuevo contenedor?
thebeancounter
79

No tenemos ninguna forma de agregar volumen en el contenedor en ejecución, pero para lograr este objetivo puede usar los siguientes comandos:

Copie archivos / carpetas entre un contenedor y el sistema de archivos local: -

docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-

docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH

Para referencia ver:

https://docs.docker.com/engine/reference/commandline/cp/

usuario128364
fuente
47
Hay una gran diferencia entre montar un volumen y copiar archivos desde y hacia un contenedor ...
Julio
31
De todos modos me ayudó. No conocía el comando 'docker cp' e intentaba lograr exactamente esto: copiar archivos del contenedor en ejecución al host.
Ivan
3
no es una montura, pero es útil para recuperar archivos y crear espuma entre el contenedor y el host local.
linehrr
Si bien esto resuelve el problema de replicar el contenido del contenedor localmente, esto no está cerca de ser equivalente a montar un volumen y no debe considerarse como una alternativa. A saber, la replicación debe ser administrada por el usuario, y los datos existen ahora en dos lugares.
Sebastian Gaweda
1
No entiendo por qué tantos votos positivos, esta es una respuesta muy incorrecta para la pregunta formulada.
João Matos
33

He montado correctamente la /home/<user-name>carpeta de mi host en la /mntcarpeta del contenedor existente (no en ejecución). Puedes hacerlo de la siguiente manera:

  1. Abra el archivo de configuración correspondiente al contenedor detenido, que se puede encontrar en /var/lib/docker/containers/99d...1fb/config.v2.json(puede ser config.jsonpara versiones anteriores de Docker).

  2. Encuentra MountPointssección, que estaba vacío en mi caso: "MountPoints":{}. Luego reemplace el contenido con algo como esto (puede copiar el contenido adecuado de otro contenedor con la configuración adecuada):

"MountPoints":{"/mnt":{"Source":"/home/<user-name>","Destination":"/mnt","RW":true,"Name":"","Driver":"","Type":"bind","Propagation":"rprivate","Spec":{"Type":"bind","Source":"/home/<user-name>","Target":"/mnt"},"SkipMountpointCreation":false}}

o lo mismo (formateado):

  "MountPoints": {
    "/mnt": {
      "Source": "/home/<user-name>",
      "Destination": "/mnt",
      "RW": true,
      "Name": "",
      "Driver": "",
      "Type": "bind",
      "Propagation": "rprivate",
      "Spec": {
        "Type": "bind",
        "Source": "/home/<user-name>",
        "Target": "/mnt"
      },
      "SkipMountpointCreation": false
    }
  }
  1. Reinicie el servicio acoplable: service docker restart

Esto funciona para mí con Ubuntu 18.04.1 y Docker 18.09.0

Igor Bendrup
fuente
3
Gracias por la respuesta. El paso 3 es crucial. También agregaría que es mejor detener el contenedor acoplable primero antes de escribir.
buzypi
77
Esta es la mejor respuesta, ya que conserva totalmente el contenedor existente. Esto es lo que hice: 1. Detener el motor de la ventana acoplable: systemctl stop docker.service2. Editar config.v2.json: vim <(jq . /var/lib/docker/containers/<container-ID>/config.v2.json)3. Guardar actualizaciones en un archivo: :w config.v2.json4. Salir de vim: :q!5. Actualizar el archivo existente: jq -c . config.v2.json > /var/lib/docker/containers/<container-ID>/config.v2.json6. Iniciar el motor de la ventana acoplable: systemctl start docker.service7. Iniciar el contenedor si es necesario : docker start <container-name/ID>8. Disfruta :-)
Control de Android
2
Un paso clave es service docker restart. Traté de que docker restart <container>la nueva configuración no se recoja, y la configuración anterior la sobrescribe.
KFL
1
También jqayudará a imprimir bastante el JSON para que sea más humano editable:cat config.v2.json | jq . > config.json
KFL
14

Jérôme Petazzoni tiene una publicación de blog bastante interesante sobre cómo adjuntar un volumen a un contenedor mientras se está ejecutando . Esto no es algo integrado en Docker de fábrica, pero es posible lograrlo.

Como él también señala

Esto no funcionará en sistemas de archivos que no estén basados ​​en dispositivos de bloque.

Solo funcionará si / proc / mounts enumera correctamente el nodo del dispositivo de bloque (que, como vimos anteriormente, no es necesariamente cierto).

Además, solo probé esto en mi entorno local; Ni siquiera probé una instancia en la nube o algo así

YMMV

R0MANARMY
fuente
8

Lamentablemente, la opción de cambio para montar un volumen solo se encuentra en el runcomando.

docker run --help

-v, --volume list Bind mount a volume (default [])

Sin embargo, hay una manera de evitar esto para que no tenga que reinstalar las aplicaciones que ya ha configurado en su contenedor.

  1. Exporta tu contenedor docker container export -o ./myimage.docker mycontainer
  2. Importar como imagen docker import ./myimage.docker myimage
  3. Luego docker run -i -t -v /somedir --name mycontainer myimage /bin/bash
Adel Helal
fuente
1
FYI: docker containerno es un comando válido en 1.11.2 (que es la última versión admitida por Synology a partir de este escrito). Sin embargo, no puedo encontrar ningún documento que indique cuándo se agregó. En este caso, el primer comando es docker export -o ./myimage.docker mycontainer.
Chris R. Donnelly
2

¡Una nota para usar los contenedores de Docker Windows después de que tuve que buscar este problema durante mucho tiempo!

Condiciones:

  • Windows 10
  • Docker Desktop (última versión)
  • utilizando Docker Windows Container para image microsoft / mssql-server-windows-developer

Problema:

  • Quería montar un diccionario de host en mi contenedor de Windows.

Solución como se describe aquí parcialmente:

  • crear contenedor acoplable

docker run -d -p 1433:1433 -e sa_password=<STRONG_PASSWORD> -e ACCEPT_EULA=Y microsoft/mssql-server-windows-developer

  • ir a shell de comando en contenedor

docker exec -it <CONTAINERID> cmd.exe

  • crear DIR

mkdir DirForMount

  • detener el contenedor

docker container stop <CONTAINERID>

  • confirmar contenedor

docker commit <CONTAINERID> <NEWIMAGENAME>

  • eliminar contenedor antiguo

docker container rm <CONTAINERID>

  • crear un nuevo contenedor con nueva imagen y montaje de volumen

docker run -d -p 1433:1433 -e sa_password=<STRONG_PASSWORD> -e ACCEPT_EULA=Y -v C:\DirToMount:C:\DirForMount <NEWIMAGENAME>

Después de esto, resolví este problema en los contenedores de ventanas acoplables.

droebi
fuente
-3

La mejor manera es copiar todos los archivos y carpetas dentro de un directorio en su sistema de archivos local: docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH

SRC_PATHestá en contenedor DEST_PATHestá en localhost

Luego docker-compose downadjunte un volumen al mismo DEST_PATHy ejecute contenedores Docker utilizandodocker-compose up -d

Agregue volumen siguiendo en docker-compose.yml

volumes:
 - DEST_PATH:SRC_PATH
Vatsal Mishra
fuente
Hay otras mejores opciones anteriores.
MrR
De hecho, hay mejores opciones anteriores, y copiar archivos no es montarlos. Además, la definición de "volúmenes" dada para la opción docker-compose es al revés: volúmenes: - HOST_PATH: CONTAINER_PATH
Guillaume S.