Como montar um único arquivo em um volume

257

Estou tentando dockerize um aplicativo php. No arquivo docker, eu baixa o arquivo, extraio-o etc.

Tudo funciona bem, no entanto, se uma nova versão for lançada e eu atualizar o arquivo docker, tenho que reinstalar o aplicativo, porque o config.php é substituído.

Então, pensei em montar o arquivo como um volume, como faço com o banco de dados.

Eu tentei de duas maneiras, com um volume e um caminho direto.

docker-compor:

version: '2'
services:
  app:
    build: src
    ports:
      - "8080:80"
    depends_on:
      - mysql
    volumes:
      -  app-conf:/var/www/html/upload
      -  app-conf:/var/www/html/config.php
    environment:
      DB_TYPE: mysql
      DB_MANAGER: MysqlManager

  mysql:
    image: mysql:5.6
    container_name: mysql
    volumes:
      - mysqldata:/var/lib/mysql
    ports:
      - 3306:3306
    environment:
      MYSQL_ROOT_PASSWORD:
      MYSQL_DATABASE:
      MYSQL_USER:
      MYSQL_PASSWORD:

volumes:
  mysqldata:
  app-conf:

O que resulta no erro:

E eu tentei com um determinado caminho, como um volume montado.

/src/docker/myapp/upload:/var/www/html/upload
/src/docker/myapp/upload:/var/www/html/config.php

No entanto, os dois lados não estão funcionando. Com o volume montado, vejo que o upload é criado.

Mas então falha com

/var/www/html/config.php \\ "causou \\" não um diretório \\ "\" "

Se eu tentar com

/src/docker/myapp/upload/config.php:/var/www/html/config.php

O Docker cria a pasta de upload e, em seguida, uma pasta config.php. Não é um arquivo.

Ou existe outra maneira de persistir na configuração?

Jakub Juszczak
fonte
No meu caso, eu simples que "toque" em um arquivo vazio antes de criar o contêiner / volume. Se o arquivo não existisse, ele criaria um diretório.
FreeSoftwareServers

Respostas:

312

TL; DR / Aviso:

Se você encontrar um diretório sendo criado no lugar do arquivo que está tentando montar, provavelmente não conseguiu fornecer um caminho válido e absoluto . Este é um erro comum com um modo de falha silencioso e confuso.

Os volumes de arquivos são feitos dessa maneira no docker (exemplo de caminho absoluto (pode usar variáveis ​​env) e você precisa mencionar o nome do arquivo):

    volumes:
      - /src/docker/myapp/upload:/var/www/html/upload
      - /src/docker/myapp/upload/config.php:/var/www/html/config.php

Você também pode fazer:

    volumes:
      - ${PWD}/upload:/var/www/html/upload
      - ${PWD}/upload/config.php:/var/www/html/config.php

Se você disparar a janela de encaixe-compor da /src/docker/myapppasta

BlackStork
fonte
81
Como eu disse, se eu tentar /src/docker/myapp/upload/config.php:/var/www/html/config.php O Docker cria a pasta de upload e, em seguida, uma pasta config.php. Não é um arquivo.
Jakub Juszczak
9
No seu post, você escreveu de forma diferente. Se o arquivo estiver lá, ele deverá ser montado como arquivo.
BlackStork 16/02
16
Para que isso funcionasse, tive que fornecer um caminho absoluto. A dica usando PWD ajudou muito aqui, obrigado!
9788 Steve
4
Para mim, está criando uma pasta em vez dos arquivos, mas acho que porque esse arquivo é copiado posteriormente nesse caminho, existe uma maneira de adiar a ligação?
eKelvin
18
se /src/docker/myapp/upload/config.php não existir no docker host criará uma pasta ... O que estou fazendo é criar um script que cria um arquivo vazio antes de executar o docker - seria o ideal se eu puder instruir o docker a fazer isso por mim através da linha cmd args.
Cancerbero
78

Eu estava sofrendo de um problema semelhante. Eu estava tentando importar meu arquivo de configuração para o meu contêiner, para que eu possa corrigi-lo toda vez que precisar, sem reconstruir a imagem.

Quero dizer, pensei que o comando abaixo fosse $(pwd)/config.pymapeado do host do Docker para /root/app/config.pyo contêiner como um arquivo.

docker run -v $(pwd)/config.py:/root/app/config.py my_docker_image

No entanto, sempre criou um diretório chamado config.py, não um arquivo.

enquanto procurava por pistas, encontrei o motivo ( daqui )

Se você usar -v ou --volume para montar um arquivo ou diretório que ainda não exista no host do Docker, -v criará o terminal para você. É sempre criado como um diretório .

Portanto, ele sempre é criado como um diretório porque o meu host de docker não possui $(pwd)/config.py.

Mesmo se eu criar o config.py no host do docker. $(pwd)/config.pyapenas exagere na /root/app/config.pyexportação /root/app/config.py.

SangminKim
fonte
16
Acabei de adicionar um touch path/to/fileno Dockerfilemodo que quando eu montá-lo ainda seria um arquivo (não é um dir criado)
shadi
8
lado esquerdo de :tem que ser o caminho completo. Funciona assim
sdkks
A touchresposta foi a seguinte: faça isso no Dockerfile para que o seu volume de docker-componha a montagem funcione corretamente sem criar um diretório
ctrlbrk
27

Use mount ( --mount) em vez de volume ( -v)

Mais informações: https://docs.docker.com/storage/bind-mounts/

Exemplo:

Verifique se /tmp/a.txt existe no host do docker

docker run -it --mount type=bind,source=/tmp/a.txt,target=/root/a.txt alpine sh
Subbu M
fonte
Obrigado subbu, @Jakub Juszczak esta deve ser a resposta aceita, é a única resposta que responde à pergunta em tudo, e ele trabalhou para mim
neokyle
2
Isso realmente não responde à pergunta. os volumes também funcionarão (porque o problema está no caminho absoluto). A única diferença entre --mounte -vé o comportamento quando parte do host do volume ainda não existe. Conforme o seu link:> Se você usar -v ou --volume para montar um arquivo ou diretório que ainda não exista no host do Docker, -v criará o terminal para você. É sempre criado como um diretório.
The Godfather
2
Não sei como traduzir isso em uma janela de encaixe-compor. 'Pequena ajuda?
msanford
@msanford Adicionei um exemplo de docker-compose à resposta.
sebisnow 6/03
10

Para quem usa contêiner do Windows como eu, saiba que NÃO PODE vincular ou montar arquivos únicos usando o contêiner do Windows.

Os exemplos a seguir falharão ao usar contêineres baseados no Windows, pois o destino de uma montagem de volume ou ligação dentro do contêiner deve ser um dos seguintes: um diretório inexistente ou vazio; ou uma unidade diferente de C :. Além disso, a origem de uma montagem de ligação deve ser um diretório local, não um arquivo .

net use z: \\remotemachine\share

docker run -v z:\foo:c:\dest ...

docker run -v \\uncpath\to\directory:c:\dest ...

docker run -v c:\foo\somefile.txt:c:\dest ...

docker run -v c:\foo:c: ...

docker run -v c:\foo:c:\existing-directory-with-contents ...

É difícil de detectar, mas está lá

Link para o problema do Github referente ao mapeamento de arquivos no contêiner do Windows

Justin Lessard
fonte
7

No arquivo docker-compose versão 3.2, você pode especificar uma montagem de volume do tipo "bind" (em vez do tipo padrão "volume") que permite montar um único arquivo no contêiner. Procure por "montagem de ligação" nos documentos do volume de encaixe / composição: https://docs.docker.com/compose/compose-file/#volumes

No meu caso, eu estava tentando montar um único arquivo ".secrets" no meu aplicativo que continha segredos apenas para desenvolvimento e teste local. Na produção, meu aplicativo busca esses segredos da AWS.

Se eu montei esse arquivo como um volume usando a sintaxe abreviada:

volumes:
 - ./.secrets:/data/app/.secrets

O Docker criaria um diretório ".secrets" dentro do contêiner, em vez de mapear para o arquivo fora do contêiner. Meu código geraria um erro como "IsADirectoryError: [Erro 21] É um diretório: '.secrets'".

Corrigi isso usando a sintaxe da mão longa, especificando meu arquivo de segredos usando uma montagem de volume "bind" somente leitura:

volumes:
 - type: bind
   source: ./.secrets
   target: /data/app/.secrets
   read_only: true

Agora, o Docker monta corretamente meu arquivo .secrets no contêiner, criando um arquivo dentro do contêiner, em vez de um diretório. Espero que outros achem este exemplo útil!

Carlton Duffett
fonte
Obrigado senhor! Essa era a solução que eu precisava para montar meu arquivo wp-config.php do WordPress (e impedir que ele fosse criado como um diretório)
Jono
6

Você também pode usar um caminho relativo para seu docker-compose.ymlarquivo como este (testado no host do Windows, contêiner Linux):

 volumes:
      - ./test.conf:/fluentd/etc/test.conf
Daniel
fonte
1
Eu testei isso no Mac com version: '3.7'especificado no docker-compose.ymlarquivo com docker-compose versão 1.24.1, compilação 4667896b e funcionou.
Acumenus 28/10/19
6
Ainda recebo um diretório em vez de um arquivo.
Chovy
0

Para mim, o problema era que eu tinha um link simbólico quebrado no arquivo que estava tentando montar no contêiner

jla
fonte
0

Eu tive o mesmo problema no Windows Docker 18.06.1-ce-win73 (19507),.

Remover e adicionar novamente a unidade compartilhada através do painel de configurações do Docker e tudo funcionou novamente.

Piscina
fonte
0

No Windows, se você precisar da variável env $ {PWD} em seu docker-compose.yml, poderá criar um arquivo .env no mesmo diretório que o arquivo docker-compose.yml e inserir manualmente o local da sua pasta.

CMD (pwd_var.bat):

echo PWD=%cd% >> .env

PowerShell (pwd_var.ps1):

$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'; echo "PWD=$(get-location).path" >> .env

Há mais recursos bons para as variáveis ​​.env do docker-compose: https://docs.docker.com/compose/reference/envvars/, especialmente para a COMPOSE_CONVERT_WINDOWS_PATHSvariável env que permite que o docker compose aceite o caminho do Windows com barra de ataque "\".

Quando você deseja compartilhar um arquivo no Windows, o arquivo deve existir antes de compartilhá-lo com o contêiner.

CallMarl
fonte
Você não pode usar o PowerShell com janela de encaixe, ele cria um vendor lock-in e fere a comunidade ...
Matej 'Yin' Gagyi
0

Talvez isso ajude alguém.

Eu tive esse problema e tentei de tudo. As ligações de volume pareciam bem e, mesmo que eu montei o diretório (não os arquivos), eu tinha os nomes dos arquivos no diretório montado corretamente, mas montados como dirs.

Tentei reativar unidades compartilhadas e o Docker reclamou que o firewall está ativo.

Depois de desativar o firewall, tudo estava funcionando bem.

Josef Sábl
fonte
Obrigado por isso! Sua postagem me fez perceber que meu selinux estava sendo aplicado e que estava causando todos os meus problemas. Não sei por que você recebeu votos negativos ¯_ (ツ) _ / ¯
Otaviano
0

Você pode montar arquivos ou diretórios / pastas, tudo depende do arquivo ou diretório de origem. E você também precisa fornecer o caminho completo ou, se não tiver certeza, pode usar o PWD. Aqui está um exemplo simples de trabalho.

Neste exemplo, estou montando o arquivo env-command que já existe no meu diretório de trabalho

$ docker run  --rm -it -v ${PWD}/env-commands:/env-commands aravindgv/eosdt:1.0.5 /bin/bash -c "cat /env-commands"
Aravind GV
fonte
-1

Tenho o mesmo problema no meu Windows 8.1

Descobriu-se que era devido à distinção entre maiúsculas e minúsculas do caminho. Liguei docker-compose updo diretório cd /c/users/alex/e, dentro do contêiner, um arquivo foi transformado em diretório.

Mas quando eu fiz cd /c/Users/alex/(e não os Usuários em maiúscula) e liguei docker-compose upde lá, funcionou.

No meu sistema, tanto o diretório Users quanto o Alex dir estão em maiúsculas, embora pareça que apenas o diretório Users seja importante.

Alex Velickiy
fonte