Temos o seguinte bloco em nosso Dockerfile
:
RUN yum -y update
RUN yum -y install epel-release
RUN yum -y groupinstall "Development Tools"
RUN yum -y install python-pip git mysql-devel libxml2-devel libxslt-devel python-devel openldap-devel libffi-devel openssl-devel
Foi-me dito que devemos unir esses RUN
comandos para reduzir as camadas de janela de encaixe criadas:
RUN yum -y update \
&& yum -y install epel-release \
&& yum -y groupinstall "Development Tools" \
&& yum -y install python-pip git mysql-devel libxml2-devel libxslt-devel python-devel openldap-devel libffi-devel openssl-devel
Sou muito novato no docker e não tenho certeza de entender completamente as diferenças entre essas duas versões da especificação de vários comandos RUN. Quando alguém uniria RUN
comandos em um único e quando faz sentido ter vários RUN
comandos?
docker
dockerfile
alecxe
fonte
fonte
Respostas:
Uma imagem do docker é na verdade uma lista vinculada de camadas do sistema de arquivos. Cada instrução em um Dockerfile cria uma camada do sistema de arquivos que descreve as diferenças no sistema de arquivos antes e após a execução da instrução correspondente. O
docker inspect
subcomando pode ser usado em uma imagem de janela de encaixe para revelar sua natureza de ser uma lista vinculada de camadas do sistema de arquivos.O número de camadas usadas em uma imagem é importante
Isso tem várias conseqüências sobre como as imagens devem ser construídas. O primeiro e mais importante conselho que posso dar é:
A razão para isso é que todas as etapas anteriores serão armazenadas em cache e as camadas correspondentes não precisarão ser baixadas repetidamente. Isso significa compilações e lançamentos mais rápidos, provavelmente o que você deseja. Curiosamente, é surpreendentemente difícil fazer um uso otimizado do cache do docker.
Meu segundo conselho é menos importante, mas acho muito útil do ponto de vista da manutenção:
Um Dockerfile seguindo este conselho pareceria
e assim por diante. O conselho de vincular vários comandos com
&&
apenas um escopo limitado. É muito mais fácil escrever com scripts, onde você pode usar funções etc. para evitar redundância ou para fins de documentação.As pessoas interessadas pelos pré-processadores e dispostas a evitar a pequena sobrecarga causada pelas
COPY
etapas e na verdade estão gerando on-the-fly um Dockerfile em que osequências são substituídas por
onde
…
é a versão codificada em base64 deapt_setup.sh
.Meu terceiro conselho é para pessoas que desejam limitar o tamanho e o número de camadas ao possível custo de construções mais longas.
Um arquivo adicionado por alguma instrução do docker e removido por alguma instrução posterior não está presente no sistema de arquivos resultante, mas é mencionado duas vezes nas camadas do docker que constituem a imagem do docker em construção. Uma vez, com nome e conteúdo completo na camada resultante da adição da instrução e uma vez como aviso de exclusão na camada resultante da remoção da instrução.
Por exemplo, suponha que precisamos temporariamente de um compilador C e alguma imagem e considere o
(Um exemplo mais realista criaria algum software com o compilador, em vez de apenas afirmar sua presença com o
--version
sinalizador.)O snippet do Dockerfile cria três camadas, a primeira contém o pacote gcc completo, de modo que, mesmo que não esteja presente no sistema de arquivos final, os dados correspondentes ainda fazem parte da imagem da mesma maneira e precisam ser baixados, carregados e descompactados sempre que o arquivo imagem final é.
O
with
idiom é uma forma comum na programação funcional para isolar a propriedade e a liberação de recursos da lógica que o utiliza. É fácil transpor esse idioma para shell-script, e podemos reformular os comandos anteriores como o script a seguir, para ser usadoCOPY & RUN
como no Conselho # 2.Comandos complexos podem ser transformados em função para que possam ser alimentados ao
with_c_compiler
. Também é possível encadear chamadas de váriaswith_whatever
funções, mas talvez não seja muito desejável. (Usando recursos mais esotéricos do shell, certamente é possível tornar oswith_c_compiler
comandos complexos aceitos, mas em todos os aspectos é preferível agrupar esses comandos complexos em funções.)Se quisermos ignorar o Conselho nº 2, o snippet do Dockerfile resultante será
o que não é tão fácil de ler e manter por causa da ofuscação. Veja como a variante do shell script enfatiza a parte importante,
gcc --version
enquanto a&&
variante encadeada enterra a parte no meio do ruído.fonte
Cada instrução que você cria no Dockerfile resulta em uma nova camada de imagem sendo criada. Cada camada traz dados adicionais que nem sempre fazem parte da imagem resultante. Por exemplo, se você adicionar um arquivo em uma camada, mas removê-lo em outra camada posteriormente, o tamanho da imagem final incluirá o tamanho do arquivo adicionado na forma de um arquivo "whiteout" especial, embora você o tenha removido.
Digamos que você tenha o seguinte Dockerfile:
O tamanho da imagem resultante será
Por outro lado, com o Dockerfile "semelhante":
O tamanho da imagem resultante será
Você obterá um tamanho ainda menor, se você limpar o cache do yum em uma única instrução RUN.
Então, você deseja manter o equilíbrio entre legibilidade / facilidade de manutenção e número de camadas / tamanho da imagem.
fonte
As
RUN
instruções representam cada camada. Imagine que alguém baixa um pacote, o instala e gostaria de removê-lo. Se alguém usar trêsRUN
instruções, o tamanho da imagem não diminuirá, pois existem camadas separadas. Se alguém executar todos os comandos usando umaRUN
instrução, o tamanho da imagem do disco poderá ser reduzido.fonte