Adicione um volume ao Docker, mas exclua uma subpasta

210

Suponha que eu tenha um contêiner do Docker e uma pasta no meu host /hostFolder. Agora, se eu quiser adicionar esta pasta ao contêiner do Docker como um volume, posso fazer isso usando ADD-o Dockerfileou montando-o como um volume.

Por enquanto, tudo bem.

Agora /hostFoldercontém uma subpasta /hostFolder/subFolder,.

Desejo montar /hostFolderno contêiner do Docker (seja como leitura-gravação ou somente leitura, não importa, funciona para mim), mas NÃO quero incluí-lo /hostFolder/subFolder. Desejo excluir isso e também quero que o contêiner do Docker possa fazer alterações nessa subpasta, sem a conseqüência de alterá-lo também no host.

Isso é possível? Se sim, como?

Golo Roden
fonte
2
@AbhijitSarkar que não é um comentário muito construtivo (nem de forma alguma útil).
kano 21/08
1
@ Kano É um comentário, não uma resposta.
Abhijit Sarkar

Respostas:

398

Usando o docker-compose, posso usar node_modules localmente, mas ignorá-lo no contêiner do docker usando a seguinte sintaxe no docker-compose.yml

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

Portanto, tudo ./angularAppé mapeado para /opt/appe, em seguida, crio outro volume de montagem /opt/app/node_modules/que agora está no diretório vazio - mesmo que na minha máquina local ./angularApp/node_modulesnão esteja vazio.

kernix
fonte
3
Funciona, mas não consigo remover esses diretórios dentro do contêiner. Por exemplo: preciso substituir /opt/app/node_modules/por outro diretório com o mesmo nome. Erro acontece: 'volume ocupado'
Stepan Yudin 23/09
32
Não se esqueça da barra à direita! por exemplo. / opt / app / node_modules não funciona, ele será sobrescrito por ./angularApp/node_modules
Stingus
3
Esse truque costumava funcionar para mim, mas não parece mais, mesmo para o mesmo arquivo Compose. Curioso se ele também parou de funcionar para os outros.
precisa saber é
8
obrigado! Você salvou o meu dia! No caso de utilizar janela de encaixe simples, não compos que seria parecido com: -v $(pwd):/build/ -v /build/node_modules
Bogdan Mart
3
Encontrei o 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 18/04
118

Se você deseja que os subdiretórios sejam ignorados pelo docker-compose, mas persistentes, faça o seguinte em docker-compose.yml:

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

Isso montará seu diretório atual como um volume compartilhado, mas montará um volume persistente de janela de encaixe no lugar do node_modulesdiretório local . Isso é semelhante à resposta do @kernix, mas permitirá node_modulespersistir entre as docker-compose upexecuções, o que provavelmente é o comportamento desejado.

Nate T
fonte
20
Volumes nomeados são uma abordagem superior. Protip: verifique se você não está usando um nome de volume hifenizado. Você passará uma pequena parte da sua vida em um pesadelo de depuração, apenas para descobrir que você foi enganado novamente por uma nuance ridícula.
Dustintheweb 31/05
3
"Observe que o docker-compose down irá matar esses volumes persistentes." Isso não é verdade no Docker for Mac v 17.0.5+ (e possivelmente nas versões mais antigas). docker-compose downirá remover os recipientes, mas o volume irá persistir até que você executar algo parecidodocker system prune
BrDaHa
3
Caso alguém esteja interessado em entender por que o uso do node_modules:volume nomeado "ignora" o /app/node_modulescontêiner do docker, poderá achar útil este post Como o docker lida com vários tipos de montagem?
21417
3
Não sei se estou fazendo algo errado, mas se fizer isso, inicie o contêiner e execute o npm install na máquina HOST, ele também altera os node_modules dentro do CONTAINER. Não consigo imaginar por que alguém iria querer fazer isso, mas ainda estou procurando uma separação mais limpa.
Renra
3
A @Renra tinha exatamente o mesmo problema, minha máquina host escrevia constantemente sobre node_modules mesmo que eu tivesse o volume nomeado ... causava todo tipo de problemas de incompatibilidade. Deu-se em corrigi-lo e trabalhou em torno dele copiando somente minha pasta src em vez de toda a repo
dancypants
19

Para excluir um arquivo, use o seguinte

volumes:
   - /hostFolder:/folder
   - /dev/null:/folder/fileToBeExcluded
Frank Wong
fonte
6
Solução perfeita para o que eu precisava (para NÃO mapear node_modules até o host porque as coisas do link simbólico foram interrompidas em um host do Windows). Apontar para / dev / null não funcionou, mas criar um diretório em branco e mapear para que funcionasse perfeitamente e resolveu os problemas que eu estava tendo - obrigado por essa idéia.
Liam Hammett
1
Isso não funciona em Docker 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. Adicionar uma barra à direita não ajudou.
Blaise
Posso confirmar que ele não funciona no Ubuntu 16.04 com Docker 18.09.3.
Dirk
Isso não funciona para mim. Tudo o que faz é copiar /dev/nullpara o contêiner, como um arquivo de dispositivo.
Radon Rosborough
1
Observe que isso funciona apenas para excluir arquivos! / dev / null é um arquivo e assim deve ser o alvo, a mensagem de erro é bastante claro sobre isso: 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. Isso não é exatamente o que o OP estava procurando, mas foi muito útil para mim, pois eu precisava excluir um único arquivo.
Avius 12/11/19
13

Primeiro, usar a ADDinstrução em um Dockerfile é muito diferente de usar um volume (pelo -vargumento docker runou pela VOLUMEinstrução em um Dockerfile). Os comandos ADDe COPYapenas tiram uma cópia dos arquivos no momento em que docker buildsão executados. Esses arquivos não são atualizados até que uma nova imagem seja criada com o docker buildcomando Por outro lado, o uso de um volume significa essencialmente "esse diretório não deve ser armazenado na imagem do contêiner; em vez disso, use um diretório no host"; sempre que um arquivo dentro de um volume for alterado, o host e o contêiner o verão imediatamente.

Não acredito que você possa alcançar o que deseja usando volumes; terá que repensar sua estrutura de diretórios se desejar fazer isso.

No entanto, é bastante simples conseguir usar COPY(o que deve ser preferido ADD). Você pode usar um .dockerignorearquivo para excluir o subdiretório ou COPYtodos os arquivos e, em seguida, fazer um RUN rm blapara remover o subdiretório.

Lembre-se de que todos os arquivos adicionados à imagem com COPYou ADDdevem estar dentro do contexto de construção, ou seja, dentro ou abaixo do diretório em que você executa docker build.

Adrian Mouat
fonte
1
aprenda algo novo todos os dias :-) o COPY e o ADD funcionam no contexto da construção (não no host). Seria possível usar um volume para mascarar a subpasta? O OP quer montar o / hostFolder (eu acho) e fazer / hostFolder / subFolder desconectado. Se houvesse um VOLUME para cada um, mas apenas o hostFolder fosse 'montado' (-v), isso isolaria as alterações da subpasta no contêiner?
Greg
Não tenho certeza, nunca tentei aninhar volumes. Não estou convencido de que seja uma boa ideia, mas teria que investigar.
Adrian Mouat
1
Não consigo encontrar um exemplo em nenhum lugar do que colocar em um .dockerignorearquivo para excluir um subdiretório (ou mesmo um diretório). Dado que esse é o objetivo declarado do arquivo, é bastante estranho.
Lukas Oberhuber
1
Depois de adicionar qualquer arquivo, eles ainda terminam em algumas camadas. Portanto, a remoção deles não ajudará a ocultá-los se for sensível à segurança ou reduzir o tamanho da imagem (porque eles estarão nas camadas subjacentes). Existem opções para squashas camadas. Um é o github.com/goldmann/docker-squash e o outro é usado oc ex dockerbuildno projeto openshift.
Akostadinov 11/11/16
6

Parece que a solução antiga não funciona mais (pelo menos para mim). Criar uma pasta vazia e mapear a pasta de destino para ela ajudou.

volumes:
   - ./angularApp:/opt/app
   - .empty:/opt/app/node_modules/
holdbar
fonte
Também não funciona para mim com a docker-compose 1.25.0-rc3sintaxe de arquivo v3.
thisismydesign
6

Com a linha de comando do docker:

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

A -vopção também pode ser usada (crédito ao Bogdan Mart ), mas --mounté mais clara e recomendada .

DS.
fonte
6

para as pessoas que também tiveram o problema de a pasta node_modules ainda sobrescrever no sistema local e vice-versa

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

Esta é a solução, com /o seguimento dos node_modules sendo a correção.

Daenor
fonte
0

Para excluir um arquivo montado contido no volume da sua máquina, você precisará substituí-lo, alocando um volume para o mesmo arquivo. No seu arquivo de configuração:

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

Um exemplo no seu arquivo docker:

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