Agregue un volumen a Docker, pero excluya una subcarpeta

210

Supongo que tengo un contenedor Docker y una carpeta en mi host /hostFolder. Ahora bien, si quiero añadir esta carpeta al contenedor acoplable como un volumen, entonces yo puedo hacer esto ya sea mediante el uso ADDde la Dockerfileo de montaje como un volumen.

Hasta aquí todo bien.

Ahora /hostFoldercontiene una subcarpeta, /hostFolder/subFolder.

Quiero montar /hostFolderen el contenedor de Docker (ya sea como lectura-escritura o solo lectura no importa, funciona para mí), pero NO quiero tenerlo incluido /hostFolder/subFolder. Quiero excluir esto, y también quiero que el contenedor Docker pueda realizar cambios en esta subcarpeta, sin la consecuencia de que también haya cambiado en el host.

es posible? ¿Si es así, cómo?

Golo Roden
fuente
2
@AbhijitSarkar no es un comentario muy constructivo (ni de ninguna manera útil).
kano
1
@Kano Es un comentario, no una respuesta.
Abhijit Sarkar

Respuestas:

399

Usando docker-compose, puedo usar node_modules localmente, pero lo ignoro en el contenedor de docker usando la siguiente sintaxis en docker-compose.yml

volumes:
   - './angularApp:/opt/app'
   - /opt/app/node_modules/

Entonces, todo ./angularAppse asigna /opt/appy luego creo otro volumen de montaje /opt/app/node_modules/que ahora está vacío, incluso si mi máquina local ./angularApp/node_modulesno está vacía.

Kernix
fuente
3
Funciona pero no puedo eliminar estos /opt/app/node_modules/directorios dentro del contenedor. Por ejemplo: necesito reemplazarlo por otro directorio con el mismo nombre. Se produce un error: 'volumen ocupado'
Stepan Yudin
32
¡No olvides la barra inclinada final! p.ej. / opt / app / node_modules no funciona, será sobrescrito por ./angularApp/node_modules
Stingus
3
Este truco solía funcionar para mí, pero ya no parece, incluso para el mismo archivo de composición. Curioso si también dejó de funcionar para otros.
plinehan
8
¡Gracias! ¡Salvaste mi día! En caso de usar un acoplador simple, no compos se vería así: -v $(pwd):/build/ -v /build/node_modules
Bogdan Mart
3
Encontré el documento, docs.docker.com/storage/volumes/… . If you start a container which creates a new volume, as above, and the container has files or directories in the directory to be mounted (such as /app/ above), the directory’s contents are copied into the volume.
hiroshi
119

Si desea que Docker-compose ignore los subdirectorios pero sea persistente, puede hacer lo siguiente en docker-compose.yml:

volumes:
  node_modules:
services:
  server:
    volumes:
      - .:/app
      - node_modules:/app/node_modules

Esto montará su directorio actual como un volumen compartido, pero montará un volumen acoplable persistente en lugar de su node_modulesdirectorio local . Esto es similar a la respuesta de @kernix, pero permitirá node_modulesque persista entre docker-compose upejecuciones, lo que probablemente sea el comportamiento deseado.

Nate T
fuente
20
Los volúmenes nombrados son un enfoque superior. Protip: asegúrese de no estar usando un nombre de volumen con guión. Pasará una pequeña parte de su vida en una pesadilla de depuración, solo para descubrir que una vez más fue engañado por un matiz ridículo.
dustintheweb
3
"Tenga en cuenta que Docker-compose down matará estos volúmenes persistentes". Esto no es cierto en Docker para Mac v 17.0.5+ (y posiblemente en versiones anteriores). docker-compose downeliminará los contenedores, pero el volumen persistirá hasta que ejecute algo comodocker system prune
BrDaHa
3
En caso de que alguien esté interesado en comprender por qué el uso del node_modules:volumen con nombre "ignora" el contenido /app/node_modulesen el contenedor de la ventana acoplable, ¿puede encontrar útil esta publicación? ¿Cómo maneja Docker varios tipos de montaje?
ira
3
No sé si estoy haciendo algo mal, pero si hago esto, inicie el contenedor y luego ejecute npm install en la máquina HOST, también cambia los node_modules dentro del CONTAINER. No puedo imaginar por qué alguien querría hacer eso, pero aún así estoy buscando una separación más limpia.
Renra
3
@Renra tuvo exactamente el mismo problema, mi máquina host constantemente escribía sobre node_modules a pesar de que tenía el volumen con nombre ... causó todo tipo de problemas de incompatibilidad. Renunció a su fijación y trabajado alrededor de ella sólo por la copia de mi carpeta src en lugar de todo el repositorio
dancypants
19

Para excluir un archivo, use lo siguiente

volumes:
   - /hostFolder:/folder
   - /dev/null:/folder/fileToBeExcluded
Frank Wong
fuente
66
Solución perfecta para lo que necesitaba (NO mapear node_modules hasta el host porque el enlace simbólico se rompió en un host de Windows). Señalar a / dev / null no funcionó, pero crear un directorio en blanco y asignarlo a eso funcionó perfectamente y resolvió los problemas que tenía. Gracias por esta idea.
Liam Hammett
1
Esto no funciona en acoplable para Mac 18.09.0: Cannot start service xxx: OCI runtime create failed: container_linux.go:348: starting container process caused "process_linux.go:402: container init caused \"rootfs_linux.go:58: mounting \\\"/dev/null\\\" to rootfs \\\"/var/lib/docker/overlay2/d15ed56ad020d408c63a1f6a6365dbb88d5d3b78a4605980d3faa9861102ef21/merged\\\" at [...] unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type. Agregar una barra diagonal final no ayudó.
Blaise
Puedo confirmar que tampoco funciona en Ubuntu 16.04 con Docker 18.09.3.
Dirk
Eso no me funciona. Todo lo que hace es copiar /dev/nullen el contenedor, como un archivo de dispositivo.
Radon Rosborough
1
¡Tenga en cuenta que esto solo funciona para excluir ARCHIVOS! / dev / null es un archivo y así debe ser el objetivo, el mensaje de error es bastante claro en esto: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type. Esto no es exactamente lo que estaba buscando el OP, pero fue muy útil para mí, ya que necesitaba excluir un solo archivo.
Avius
13

Primero, usar la ADDinstrucción en un Dockerfile es muy diferente de usar un volumen (ya sea a través del -vargumento docker runo la VOLUMEinstrucción en un Dockerfile). Los comandos ADDy COPYsimplemente toman una copia de los archivos cuando docker buildse ejecuta. Estos archivos no se actualizan hasta que se crea una imagen nueva con el docker buildcomando. Por el contrario, el uso de un volumen es esencialmente decir "este directorio no debe almacenarse en la imagen del contenedor; en su lugar, use un directorio en el host"; cada vez que se cambia un archivo dentro de un volumen, tanto el host como el contenedor lo verán de inmediato.

No creo que pueda lograr lo que quiere usando volúmenes, tendrá que repensar la estructura de su directorio si desea hacer esto.

Sin embargo, es bastante simple de lograr usando COPY(que debería preferirse ADD). Puede usar un .dockerignorearchivo para excluir el subdirectorio, o puede hacer COPYtodos los archivos RUN rm blapara eliminar el subdirectorio.

Recuerde que cualquier archivo que agregue a la imagen con COPYo ADDdebe estar dentro del contexto de compilación, es decir, en o debajo del directorio desde el que se ejecuta docker build.

Adrian Mouat
fuente
1
aprenda algo nuevo todos los días :-) la COPIA y AÑADIR funcionan desde el contexto de compilación (no el host). ¿Sería posible usar un volumen para enmascarar el subcarpeta? El OP quiere montar el / hostFolder (creo), y hacer que / hostFolder / subFolder se desconecte. Si hubiera un VOLUMEN para cada uno, pero solo el hostFolder estaba 'montado' (-v), ¿eso aislaría los cambios del subFolder en el contenedor?
Greg
No estoy seguro, nunca he intentado anidar volúmenes. No estoy convencido de que sea una buena idea, pero tendría que investigarlo.
Adrian Mouat
1
Parece que no puedo encontrar un ejemplo en ningún lugar de qué poner en un .dockerignorearchivo para excluir un subdirectorio (o incluso un directorio). Dado que ese es el propósito declarado del archivo, es bastante extraño.
Lukas Oberhuber
1
una vez que agregue cualquier archivo, aún terminan en algunas capas. Por lo tanto, eliminarlos no lo ayudará a ocultarlos si es sensible a la seguridad o reducirá el tamaño de la imagen (porque estarán en las capas subyacentes). Hay opciones para squashlas capas. Uno es github.com/goldmann/docker-squash y otro está usando oc ex dockerbuildel proyecto openshift.
akostadinov
6

Parece que la solución anterior ya no funciona (al menos para mí). Sin embargo, la creación de una carpeta vacía y el mapeo de la carpeta de destino ayudó.

volumes:
   - ./angularApp:/opt/app
   - .empty:/opt/app/node_modules/
barra de espera
fuente
Tampoco funciona para mí con docker-compose 1.25.0-rc3la sintaxis de archivo v3.
thisismydesign
6

Con la línea de comando del acoplador:

docker run \
    --mount type=bind,src=/hostFolder,dst=/containerFolder \
    --mount type=volume,dst=/containerFolder/subFolder \
    ...other-args...

La -vopción también se puede utilizar (crédito a Bogdan Mart ), pero --mountes más clara y recomendada .

DS.
fuente
6

para las personas que también tuvieron el problema de que la carpeta node_modules aún se sobrescribiría de su sistema local y viceversa

volumes:
  node_modules:
services:
  server:
    volumes:
      - .:/app
      - node_modules:/app/node_modules/

Esta es la solución, con el final /después de node_modules como la solución.

Daenor
fuente
0

Para excluir un archivo montado contenido en el volumen de su máquina, deberá sobrescribirlo asignando un volumen a este mismo archivo. En su archivo de configuración:

services:
  server:
    build : ./Dockerfile
    volumes:
      - .:/app

Un ejemplo en tu dockerfile:

# Image Location
FROM node:13.12.0-buster
VOLUME /app/you_overwrite_file
Emmario Delar
fuente