Ajouter un volume à Docker, mais exclure un sous-dossier

210

Supposons que j'ai un conteneur Docker et un dossier sur mon hôte /hostFolder. Maintenant, si je veux ajouter ce dossier au conteneur Docker en tant que volume, je peux le faire en l'utilisant ADDdans Dockerfileou en le montant en tant que volume.

Jusqu'ici tout va bien.

Maintenant , /hostFoldercontient un sous-dossier, /hostFolder/subFolder.

Je veux monter /hostFolderdans le conteneur Docker (que ce soit en lecture-écriture ou en lecture seule n'a pas d'importance, fonctionne à la fois pour moi), mais je ne veux PAS l' inclure /hostFolder/subFolder. Je veux exclure cela, et je veux aussi que le conteneur Docker puisse apporter des modifications à ce sous-dossier, sans la conséquence de l'avoir également changé sur l'hôte.

Est-ce possible? Si c'est le cas, comment?

Golo Roden
la source
2
@AbhijitSarkar ce n'est pas un commentaire très constructif (ni d'aucune façon utile).
kano
1
@Kano C'est un commentaire, pas une réponse.
Abhijit Sarkar

Réponses:

399

En utilisant docker-compose, je peux utiliser node_modules localement, mais l'ignorer dans le conteneur docker en utilisant la syntaxe suivante dans le docker-compose.yml

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

Donc, tout ./angularAppest mappé /opt/appet ensuite je crée un autre volume de montage /opt/app/node_modules/qui est maintenant un répertoire vide - même si dans ma machine locale ./angularApp/node_modulesn'est pas vide.

kernix
la source
3
Cela fonctionne mais je ne peux pas supprimer ces répertoires à l'intérieur du conteneur Par exemple: j'ai besoin de remplacer /opt/app/node_modules/par un autre répertoire du même nom. Une erreur se produit: «volume occupé»
Stepan Yudin
32
N'oubliez pas la barre oblique de fin! par exemple. / opt / app / node_modules ne fonctionne pas, il sera remplacé par ./angularApp/node_modules
Stingus
3
Cette astuce fonctionnait pour moi, mais ne semble plus, même pour le même fichier Compose. Curieux de savoir s'il a également cessé de travailler pour les autres.
plinehan
8
Merci! Tu m'as sauvé la journée! En cas d'utilisation de docker simple, pas de composition, cela ressemblerait à: -v $(pwd):/build/ -v /build/node_modules
Bogdan Mart
3
J'ai trouvé le document, 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 vous souhaitez que les sous-répertoires soient ignorés par docker-compose mais persistants, vous pouvez effectuer les opérations suivantes dans docker-compose.yml:

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

Cela montera votre répertoire actuel en tant que volume partagé, mais montera un volume docker persistant à la place de votre node_modulesrépertoire local . Ceci est similaire à la réponse de @kernix, mais cela permettra node_modulesde persister entre les docker-compose upexécutions, ce qui est probablement le comportement souhaité.

Nate T
la source
20
Les volumes nommés sont une approche supérieure. Protip: assurez-vous que vous n'utilisez pas de nom de volume avec trait d'union. Vous passerez une petite partie de votre vie dans un cauchemar de débogage, seulement pour découvrir que vous avez encore une fois été trompé par une nuance ridicule.
dustintheweb
3
"Notez que le docker-compose down va tuer ces volumes persistants." Ce n'est pas vrai dans Docker pour Mac v 17.0.5+ (et peut-être des versions plus anciennes). docker-compose downsupprimera les conteneurs, mais le volume persistera jusqu'à ce que vous docker system prune
exécutiez
3
Dans le cas où quelqu'un est intéressé à comprendre pourquoi l' utilisation du node_modules:volume nommé "ignore" le /app/node_modulesdans le conteneur Docker, peut trouver ce post utile Comment Docker gère-t-il plusieurs types de montage?
ira
3
Je ne sais pas si je fais quelque chose de mal, mais si je le fais, démarrez le conteneur puis exécutez npm install sur la machine HOST, cela modifie également les node_modules à l'intérieur du CONTENEUR. Je ne peux pas imaginer pourquoi quelqu'un voudrait faire ça, mais je cherche toujours une séparation plus propre.
Renra
3
@Renra avait exactement le même problème, ma machine hôte écrivait constamment sur node_modules même si j'avais le volume nommé ... provoquait toutes sortes de problèmes d'incompatibilité. A renoncé à le réparer et à le contourner en copiant uniquement mon dossier src au lieu du repo entier
dancypants
19

Pour exclure un fichier, utilisez ce qui suit

volumes:
   - /hostFolder:/folder
   - /dev/null:/folder/fileToBeExcluded
Frank Wong
la source
6
Solution parfaite pour ce dont j'avais besoin (pour ne PAS mapper node_modules à l'hôte parce que des choses de lien symbolique se sont brisées sur un hôte Windows). Pointer vers / dev / null n'a pas fonctionné, mais créer un répertoire vierge et le mapper à celui-ci a parfaitement fonctionné et résolu les problèmes que j'avais - merci pour cette idée.
Liam Hammett
1
Cela ne fonctionne pas dans Docker pour 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. L'ajout d'une barre oblique de fin n'a pas aidé.
Blaise
Je peux confirmer que cela ne fonctionne pas non plus sur Ubuntu 16.04 avec Docker 18.09.3.
Dirk
Ça ne marche pas pour moi. Il ne fait que copier /dev/nulldans le conteneur, en tant que fichier de périphérique.
Radon Rosborough
1
Veuillez noter que cela ne fonctionne que pour exclure les FICHIERS! / dev / null est un fichier et doit donc être la cible, le message d'erreur est tout à fait clair sur ce point : 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. Ce n'est pas exactement ce que l'OP recherchait, mais cela m'a été très utile, car j'avais besoin d'exclure un seul fichier.
Avius
13

Tout d'abord, l'utilisation de l' ADDinstruction dans un Dockerfile est très différente de l'utilisation d'un volume (soit via l' -vargument to, docker runsoit dans l' VOLUMEinstruction dans un Dockerfile). Les commandes ADDet COPYprennent simplement une copie des fichiers au moment de l' docker buildexécution. Ces fichiers ne sont pas mis à jour tant qu'une nouvelle image n'est pas créée avec la docker buildcommande. En revanche, l'utilisation d'un volume signifie essentiellement "ce répertoire ne doit pas être stocké dans l'image du conteneur; utilisez plutôt un répertoire sur l'hôte"; chaque fois qu'un fichier à l'intérieur d'un volume est modifié, l'hôte et le conteneur le verront immédiatement.

Je ne crois pas que vous puissiez obtenir ce que vous voulez en utilisant des volumes, vous devrez repenser la structure de votre répertoire si vous voulez le faire.

Cependant, c'est assez simple à réaliser en utilisant COPY(ce qui devrait être préféré ADD). Vous pouvez soit utiliser un .dockerignorefichier pour exclure le sous-répertoire, soit vous pouvez COPYtous les fichiers puis faire un RUN rm blapour supprimer le sous-répertoire.

N'oubliez pas que tous les fichiers que vous ajoutez à l'image avec COPYou ADDdoivent se trouver dans le contexte de construction, c'est-à-dire dans ou sous le répertoire à docker buildpartir duquel vous exécutez .

Adrian Mouat
la source
1
apprendre quelque chose de nouveau chaque jour :-) le travail COPY et ADD à partir du contexte de construction (pas l'hôte). Serait-il possible d'utiliser un volume pour masquer le sous-dossier? L'OP veut monter le / hostFolder (je pense), et faire / hostFolder / subFolder déconnecté. S'il y avait un VOLUME pour chacun, mais que seul le hostFolder était 'monté' (-v), cela isolerait-il les modifications du sous-dossier dans le conteneur?
Greg
Je ne suis pas sûr, je n'ai jamais essayé d'imbriquer des volumes. Je ne suis pas convaincu que ce soit une bonne idée, mais je devrais y réfléchir.
Adrian Mouat
1
Je n'arrive pas à trouver un exemple n'importe où de quoi mettre dans un .dockerignorefichier pour exclure un sous-répertoire (ou même un répertoire). Étant donné que c'est l'objectif déclaré du fichier, c'est assez étrange.
Lukas Oberhuber le
1
une fois que vous avez ajouté des fichiers, ils se retrouvent toujours dans certaines couches. Donc, leur suppression ne vous aidera pas à les masquer si elles sont sensibles à la sécurité ou à réduire la taille de l'image (car elles seront dans les couches sous-jacentes). Il existe des options pour squashles couches. L'un est github.com/goldmann/docker-squash et un autre utilise oc ex dockerbuildle projet openshift.
akostadinov
6

On dirait que l'ancienne solution ne fonctionne plus (du moins pour moi). La création d'un dossier vide et le mappage du dossier cible à celui-ci ont cependant aidé.

volumes:
   - ./angularApp:/opt/app
   - .empty:/opt/app/node_modules/
barre de maintien
la source
Ne fonctionne pas non plus pour moi avec docker-compose 1.25.0-rc3la syntaxe de fichier v3.
thisismydesign
6

Avec la ligne de commande docker:

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

L' -voption peut également être utilisée (crédit à Bogdan Mart ), mais elle --mountest plus claire et recommandée .

DS.
la source
6

pour les personnes qui ont également eu le problème que le dossier node_modules écraserait toujours à partir de votre système local et vice versa

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

C'est la solution, avec la fin /après les node_modules étant le correctif.

Daenor
la source
0

Pour exclure un fichier monté contenu dans le volume de votre machine, vous devrez l'écraser en allouant un volume à ce même fichier. Dans votre fichier de configuration:

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

Un exemple dans votre dockerfile:

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