Pergunta original: Como usar a instrução VOLUME no Dockerfile?
A questão real que quero resolver é: como montar volumes de host em contêineres do Dockerfile durante a compilação, ou seja, ter o docker run -v /export:/export
capacidade durante docker build
.
A razão por trás disso, para mim, é ao criar coisas no Docker, não quero isso (apt-get install
caches ) sejam bloqueados em uma única janela de encaixe, mas para compartilhá-los / reutilizá-los. Essa é a principal razão pela qual estou perguntando sobre essa pergunta.
Última atualização:
Antes da janela de encaixe v18.09, a resposta correta deve ser a que começa com:
Existe uma maneira de montar um volume durante uma compilação, mas isso não envolve os Dockerfiles.
No entanto, essa foi uma resposta mal declarada, organizada e apoiada. Quando eu estava reinstalando minha janela de encaixe, encontrei o seguinte artigo:
Dockerize um serviço apt-cacher-ng
https://docs.docker.com/engine/examples/apt-cacher-ng/
Essa é a solução do docker para esta / minha pergunta, não direta mas indiretamente. É a maneira ortodoxa que o docker nos sugere. E admito que é melhor do que o que eu estava tentando perguntar aqui.
Outra maneira é a resposta recém-aceita , por exemplo, o Buildkit na v18.09.
Escolha o que mais lhe convier.
Foi: Houve uma solução - rocker, que não era da Docker, mas agora que o rocker foi descontinuado, eu reverto a resposta novamente para "Não é possível" novamente.
Atualização antiga: Portanto, a resposta é "Não é possível". Posso aceitá-lo como resposta, pois sei que o problema foi amplamente discutido em https://github.com/docker/docker/issues/3156 . Entendo que a portabilidade é um problema primordial para o desenvolvedor de docker; mas como usuário do docker, devo dizer que estou muito desapontado com esse recurso ausente. Deixe-me encerrar meu argumento com uma citação da discussão acima: " Gostaria de usar o Gentoo como uma imagem de base, mas definitivamente não quero que mais de 1 GB de dados da árvore do Portage estejam em qualquer uma das camadas depois que a imagem for criada. poderia ter alguns recipientes compactos e agradáveis, se não fosse pela gigantesca árvore do portage que aparecesse na imagem durante a instalação."Sim, eu posso usar o wget ou curl para baixar o que precisar, mas o fato de que apenas uma consideração de portabilidade está me forçando a baixar> 1 GB da árvore do Portage cada vez que eu construo uma imagem base do Gentoo não é eficiente nem amigável. além disso, o repositório de pacotes SEMPRE estará em / usr / portage, portanto SEMPRE PORTÁTIL no Gentoo. Mais uma vez, eu respeito a decisão, mas permita-me expressar minha decepção também nesse meio tempo.
Pergunta original em detalhes:
De
Compartilhar diretórios por volumes
http://docker.readthedocs.org/en/v0.7.3/use/working_with_volumes/
ele diz que o recurso de volumes de dados "está disponível desde a versão 1 da API remota do Docker". Minha janela de encaixe é da versão 1.2.0, mas achei o exemplo dado no artigo acima não funcionando:
# BUILD-USING: docker build -t data .
# RUN-USING: docker run -name DATA data
FROM busybox
VOLUME ["/var/volume1", "/var/volume2"]
CMD ["/usr/bin/true"]
Qual é a maneira correta no Dockerfile de montar volumes montados no host em contêineres do docker, através do comando VOLUME?
$ apt-cache policy lxc-docker
lxc-docker:
Installed: 1.2.0
Candidate: 1.2.0
Version table:
*** 1.2.0 0
500 https://get.docker.io/ubuntu/ docker/main amd64 Packages
100 /var/lib/dpkg/status
$ cat Dockerfile
FROM debian:sid
VOLUME ["/export"]
RUN ls -l /export
CMD ls -l /export
$ docker build -t data .
Sending build context to Docker daemon 2.56 kB
Sending build context to Docker daemon
Step 0 : FROM debian:sid
---> 77e97a48ce6a
Step 1 : VOLUME ["/export"]
---> Using cache
---> 59b69b65a074
Step 2 : RUN ls -l /export
---> Running in df43c78d74be
total 0
---> 9d29a6eb263f
Removing intermediate container df43c78d74be
Step 3 : CMD ls -l /export
---> Running in 8e4916d3e390
---> d6e7e1c52551
Removing intermediate container 8e4916d3e390
Successfully built d6e7e1c52551
$ docker run data
total 0
$ ls -l /export | wc
20 162 1131
$ docker -v
Docker version 1.2.0, build fa7b24f
VOLUME ~/host_dir ~/container_dir
. A discussão é bastante extensa, e existe uma maneira curta de resumir qual é o motivo?Respostas:
Primeiro, para responder "por que não
VOLUME
funciona?" Quando você define aVOLUME
no Dockerfile, é possível definir apenas o destino, não a origem do volume. Durante a construção, você receberá apenas um volume anônimo. Esse volume anônimo será montado a cadaRUN
comando, preenchido previamente com o conteúdo da imagem e descartado no final doRUN
comando. Somente alterações no contêiner são salvas, não alterações no volume.Como essa pergunta foi feita, alguns recursos foram lançados que podem ajudar. O primeiro é a compilação de vários estágios, permitindo que você crie um primeiro estágio ineficiente em espaço em disco e copie apenas a saída necessária para o estágio final que você envia. E o segundo recurso é o Buildkit, que está mudando drasticamente a maneira como as imagens são construídas e os novos recursos sendo adicionados à construção.
Para uma construção de vários estágios, você teria várias
FROM
linhas, cada uma iniciando a criação de uma imagem separada. Somente a última imagem é marcada por padrão, mas você pode copiar arquivos dos estágios anteriores. O uso padrão é ter um ambiente de compilador para construir um artefato binário ou outro aplicativo e um ambiente de tempo de execução como o segundo estágio que copia esse artefato. Você pode ter:Isso resultaria em uma construção que contém apenas o binário resultante, e não o diretório completo / export.
O Buildkit está saindo do experimental em 18.09. É uma reformulação completa do processo de compilação, incluindo a capacidade de alterar o analisador de front-end. Uma dessas alterações no analisador implementou a
RUN --mount
opção que permite montar um diretório de cache para seus comandos de execução. Por exemplo, aqui está um que monta alguns dos diretórios debian (com uma reconfiguração da imagem debian, isso pode acelerar a reinstalação de pacotes):Você ajustaria o diretório de cache para qualquer cache de aplicativo que possua, por exemplo, $ HOME / .m2 para maven ou /root/.cache para golang.
TL; DR: A resposta está aqui: Com essa
RUN --mount
sintaxe, você também pode vincular diretórios somente leitura de montagem a partir do contexto de construção. A pasta deve existir no contexto de construção e não é mapeada de volta para o host ou o cliente de construção:Observe que, como o diretório é montado a partir do contexto, ele também é montado como somente leitura, e você não pode enviar as alterações de volta ao host ou cliente. Ao criar, você desejará uma instalação 18.09 ou mais recente e habilitar o buildkit com
export DOCKER_BUILDKIT=1
.Se você receber um erro de que o sinalizador mount não é suportado, isso indica que você não ativou o buildkit com a variável acima ou que não ativou a sintaxe experimental com a linha de sintaxe na parte superior do Dockerfile antes quaisquer outras linhas, incluindo comentários. Observe que a variável para alternar o buildkit só funcionará se a instalação do docker tiver suporte para buildkit embutido, o que requer a versão 18.09 ou mais recente do Docker, no cliente e no servidor.
fonte
Não é possível usar as
VOLUME
instruções para informar ao docker o que montar. Isso quebraria seriamente a portabilidade. Esta instrução informa ao estivador que o conteúdo desses diretórios não entra em imagens e pode ser acessado de outros contêineres usando o--volumes-from
parâmetro de linha de comando. Você precisa executar o contêiner-v /path/on/host:/path/in/container
para acessar diretórios do host.A montagem de volumes do host durante a construção não é possível. Não há construção privilegiada e a montagem do host também degradaria seriamente a portabilidade. Você pode tentar usar o wget ou curl para baixar o que for necessário para a compilação e colocá-lo no lugar.
fonte
ATUALIZAÇÃO: Alguém simplesmente não aceita o não como resposta e eu gosto muito, especialmente para essa pergunta em particular.
BOAS NOTÍCIAS, Existe um caminho agora -
A solução é Rocker: https://github.com/grammarly/rocker
John Yani disse : "Na IMO, ele resolve todos os pontos fracos do Dockerfile, tornando-o adequado para o desenvolvimento".
Rocker
https://github.com/grammarly/rocker
Atualização: Rocker foi descontinuado, de acordo com o repositório oficial do projeto no Github
fonte
MOUNT ~/code/docker-app-dev/new-editor/:/src/
e meu comando de montagem do Rocker é este -rocker build -f Dockerfile .
. O que estou fazendo de errado?~
é um metacaractere da casca de Bourne.Rocker build
não permitedocker run
opções de linha de comando; portanto, atualmente não permite coisas como--privileged
.Existe uma maneira de montar um volume durante uma compilação, mas isso não envolve os Dockerfiles.
A técnica seria criar um contêiner a partir de qualquer base que você desejasse usar (montar o (s) seu (s) volume (s) no contêiner com a
-v
opção), executar um script de shell para fazer o trabalho de criação da imagem e confirmar o contêiner como uma imagem quando terminar .Isso não apenas deixará de fora os arquivos em excesso que você não deseja (isso também é bom para arquivos seguros, como arquivos SSH), mas também cria uma única imagem. Ele tem desvantagens: o comando commit não suporta todas as instruções do Dockerfile e não permite que você escolha quando parou se precisar editar seu script de construção.
ATUALIZAR:
Por exemplo,
fonte
debian:wheezy
e o shell scriptbuild.sh
, que instruções específicas você usaria?Conforme você executa o contêiner, um diretório em seu host é criado e montado no contêiner. Você pode descobrir em que diretório está esse
Se você deseja montar um diretório a partir do seu host dentro de seu contêiner, é necessário usar o
-v
parâmetro e especificar o diretório No seu caso, isso seria:Portanto, você usaria a pasta hosts dentro do seu contêiner.
fonte
Eu acho que você pode fazer o que deseja, executando a compilação por meio de um comando docker, que é executado dentro de um contêiner de docker. Consulte Docker agora pode ser executado no Docker | Blog do Docker . Uma técnica como essa, mas que realmente acessou a janela de encaixe externa de um contêiner, foi usada, por exemplo, ao explorar como criar o menor contêiner de Docker possível | Xebia Blog .
Outro artigo relevante é Otimizando imagens do Docker | O CenturyLink Labs , que explica que, se você fizer o download de coisas durante uma compilação, poderá evitar o desperdício de espaço na imagem final fazendo o download, construindo e excluindo o download em uma única etapa RUN.
fonte
É feio, mas consegui uma aparência assim:
Dockerfile:
imageBuild.sh:
Eu tenho uma compilação java que baixa o universo para /root/.m2, e o fazia todas as vezes .
imageBuild.sh
copia o conteúdo dessa pasta no host após a compilação e osDockerfile
copia novamente na imagem para a próxima compilação.É algo como um volume funcionaria (isto é, persiste entre as compilações).
fonte
Aqui está uma versão simplificada da abordagem em duas etapas usando build e commit, sem scripts de shell. Envolve:
Com alterações relativamente pequenas, a etapa adicional adiciona apenas alguns segundos ao tempo de compilação.
Basicamente:
No meu caso de uso, quero pré-gerar um arquivo maven toolchains.xml, mas minhas muitas instalações JDK estão em um volume que não está disponível até o tempo de execução. Algumas de minhas imagens não são compatíveis com todos os JDKS, portanto, preciso testar a compatibilidade no momento da construção e preencher o toolchains.xml condicionalmente. Observe que não preciso que a imagem seja portátil, não a estou publicando no Docker Hub.
fonte
Como muitos já responderam, não é possível montar volumes de host durante a construção. Gostaria apenas de acrescentar uma
docker-compose
maneira, acho que será bom ter, principalmente para uso em desenvolvimento / testeDockerfile
docker-compose.yml
E execute seu contêiner
docker-compose up -d --build
fonte