<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Matheus Andrade</title>
    <description>The latest articles on Forem by Matheus Andrade (@matheuslao).</description>
    <link>https://forem.com/matheuslao</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F546084%2F4350c2ba-2e8e-4546-9dad-36b7286bfc41.jpg</url>
      <title>Forem: Matheus Andrade</title>
      <link>https://forem.com/matheuslao</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/matheuslao"/>
    <language>en</language>
    <item>
      <title>Docker Images, Read-Only/Writable Layers, CoW e Dive</title>
      <dc:creator>Matheus Andrade</dc:creator>
      <pubDate>Wed, 06 Jan 2021 15:29:43 +0000</pubDate>
      <link>https://forem.com/matheuslao/docker-images-read-only-writable-layers-cow-e-dive-458p</link>
      <guid>https://forem.com/matheuslao/docker-images-read-only-writable-layers-cow-e-dive-458p</guid>
      <description>&lt;p&gt;Saudações!&lt;/p&gt;

&lt;p&gt;No &lt;a href="https://matheuslao.dev/posts/docker-imagens-empty-filesystem-layers/"&gt;post anterior&lt;/a&gt; vimos a definição de imagens, além da conceituação de &lt;em&gt;layers&lt;/em&gt; e como estas são intrínsecas ao assunto. Entendemos também a existência de &lt;em&gt;filesystem layers&lt;/em&gt;, assim como &lt;em&gt;empty layers&lt;/em&gt; no processo de formação de uma imagem, a partir de instruções (nem todas geram layers) de um &lt;em&gt;Dockerfile&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;O objetivo deste post é continuar dissecando o tema, com alguns estudos/experimentações que nos permitam entender mais como imagens Docker funcionam e são construídas.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR.
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Em relação às &lt;strong&gt;filesystem layers&lt;/strong&gt;, podemos categorizá-las em camadas &lt;em&gt;ReadOnly&lt;/em&gt; ou &lt;em&gt;Writable&lt;/em&gt;;&lt;/li&gt;
&lt;li&gt;Camadas de Imagens são &lt;em&gt;ReadOnly&lt;/em&gt;;&lt;/li&gt;
&lt;li&gt;Camada do Container é &lt;em&gt;Writable&lt;/em&gt;;&lt;/li&gt;
&lt;li&gt;O &lt;strong&gt;CoW: Copy on Write&lt;/strong&gt; acontece tanto no momento do build, quanto com um container em execução, quando há a necessidade de uma modificação em um arquivo/objeto;&lt;/li&gt;
&lt;li&gt;Ferramentas externas como o &lt;a href="https://github.com/wagoodman/dive"&gt;Dive&lt;/a&gt; auxiliam no processo de análises das camadas.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Read-Only Layers e Writable Layers
&lt;/h2&gt;

&lt;p&gt;Há uma relação indissociável entre imagem e &lt;em&gt;layers&lt;/em&gt;. Neste ponto, já entendemos que uma imagem pode ser definida como um &lt;strong&gt;agrupamento ordenado de &lt;em&gt;layers&lt;/em&gt;, sendo estas ultimas, modificações imutáveis resultados de instruções&lt;/strong&gt; presentes no &lt;em&gt;Dockerfile&lt;/em&gt;.  &lt;/p&gt;

&lt;p&gt;A palavra em destaque aqui nesta seção é &lt;strong&gt;imutabilidade&lt;/strong&gt;, ou seja, a &lt;em&gt;layer&lt;/em&gt; representa uma modificação realizada na imagem e esta modificação é permanente &lt;strong&gt;no contexto da *layer&lt;/strong&gt;&lt;em&gt;. Se desejarmos fazer uma segunda modificação, após a primeira já ter sido persistida, tal alteração estará registrada em uma *layer&lt;/em&gt; posterior.&lt;/p&gt;

&lt;p&gt;Em resumo:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Layers de Imagens são **Read Only&lt;/strong&gt;.**&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Aqui também é importante destacar que uma &lt;em&gt;filesystem layer&lt;/em&gt; possuirá persistido &lt;strong&gt;apenas os arquivos modificados em relação à camada anterior&lt;/strong&gt;. Por isso, a ordenação das &lt;em&gt;layers&lt;/em&gt; é importante.&lt;/p&gt;

&lt;p&gt;E o que, ou melhor, de quem seria uma &lt;em&gt;layer&lt;/em&gt; gravável? A resposta: &lt;strong&gt;Container!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Containers nada mais são (do ponto de vista de camadas e armazenamento), do que a adição de uma &lt;em&gt;layer&lt;/em&gt; gravável sobre as &lt;em&gt;layers&lt;/em&gt; que formam uma imagem. Quando um container é instanciado, uma nova camada, desta vez &lt;em&gt;writable&lt;/em&gt;, é criada no topo da imagem (camadas &lt;em&gt;read-only&lt;/em&gt; de formação). Quando o container morre (e deletado do &lt;em&gt;host&lt;/em&gt;), a camada &lt;em&gt;rw&lt;/em&gt; é destruída:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Container adiciona uma &lt;em&gt;layer&lt;/em&gt; gravável sobre as &lt;em&gt;layers&lt;/em&gt; que formam a imagem.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gh-fxC-X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://docs.docker.com/storage/storagedriver/images/sharing-layers.jpg" alt="containers e imagem layers"&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;&lt;a href="https://docs.docker.com/storage/storagedriver/images/sharing-layers.jpg"&gt;https://docs.docker.com/storage/storagedriver/images/sharing-layers.jpg&lt;/a&gt;&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Neste ponto, já é possível perceber o ganho que obtemos, em relação ao espaço em disco consumido, ao instanciar vários containers (réplicas) oriundos de uma mesma imagem. Se instanciarmos 10 containers de uma imagem alpine, por exemplo, as &lt;em&gt;layers read-only&lt;/em&gt; da imagem não serão multiplicadas por 10, mas sim reaproveitadas e 10 camadas &lt;em&gt;writables&lt;/em&gt; serão criadas e associadas cada uma à um container em execução.&lt;/p&gt;

&lt;p&gt;No Docker, temos 2 propriedades que nos mostram tais valores: &lt;code&gt;size&lt;/code&gt; e &lt;code&gt;virtual size&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;size&lt;/code&gt;: o tamanho da camada gravável do container;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;virtual size&lt;/code&gt;: o tamanho total das &lt;em&gt;layers&lt;/em&gt; que fazem o container funcionar: &lt;em&gt;image layers&lt;/em&gt; + &lt;em&gt;writable layer&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No exemplo abaixo, 4 containers já encerrados, oriundos da imagem alpine, sendo que 3 não escreveram em sua camada &lt;em&gt;writable&lt;/em&gt; (size 0) e 1 container teve escrita:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker ps &lt;span class="nt"&gt;-as&lt;/span&gt;
CONTAINER ID   IMAGE     COMMAND   CREATED          STATUS                      PORTS     NAMES             SIZE
789d0f43e596   alpine    &lt;span class="s2"&gt;"sh"&lt;/span&gt;      6 seconds ago    Exited &lt;span class="o"&gt;(&lt;/span&gt;0&lt;span class="o"&gt;)&lt;/span&gt; 5 seconds ago              upbeat_rubin      0B &lt;span class="o"&gt;(&lt;/span&gt;virtual 5.58MB&lt;span class="o"&gt;)&lt;/span&gt;
fee34efca016   alpine    &lt;span class="s2"&gt;"sh"&lt;/span&gt;      10 seconds ago   Exited &lt;span class="o"&gt;(&lt;/span&gt;0&lt;span class="o"&gt;)&lt;/span&gt; 8 seconds ago              reverent_kalam    0B &lt;span class="o"&gt;(&lt;/span&gt;virtual 5.58MB&lt;span class="o"&gt;)&lt;/span&gt;
40c0882f562d   alpine    &lt;span class="s2"&gt;"sh"&lt;/span&gt;      14 seconds ago   Exited &lt;span class="o"&gt;(&lt;/span&gt;0&lt;span class="o"&gt;)&lt;/span&gt; 12 seconds ago             upbeat_sinoussi   0B &lt;span class="o"&gt;(&lt;/span&gt;virtual 5.58MB&lt;span class="o"&gt;)&lt;/span&gt;
90b23b31f6aa   alpine    &lt;span class="s2"&gt;"sh"&lt;/span&gt;      56 seconds ago   Exited &lt;span class="o"&gt;(&lt;/span&gt;0&lt;span class="o"&gt;)&lt;/span&gt; 29 seconds ago             musing_swirles    6.89MB &lt;span class="o"&gt;(&lt;/span&gt;virtual 12.5MB&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quanto de espaço em disco total estamos consumindo em nosso &lt;em&gt;host&lt;/em&gt;, em relação às &lt;em&gt;layers&lt;/em&gt;? A respostá é 12,5Mb.&lt;/p&gt;

&lt;h2&gt;
  
  
  CoW: Copy on Write
&lt;/h2&gt;

&lt;p&gt;Agora que sabemos quais &lt;em&gt;layers&lt;/em&gt; são &lt;em&gt;read-only&lt;/em&gt; e quais são &lt;em&gt;read-write&lt;/em&gt;, vamos &lt;em&gt;meter mão na massa&lt;/em&gt; para entender um conceito: CoW. &lt;/p&gt;

&lt;p&gt;Tomemos como exemplo o conteúdo do arquivo &lt;code&gt;file1.txt&lt;/code&gt; e do &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#file1.txt&lt;/span&gt;
Primeira linha
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#Dockerfile&lt;/span&gt;
FROM alpine
WORKDIR /exemplo
COPY file1.txt &lt;span class="nb"&gt;.&lt;/span&gt;
RUN &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"segunda linha"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; file1.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Realizando o build da imagem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker build -t exemplo:01 .

Step 1/4 : FROM alpine
latest: Pulling from library/alpine
801bfaa63ef2: Pull complete
Digest: sha256:3c7497bf0c7af93428242d6176e8f7905f2201d8fc5861f45be7a346b5f23436
Status: Downloaded newer image for alpine:latest
 ---&amp;gt; 389fef711851
Step 2/4 : WORKDIR /exemplo
 ---&amp;gt; Running in 90cd105624a7
Removing intermediate container 90cd105624a7
 ---&amp;gt; f1b5e463de89
Step 3/4 : COPY file1.txt .
 ---&amp;gt; 6d149ef7f9fd
Step 4/4 : RUN echo "segunda linha" &amp;gt;&amp;gt; file1.txt
 ---&amp;gt; Running in 536635e86c81
Removing intermediate container 536635e86c81
 ---&amp;gt; c741d831be62
Successfully built c741d831be62
Successfully tagged exemplo:01
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tranquilo perceber que as 4 instruções criaram &lt;em&gt;layers&lt;/em&gt; e que todas elas são &lt;em&gt;filesystem layers&lt;/em&gt;, concorda? Nossa imagem, no final, possui 05 layers sendo 02 provenientes da imagem alpine (instrução &lt;code&gt;FROM&lt;/code&gt;) e 3 layers das instruções adicionais:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker image history exemplo:01

IMAGE          CREATED              CREATED BY                                      SIZE      COMMENT
c741d831be62   About a minute ago   /bin/sh -c echo "segunda linha" &amp;gt;&amp;gt; file1.txt    29B
6d149ef7f9fd   About a minute ago   /bin/sh -c #(nop) COPY file:91615d60f2e8bc41…   15B
f1b5e463de89   About a minute ago   /bin/sh -c #(nop) WORKDIR /exemplo              0B
389fef711851   2 weeks ago          /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B
&amp;lt;missing&amp;gt;      2 weeks ago          /bin/sh -c #(nop) ADD file:ec475c2abb2d46435…   5.58MB

$ docker image inspect exemplo:01 --format='{{.RootFS}}'

{layers [
    sha256:777b2c648970480f50f5b4d0af8f9a8ea798eea43dbcf40ce4a8c7118736bdcf 
    sha256:cd894f30417890083791614709bacc9b0f771366be38bda720ea6f622b02ad1c 
    sha256:8062d1a8dd2c9a137a8d0e90bff7d94511f014bb37f8fafb22edad46b4ca2cbe 
    sha256:2bc55ad19ad6d5fb5992402b70becd7e6973dc69ed10ce36a59681815cf9bd78
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Olhemos as nossas 4 &lt;em&gt;filesystem layers&lt;/em&gt; armazenadas em nosso diretório de armazenamento das layers no Docker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ll /var/lib/docker/overlay2
drwx------. 5 matheus root     69 Jan  2 10a4d6010850c9ea40dc684d7ec90d5e0cf90d790d06b8be9365f54465bd426c
drwx------. 5 matheus root     69 Jan  2 14be73d49e9d43672ee62a42250873a6eb4d8994d28d7f2d40228dc548de3735
drwx------. 5 matheus root     69 Jan  2 86899162aaea64b2c0e2ab86279f4f21d41317bbe9566df29d6362cb770c2bff
drwx------. 5 matheus root     69 Jan  2 aada6a14754e4e648f22adcc5f92b2c744dbc0e12db5f5f622300db6127a0046
drwx------. 2 matheus root   8192 Jan  9 l
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;em&gt;layer&lt;/em&gt; do alpine é a pasta &lt;code&gt;14be73d49e9d43...&lt;/code&gt; e temos parte de seu conteúdo mostrado abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ll /var/lib/docker/overlay2/14be73d49e9d43672ee62a42250873a6eb4d8994d28d7f2d40228dc548de3735/diff
drwx------. 5 matheus root     69 Jan  2 bin
drwx------. 5 matheus root     69 Jan  2 dev
drwx------. 5 matheus root     69 Jan  2 etc
drwx------. 5 matheus root     69 Jan  2 home
drwx------. 5 matheus root     69 Jan  2 lib
drwx------. 5 matheus root     69 Jan  2 media
drwx------. 5 matheus root     69 Jan  2 mnt
...

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A conteúdo gerado pela instrução &lt;code&gt;WORKDIR /exemplo&lt;/code&gt; apenas criou a pasta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ll /var/lib/docker/overlay2/10a4d6010850c9ea40dc684d7ec90d5e0cf90d790d06b8be9365f54465bd426c/diff
drwx------. 5 matheus root     69 Jan  2 exemplo


&lt;span class="nv"&gt;$ &lt;/span&gt;ll /var/lib/docker/overlay2/10a4d6010850c9ea40dc684d7ec90d5e0cf90d790d06b8be9365f54465bd426c/diff/exemplo
drwx------. 5 matheus root     69 Jan  2 ./
drwx------. 5 matheus root     69 Jan  2 ../
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Já na &lt;em&gt;layer&lt;/em&gt; &lt;code&gt;86899162a...&lt;/code&gt;, temos o arquivo copiado pela instrução &lt;code&gt;COPY file1.txt&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ll /var/lib/docker/overlay2/86899162aaea64b2c0e2ab86279f4f21d41317bbe9566df29d6362cb770c2bff/diff/exemplo/
&lt;span class="nt"&gt;-rwx------&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; 5 matheus root     69 Jan  2 file1.txt

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /var/lib/docker/overlay2/86899162aaea64b2c0e2ab86279f4f21d41317bbe9566df29d6362cb770c2bff/diff/exemplo/file1.txt
primeira linha
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enquanto na &lt;em&gt;layer&lt;/em&gt; pertencente à instrução &lt;code&gt;RUN&lt;/code&gt;, temos o novo arquivo &lt;code&gt;file1.txt&lt;/code&gt; persistido:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ll /var/lib/docker/overlay2/aada6a14754e4e648f22adcc5f92b2c744dbc0e12db5f5f622300db6127a0046/diff/exemplo/
&lt;span class="nt"&gt;-rwx------&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; 5 matheus root     69 Jan  2 file1.txt


&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /var/lib/docker/overlay2/aada6a14754e4e648f22adcc5f92b2c744dbc0e12db5f5f622300db6127a0046/diff/exemplo/file1.txt
primeira linha
segunda linha
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perceba que o arquivo &lt;code&gt;file1.txt&lt;/code&gt; está presente em 2 &lt;em&gt;layers&lt;/em&gt; diferentes e por conseguinte em 2 diretórios no &lt;em&gt;filesystem&lt;/em&gt;,  pois foi "tocado" por 2 instruções que o criou/modificou.&lt;/p&gt;

&lt;p&gt;CoW é exatamente este comportamento: &lt;strong&gt;Copy on Write&lt;/strong&gt;. Quando uma &lt;em&gt;layer&lt;/em&gt; precisa modificar um arquivo/diretório, este é copiado para dentro da nova &lt;em&gt;layer&lt;/em&gt; e então, modificado. Já quando há apenas leitura de um objeto, esta ação é realizada na &lt;em&gt;layer&lt;/em&gt; em que o arquivo/diretório é encontrado.&lt;/p&gt;

&lt;p&gt;O exemplo acima mostrou o &lt;em&gt;CoW&lt;/em&gt; no momento do &lt;em&gt;build&lt;/em&gt; de uma imagem, mas o processo também acontece quando um container está em execução e precisa modificar um arquivo/dietório, afinal, o container também possui sua &lt;em&gt;layer&lt;/em&gt;, lembra? O objeto é copiado para a &lt;em&gt;top layer&lt;/em&gt; (container) e nela realizadas suas modificações.&lt;/p&gt;

&lt;p&gt;Veja o exemplo abaixo, em que é instanciado um container a partir da imagem &lt;code&gt;exemplo:01&lt;/code&gt;, que altera o arquivo &lt;code&gt;file1.txt&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker container run exemplo:01 /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'echo "linha escrita pelo container" &amp;gt;&amp;gt; /exemplo/file1.txt'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O container acima é instanciado e por causa de sua instrução, copia o arquivo para sua layer e efetua a modificação. Podemos ver a &lt;em&gt;layer&lt;/em&gt; do container abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ll /var/lib/docker/overlay2/cdc6c284aef2e9dfac02c905c2aa3dda3d9e11d3ef37bd9d2d15fe4429dd9519/diff/exemplo/
&lt;span class="nt"&gt;-rwx------&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; 5 matheus root     69 Jan  2 file1.txt


&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /var/lib/docker/overlay2/cdc6c284aef2e9dfac02c905c2aa3dda3d9e11d3ef37bd9d2d15fe4429dd9519/diff/exemplo/file1.txt
primeira linha
segunda linha
linha escrita pelo container
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enquanto o container estiver presente no &lt;em&gt;host&lt;/em&gt;, sua &lt;em&gt;layer&lt;/em&gt; estará também presente (e consumindo espaço em disco).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;CoW acontece tanto no momento do build de uma imagem, quanto na execução de um container, quando este precisa alterar um arquivo/diretório.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Aqui neste ponto, já podemos pensar que é uma boa prática, &lt;strong&gt;reduzir ao máximo o número de layers em que um arquivo aparece&lt;/strong&gt;, ou seja, concentrar o máximo possível as modificações de um arquivo na mesma layer que o criou, para evitar aumento de espaço em disco. Nem sempre é possível, mas quanto mais alcançar tal objetivo, melhor a utilização/consumo de espaço.&lt;/p&gt;

&lt;p&gt;Um outro aprendizado que podemos ter é que a camada do container &lt;strong&gt;inicia-se sempre com o menor tamanho possível&lt;/strong&gt;, e somente quando precisa-se modificar um objeto, há o aumento de tamanho desta camada.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OBS&lt;/strong&gt;: o modo como o &lt;strong&gt;Copy on Write&lt;/strong&gt; é implementado pode variar a depender do &lt;a href="https://docs.docker.com/storage/storagedriver/#copying-makes-containers-efficient"&gt;Storage Driver&lt;/a&gt; implementado. Entretanto, a estratégia e objetivo é sempre este: leitura na camada onde o objeto se encontra em seu estado mais recente (de acordo com a ordem das camadas na imagem) e cópia do objeto para a alteração.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dive: Visualizando melhor as Layers
&lt;/h2&gt;

&lt;p&gt;Neste post e em outros, sempre recorri à comandos docker como &lt;code&gt;history&lt;/code&gt; ou &lt;code&gt;inspect&lt;/code&gt; para visualizar as &lt;em&gt;layers&lt;/em&gt;, além claro, de visualizar as modificações no &lt;em&gt;filesystem&lt;/em&gt; lá no diretório &lt;code&gt;/var/lib/docker/overlay2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;O &lt;a href="https://github.com/wagoodman/dive"&gt;Dive&lt;/a&gt; é uma ferramenta externa bem legal que auxilia bastante na exploração de uma imagem docker, conteúdo das camadas, além de ajudar na descoberta de alternativas para melhorar o tamanho de suas imagens. O legal é que você pode rodar ela como container!&lt;/p&gt;

&lt;p&gt;Uma vez instalado o &lt;em&gt;Dive&lt;/em&gt;, basta apenas chamar ele passando a imagem: &lt;code&gt;dive &amp;lt;image&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Página da ferramenta &lt;strong&gt;Dive&lt;/strong&gt;: &lt;a href="https://github.com/wagoodman/dive"&gt;https://github.com/wagoodman/dive&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Vamos utilizar o &lt;em&gt;Dive&lt;/em&gt; em container. Para melhorar a usabilidade, eu criei o seguinte &lt;em&gt;alias&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;dive&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'sudo docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock wagoodman/dive'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E agora, posso analisar a imagem &lt;code&gt;exemplo:01&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;dive imagem:01
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A saída é no próprio terminal, onde vc tem várias opções para melhorar a análise e investigação das &lt;em&gt;layers&lt;/em&gt;. Na imagem abaixo, analisando a &lt;em&gt;layer&lt;/em&gt; referente à instrução &lt;code&gt;COPY&lt;/code&gt;de nossa imagem, consigo visualizar quais arquivos foram adicionados/removidos/modificados, inclusive com destaque de cores para cada cenário.&lt;/p&gt;

&lt;p&gt;Vale a pena conferir!&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;a href="https://postimg.cc/8f6vQ3VS"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--p4WPw_T5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.postimg.cc/MHsmR2Pv/dive001.png" alt="dive001.png"&gt;&lt;/a&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Analisando a imagem exemplo:01 com o Dive&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Em grandes empresas, com muitos times, produtos e/ou serviços, a tendência é uma alta quantidade de imagens gerenciadas. Para que isso não vire um problema, atentar-se para o tamanho das imagens, a relação entre elas (imagens que são construídas a partir de outras), o número de &lt;em&gt;layers&lt;/em&gt; que as formam, além de claro, como cada &lt;em&gt;layer&lt;/em&gt; é construída são alguns pontos de atenção. Um melhor entendimento sobre &lt;em&gt;Layers&lt;/em&gt; e suas categorizações podem auxiliar nos processos de trabalho sobre estes pontos.&lt;/p&gt;

&lt;p&gt;Abraços!&lt;/p&gt;

&lt;p&gt;:D&lt;/p&gt;

&lt;p&gt;Post originalmente publicado em meu site pessoal&lt;br&gt;
&lt;a href="https://matheuslao.dev/posts/docker-images-ro-rw-layers-cow-dive/"&gt;https://matheuslao.dev/posts/docker-images-ro-rw-layers-cow-dive/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>container</category>
      <category>dockerfile</category>
      <category>layers</category>
    </item>
    <item>
      <title>Docker Images, Empty Layers e FileSystem Layers</title>
      <dc:creator>Matheus Andrade</dc:creator>
      <pubDate>Sat, 02 Jan 2021 15:14:01 +0000</pubDate>
      <link>https://forem.com/matheuslao/docker-images-empty-layers-e-filesystem-layers-43g2</link>
      <guid>https://forem.com/matheuslao/docker-images-empty-layers-e-filesystem-layers-43g2</guid>
      <description>&lt;p&gt;Saudações!&lt;/p&gt;

&lt;p&gt;Containers não são mais novidades. Hoje, Devs e Ops lidam diariamente com aplicações containerizadas e são responsáveis pela construção da imagem da aplicação a ser implantada em produção.&lt;/p&gt;

&lt;p&gt;Mas, &lt;strong&gt;como anda o processo de construção das imagens das aplicações de sua empresa&lt;/strong&gt;? Todos os membros do time compreendem o que acontece no &lt;em&gt;building&lt;/em&gt; de uma imagem? Há uma busca por otimizações em reaproveitamento, consumo de espaço em disco, processos de atualização das imagens de todos os apps?&lt;/p&gt;

&lt;p&gt;Entender imagens (de containers) e construí-las de forma otimizada não é tão trivial para um iniciante no assunto, mas também nada tão difícil. Pensando nisso, tentarei publicar em alguns posts informações que achei interessante durante meu aprendizado.&lt;/p&gt;

&lt;p&gt;O assunto desta publicação é &lt;strong&gt;Layers&lt;/strong&gt;, principalmente por causa de uma dúvida que aparece muito nas equipes de trabalho:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Afinal, quais instruções do Dockerfile geram Layers e/ou aumentam o espaço em disco consumido?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;O conceito de &lt;em&gt;layers&lt;/em&gt; nem sempre está atrelado à existência de alterações no sistema de arquivos (&lt;em&gt;filesystem layers&lt;/em&gt;);&lt;/li&gt;
&lt;li&gt;Nem todas as instruções do Dockerfile geram layers (sejam quais forem) . Exemplo: instrução &lt;code&gt;ARG&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Nem sempre a instrução &lt;code&gt;RUN&lt;/code&gt; gera uma &lt;em&gt;filesystem layer&lt;/em&gt;, como aparentemente indica a documentação;&lt;/li&gt;
&lt;li&gt;Outras instruções podem gerar uma &lt;em&gt;filesystem layer&lt;/em&gt; como a &lt;code&gt;WORKDIR&lt;/code&gt;, e não somente &lt;code&gt;RUN, COPY e ADD&lt;/code&gt; como, aparentemente, indica uma página da documentação.&lt;/li&gt;
&lt;li&gt;Atentar-se sempre ao contexto da palavra &lt;em&gt;layer&lt;/em&gt; presente nos livros, documentação, etc., pois podem referenciar somente &lt;em&gt;filesystem layers&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  O que é uma Imagem Docker?
&lt;/h2&gt;

&lt;p&gt;Fui procurar na documentação oficial da Docker o conceito de &lt;strong&gt;imagem&lt;/strong&gt;. No &lt;a href="https://docs.docker.com/glossary/"&gt;Glossário&lt;/a&gt;, temos a seguinte definição:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Docker images are the basis of containers. An Image is an ordered collection of root filesystem changes and the corresponding execution parameters for use within a container runtime. An image typically contains a union of layered filesystems stacked on top of each other. An image does not have state and it never changes."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Praticamente diz tudo. Aqui deixo a minha tradução livre:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;coleção &lt;strong&gt;ordenada&lt;/strong&gt; de &lt;strong&gt;mudanças imutáveis&lt;/strong&gt; no &lt;strong&gt;sistema de arquivos&lt;/strong&gt; mais &lt;strong&gt;parâmetros de execução&lt;/strong&gt; em &lt;strong&gt;camadas empilhadas&lt;/strong&gt; umas sobre as outras;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Na grande maioria dos casos, estas camadas são construídas através das instruções presentes no famoso arquivo &lt;strong&gt;Dockerfile&lt;/strong&gt;. &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LKMxUxGp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/2520/1%2Ap8k1b2DZTQEW_yf0hYniXw.png" alt="dockerfile-como-origem-para-contrucao-imagem"&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Fonte: &lt;a href="https://medium.com/platformer-blog/practical-guide-on-writing-a-dockerfile-for-your-application-89376f88b3b5"&gt;https://medium.com/platformer-blog/practical-guide-on-writing-a-dockerfile-for-your-application-89376f88b3b5&lt;/a&gt;&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;PS: Não gosto nem de lembrar, mas temos que assumir que existe outro método de gerar imagens, a partir de containers: &lt;em&gt;docker commit&lt;/em&gt;. :D&lt;/p&gt;

&lt;h2&gt;
  
  
  O que são Layers?
&lt;/h2&gt;

&lt;p&gt;Recorrendo novamente ao &lt;a href="https://docs.docker.com/glossary/"&gt;Glossário do Docker&lt;/a&gt; temos:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"In an image, a layer is modification to the image, represented by an instruction in the Dockerfile. Layers are applied in sequence to the base image to create the final image. When an image is updated or rebuilt, only layers that change need to be updated, and unchanged layers are cached locally. This is part of why Docker images are so fast and lightweight. The sizes of each layer add up to equal the size of the final image."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Aqui, mais uma vez, deixo minha tradução livre e resumida do que considero importante:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Modificação&lt;/strong&gt; da imagem representada por uma &lt;strong&gt;instrução do Dockerfile&lt;/strong&gt; aplicadas em &lt;strong&gt;sequência&lt;/strong&gt; à imagem base para criar outra imagem final.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Repare que é bem sutil (e por isso, confuso numa primeira vez) o conceito de Layer e Imagem. Muitas vezes usamos a definição de &lt;em&gt;layer&lt;/em&gt; para imagem, concorda? &lt;/p&gt;

&lt;p&gt;Podemos, por exemplo, afirmar que &lt;strong&gt;1 layer é uma imagem intermediária&lt;/strong&gt;, já que o empilhamento ordenado de N camadas representará a &lt;strong&gt;imagem final&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Guardemos, por ora, que uma &lt;strong&gt;imagem é um agrupamento ordenado de layers e estas são as modificações imutáveis, resultados de instruções presentes no Dockerfile.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Layers: Quantas são?
&lt;/h2&gt;

&lt;p&gt;Vamos visualizar, metendo a "mão na massa"! Baixemos uma das imagens mais famosas (e menores) que existem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker image pull alpine
Using default tag: latest
latest: Pulling from library/alpine
801bfaa63ef2: Pulling fs layer
801bfaa63ef2: Verifying Checksum
801bfaa63ef2: Download &lt;span class="nb"&gt;complete
&lt;/span&gt;801bfaa63ef2: Pull &lt;span class="nb"&gt;complete
&lt;/span&gt;Digest: sha256:3c7497bf0c7af93428242d6176e8f7905f2201d8fc5861f45be7a346b5f23436
Status: Downloaded newer image &lt;span class="k"&gt;for &lt;/span&gt;alpine:latest
docker.io/library/alpine:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pela saída de texto do comando acima executado, podemos verificar que &lt;strong&gt;1 layer&lt;/strong&gt;, identificada pelo &lt;em&gt;hash 801bfaa63ef2&lt;/em&gt;, foi baixada. Vamos rodar o comando &lt;code&gt;inspect&lt;/code&gt;, fazendo um filtro no formato de saída:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker image inspect alpine &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{{.RootFS}}'&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;layers &lt;span class="o"&gt;[&lt;/span&gt;sha256:777b2c648970480f50f5b4d0af8f9a8ea798eea43dbcf40ce4a8c7118736bdcf] &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O retorno também é &lt;strong&gt;1 layer&lt;/strong&gt;, identificada por um &lt;em&gt;hash sha256&lt;/em&gt;. Se formos mais curiosos, encontraremos a camada baixada no sistema de arquivos, onde o Docker a armazena (usando Linux, &lt;a href="https://docs.docker.com/storage/storagedriver/"&gt;storage driver overlay2&lt;/a&gt; e sem alteração do local de instalação do Docker):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ll /var/lib/docker/overlay2/
drwx------. 5 matheus root     69 Oct 19 b29be06af013d08aa3a729693e9368e2b43f3a7fd4de362caaaee93ef3dc2c59
drwx------. 2 matheus root   8192 Nov  9 l
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perceba que apenas 1 pasta identificada por um &lt;em&gt;hash&lt;/em&gt; está presente. E despreze que os &lt;em&gt;hashes&lt;/em&gt; não batem, pois não é mesmo pra acontecer.&lt;/p&gt;

&lt;p&gt;Agora, vamos utilizar o comando &lt;code&gt;history&lt;/code&gt; para dissecar um pouco mais a imagem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker image &lt;span class="nb"&gt;history &lt;/span&gt;alpine
IMAGE          CREATED       CREATED BY                                      SIZE      COMMENT
389fef711851   2 weeks ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  CMD ["/bin/sh"]              0B&lt;/span&gt;
&amp;lt;missing&amp;gt;      2 weeks ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop) ADD file:ec475c2abb2d46435ÔÇª   5.58MB&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Desprezando a falta do identificador da &lt;em&gt;layer&lt;/em&gt; mais baixa (&lt;code&gt;&amp;lt;missing&amp;gt;&lt;/code&gt; que explicarei em outro post), verificamos que a imagem alpine é &lt;strong&gt;composta por 2 layers&lt;/strong&gt;, cujas instruções de construção são:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ADD file:a4845c3840a3fd0e41e4635a179cce20c81afc6c02e34e3fd5bd2d535698918b &lt;span class="k"&gt;in&lt;/span&gt; / 
CMD &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/bin/sh"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos confirmar também &lt;a href="https://hub.docker.com/layers/alpine/library/alpine/latest/images/sha256-549694ea68340c26d1d85c00039aa11ad835be279bfd475ff4284b705f92c24e?context=explore"&gt;lá no Docker Hub:&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;a href="https://postimg.cc/LqYTWDsQ"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--11yg9-sl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.postimg.cc/XvxzpD6W/alpine-layers-001.png" alt="alpine-layers-001.png"&gt;&lt;/a&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Visualizando as camadas da imagem alpine:latest no Docker Hub&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;E agora? 1 ou 2 camadas na imagem alpine?&lt;/p&gt;

&lt;h2&gt;
  
  
  Empty Layers e FileSystem Layers
&lt;/h2&gt;

&lt;p&gt;A resposta para a pergunta anterior é: 2 camadas!&lt;/p&gt;

&lt;p&gt;A "pegadinha" acontece que apenas 1 camada gera persistência, alteração no sistema de arquivos, enquanto a outra camada é "vazia" em modificação/alteração do &lt;em&gt;filesystem&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Neste ponto, podemos dizer que a camada que vemos o &lt;code&gt;docker pull&lt;/code&gt; baixar (a mesma vista no &lt;code&gt;inspect&lt;/code&gt; e presente no &lt;code&gt;/var/lib/docker/overlay&lt;/code&gt;) pode ser categorizada como uma &lt;strong&gt;FS layer&lt;/strong&gt;, ou seja, uma camada de sistema de arquivos. Já a camada construída pela instrução &lt;code&gt;CMD ["/bin/sh"]&lt;/code&gt; pode ser categorizada como uma &lt;strong&gt;Empty Layer&lt;/strong&gt;, pois não gera alteração no &lt;em&gt;filesystem&lt;/em&gt;, não consumindo espaço, e portanto, não sendo baixada.&lt;/p&gt;

&lt;p&gt;Aqui que reside a confusão conceitual de &lt;em&gt;Layers&lt;/em&gt;. Em versões anteriores do Docker e de construção de imagens, as &lt;em&gt;layers&lt;/em&gt; sempre estavam associadas à &lt;strong&gt;modificações no filesystem&lt;/strong&gt;. Contudo, em versões atuais, há instruções presentes no Dockerfile que &lt;strong&gt;não alteram o filesystem e precisam ser definidas como layers&lt;/strong&gt;, pois fazem parte do processo de construção (empilhamento ordenado de instruções) de uma imagem.&lt;/p&gt;

&lt;p&gt;Lembre-se das definições atuais de Imagens e Layers lá do Glossário do Docker:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;imagens: coleção ordenada de mudanças no &lt;em&gt;filesystem&lt;/em&gt; e parâmetros de execução;&lt;/li&gt;
&lt;li&gt;layers: modificação da imagem, através de uma instrução.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Todas instruções do Dockerfile geram Layers?
&lt;/h2&gt;

&lt;p&gt;Aqui, mais uma vez, vamos meter mão na massa!&lt;/p&gt;

&lt;p&gt;Em uma página da documentação oficial do Docker que versa sobre &lt;a href="https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#minimize-the-number-of-layers"&gt;boas práticas no processo de construção de imagens&lt;/a&gt;, temos a seguinte informação:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Only the instructions RUN, COPY, ADD create layers. Other instructions create temporary intermediate images, and do not increase the size of the build."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Opa, respondido? Talvez. Uma leitura mais atenta e você pode notar que:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RUN, COPY, ADD criam layers;&lt;/li&gt;
&lt;li&gt;outras instruções criam &lt;em&gt;temporary intermediate images&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pelo que já apresentamos, podemos definir &lt;em&gt;layers&lt;/em&gt; como imagens intermediárias, logo, determinadas instruções criariam camadas temporárias que não aumentariam o espaço consumido do &lt;em&gt;build&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Repare que aqui a documentação nos confunde com o conceito de &lt;em&gt;layers&lt;/em&gt;: somente RUN, COPY e ADD criam &lt;strong&gt;filesystem layers&lt;/strong&gt;, enquanto outras não (&lt;em&gt;empty layers&lt;/em&gt;). &lt;/p&gt;

&lt;p&gt;Neste ponto, gostaria de levantar alguma dúvidas para testarmos/validarmos, pois me confundiu muito no início:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dúvida 01: A instrução &lt;code&gt;RUN&lt;/code&gt; sempre vai gerar uma &lt;em&gt;FS Layer&lt;/em&gt; ?&lt;/li&gt;
&lt;li&gt;Dúvida 02: A instrução &lt;code&gt;WORKDIR&lt;/code&gt; quando cria um novo path (uma alteração no &lt;em&gt;filesystem&lt;/em&gt;), geraria uma &lt;em&gt;FS Layer&lt;/em&gt;?&lt;/li&gt;
&lt;li&gt;Dúvida 03: Alguma instrução do Dockerfile não gera Layer (seja filesystem layers ou empty layers)?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vamos testar algumas das principais instruções de utilização na construção de imagens docker para validar os conceitos apresentados e hipóteses levantadas. Todas as instruções possíveis estão presentes no &lt;a href="https://docs.docker.com/engine/reference/builder/"&gt;Dockerfile Reference&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Tomemos como exemplo o Dockerfile abaixo onde tentei utilizar as instruções mais conhecidas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ARG  VERSION=latest
FROM alpine:${VERSION}
LABEL mantainer="matheuslao.dev"
ENV URL "https://artefatos.empresa.com.br/app-1.2.3.jar"
WORKDIR /
RUN addgroup -g 10001 francisco &amp;amp;&amp;amp; adduser -u 10001 francisco -G francisco -s /sbin/nologin --disabled-password
RUN apk add curl \
    &amp;amp;&amp;amp; curl -o app.jar $URL
WORKDIR /myapp
COPY file1.txt .
ADD file2.txt .
RUN export USER="francisco" \
    &amp;amp;&amp;amp; echo $USER
USER francisco
CMD ["/bin/sh"]
ENTRYPOINT ["java", "-XX:+UnlockExperimentalVMOptions", "-Djava.security.egd=file:/dev/./urandom","-jar","app.jar"]
EXPOSE 80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Analisemos o resultado do &lt;em&gt;build&lt;/em&gt; da imagem (saída do comando sem o &lt;a href="https://docs.docker.com/develop/develop-images/build_enhancements/"&gt;buildkit&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker image build -t minha-imagem .

Sending build context to Docker daemon  4.608kB
Step 1/15 : ARG  VERSION=latest
Step 2/15 : FROM alpine:${VERSION}
 ---&amp;gt; 389fef711851
Step 3/15 : LABEL mantainer="matheuslao.dev"
 ---&amp;gt; Running in 7b372ffdfc95
Removing intermediate container 7b372ffdfc95
 ---&amp;gt; 6a5c0a8519d8
Step 4/15 : ENV URL "https://raw.githubusercontent.com/matheuslao/matheuslao.dev/main/static/img/matheuslao.jpg"
 ---&amp;gt; Running in c376576063ff
Removing intermediate container c376576063ff
 ---&amp;gt; 12828b25bdff
Step 5/15 : WORKDIR /
 ---&amp;gt; Running in 65cf9d3a17bb
Removing intermediate container 65cf9d3a17bb
 ---&amp;gt; e3d131d4c8f9
Step 6/15 : RUN addgroup -g 10001 francisco &amp;amp;&amp;amp; adduser -u 10001 francisco -G francisco -s /sbin/nologin --disabled-password
 ---&amp;gt; Running in 1144c1a690da
Removing intermediate container 1144c1a690da
 ---&amp;gt; 370ee1418f66
Step 7/15 : RUN apk add curl     &amp;amp;&amp;amp; curl -o app.jar $URL
 ---&amp;gt; Running in aee90a4a5f09
fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/community/x86_64/APKINDEX.tar.gz
(1/4) Installing ca-certificates (20191127-r4)
(2/4) Installing nghttp2-libs (1.41.0-r0)
(3/4) Installing libcurl (7.69.1-r3)
(4/4) Installing curl (7.69.1-r3)
Executing busybox-1.31.1-r19.trigger
Executing ca-certificates-20191127-r4.trigger
OK: 7 MiB in 18 packages
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 21926  100 21926    0     0  32872      0 --:--:-- --:--:-- --:--:-- 32823
Removing intermediate container aee90a4a5f09
 ---&amp;gt; 5afd3449a399
Step 8/15 : WORKDIR /myapp
 ---&amp;gt; Running in 1e1d3f15d239
Removing intermediate container 1e1d3f15d239
 ---&amp;gt; d1ccd41ed16e
Step 9/15 : COPY file1.txt .
 ---&amp;gt; 476f0884009f
Step 10/15 : ADD file2.txt .
 ---&amp;gt; 8e8b4ed9127d
Step 11/15 : RUN export USER="francisco"     &amp;amp;&amp;amp; echo $USER
 ---&amp;gt; Running in ca95419bbf81
francisco
Removing intermediate container ca95419bbf81
 ---&amp;gt; 4b75a0feb0de
Step 12/15 : USER francisco
 ---&amp;gt; Running in a510fe377aff
Removing intermediate container a510fe377aff
 ---&amp;gt; 562d417df13d
Step 13/15 : CMD ["/bin/sh"]
 ---&amp;gt; Running in c7db6aabcd80
Removing intermediate container c7db6aabcd80
 ---&amp;gt; 0054ff10e607
Step 14/15 : ENTRYPOINT ["java", "-XX:+UnlockExperimentalVMOptions", "-Djava.security.egd=file:/dev/./urandom","-jar","app.jar"]
 ---&amp;gt; Running in fc1f9065fc21
Removing intermediate container fc1f9065fc21
 ---&amp;gt; 5c7cd86d14a3
Step 15/15 : EXPOSE 80
 ---&amp;gt; Running in fa19fc0c27e3
Removing intermediate container fa19fc0c27e3
 ---&amp;gt; 986b3c714918
Successfully built 986b3c714918
Successfully tagged minha-imagem:latest


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;São 15 instruções em nosso Dockerfile que geram 15 steps (passos) no build:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Step 1/15: Repare que nenhuma informação adicional é gerada como a criação/geração de uma &lt;strong&gt;layer&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;Step 2/15: A &lt;strong&gt;FS Layer&lt;/strong&gt; da imagem alpine é referenciada aqui (mas já sabemos que no fundo, a imagem alpine possui 2 layers);&lt;/li&gt;
&lt;li&gt;Step 3/15: Um container de hash 7b372ffdfc95 sobe, executa a instrução, morre e uma layer de hash 6a5c0a8519d8 é gerada;&lt;/li&gt;
&lt;li&gt;Step 4/15: Um container sobe, executa a instrução, morre e uma layer é gerada;&lt;/li&gt;
&lt;li&gt;Step 5/15: Um container sobe, executa a instrução, morre e uma layer é gerada;&lt;/li&gt;
&lt;li&gt;Step 6/15: Um container sobe, executa a instrução, morre e uma layer é gerada;&lt;/li&gt;
&lt;li&gt;Step 7/15: Um container sobe, executa a instrução, morre e uma layer é gerada;&lt;/li&gt;
&lt;li&gt;Step 8/15: Um container sobe, executa a instrução, morre e uma layer é gerada;&lt;/li&gt;
&lt;li&gt;Step 9/15: Uma layer é gerada com a transferência do arquivo copiado;&lt;/li&gt;
&lt;li&gt;Step 10/15: Uma layer é gerada com a transferência do arquivo adicionado;&lt;/li&gt;
&lt;li&gt;Step 11/15: Um container sobe, executa a instrução, morre e uma layer é gerada;&lt;/li&gt;
&lt;li&gt;Step 12/15: Um container sobe, executa a instrução, morre e uma layer é gerada;&lt;/li&gt;
&lt;li&gt;Step 13/15: Um container sobe, executa a instrução, morre e uma layer é gerada;&lt;/li&gt;
&lt;li&gt;Step 14/15: Um container sobe, executa a instrução, morre e uma layer é gerada;&lt;/li&gt;
&lt;li&gt;Step 15/15: Um container sobe, executa a instrução, morre e uma layer é gerada;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A Dúvida 03 já tem um candidato para a resposta:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Com exceção da instrução &lt;code&gt;ARG&lt;/code&gt;, todas as outras utilizadas geraram layers.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Vamos utilizar o &lt;code&gt;history&lt;/code&gt; para validar/confirmar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker image &lt;span class="nb"&gt;history &lt;/span&gt;minha-imagem

IMAGE          CREATED              CREATED BY                                      SIZE      COMMENT
9f338caaa516   About a minute ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  EXPOSE 80                    0B&lt;/span&gt;
6449ad4000e5   About a minute ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  ENTRYPOINT ["java" "-XX:+…   0B&lt;/span&gt;
65a889958083   About a minute ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  CMD ["/bin/sh"]              0B&lt;/span&gt;
1abacd6cfbe6   About a minute ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  USER francisco               0B&lt;/span&gt;
2a1a85501e97   About a minute ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"francisco"&lt;/span&gt;     &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ec…   0B
f055068ccc6c   About a minute ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop) ADD file:328c2a0fff8f5e953…   10B&lt;/span&gt;
6085fb888a33   About a minute ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop) COPY file:bb441069227b280c…   10B&lt;/span&gt;
cba01884fddf   About a minute ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop) WORKDIR /myapp                0B&lt;/span&gt;
9a12d9d412ae   About a minute ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; apk add curl     &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; curl &lt;span class="nt"&gt;-o&lt;/span&gt; app.j…   3.12MB
8f54af3a2563   About a minute ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; addgroup &lt;span class="nt"&gt;-g&lt;/span&gt; 10001 francisco &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ad…   4.7kB
cb8c60e24f29   About a minute ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop) WORKDIR /                     0B&lt;/span&gt;
bfe0e88f7ca5   About a minute ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  ENV URL=https://raw.githu…   0B&lt;/span&gt;
d1ba00e0a9d5   About a minute ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  LABEL mantainer=matheusla…   0B&lt;/span&gt;
389fef711851   2 weeks ago          /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  CMD ["/bin/sh"]              0B&lt;/span&gt;
&amp;lt;missing&amp;gt;      2 weeks ago          /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop) ADD file:ec475c2abb2d46435…   5.58MB&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;É fácil visualizar a presença de 16 layers, concorda? Também não é dificíl dizer que as 2 primeiras layers (de baixo pra cima) são as layers da imagem base alpine. Assim, temos 14 layers registradas adicionalmente (ordenadas e empilhadas conforme instruções) que batem com os 14 steps que geraram-as.&lt;/p&gt;

&lt;p&gt;Analisemos agora o tamanho das &lt;em&gt;layers&lt;/em&gt;. Baseado na experiência anterior, afirmaríamos que 05 são &lt;strong&gt;FS Layers&lt;/strong&gt;, pois possuem tamanho &amp;gt; 0.&lt;/p&gt;

&lt;p&gt;Vamos validar?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker image inspect minha-imagem --format='{{.RootFS}}'

{layers [
    sha256:777b2c648970480f50f5b4d0af8f9a8ea798eea43dbcf40ce4a8c7118736bdcf 
    sha256:9caf12dafc34f81365ffeefa58af5c52eb19e6e58260158f8931f51223a025a6 
    sha256:e184369701b73ed92ccb30cb4e4f34cc817a6093bfb35ec6b6a9a36946f841fd 
    sha256:ac91c339ff12c9965379a1eeac8ff51cdf9a4f1d3f229316650aa4d7e2d81bc3 
    sha256:3449aa1a02c6e90dae7e4785fd52b5b1b09128ee73e88f76fa6149fb2746bfe2 
    sha256:cfbf011495adad103cc9c9b6c7f8d9525427a3f90b34d49a6db1cf5cde812f09
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Oh, não! São 06 camadas!&lt;/p&gt;

&lt;p&gt;Vamos procurar lá em nossa pasta &lt;code&gt;/var/lib/docker/overlay2&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ll /var/lib/docker/overlay2/
drwx------. 5 matheus root     69 Oct 19 b29be06af013d08aa3a729693e9368e2b43f3a7fd4de362caaaee93ef3dc2c59
drwx------. 5 matheus root     69 Oct 19 6efd98d05213572a70e59f16840758d6072c7298f42621609cd7b286354cda9b
drwx------. 5 matheus root     69 Oct 19 46b740c355ed78e37fa9f6af8a94c23f63b1ed00d98e797d9468e557d67620f4
drwx------. 5 matheus root     69 Oct 19 090b364761d9bd50b7d634cf3aecd17794a8264d24d430c198e69deea5d54f5c
drwx------. 5 matheus root     69 Oct 19 335aa592cb4a89b7165017f78c7b01a0b92c5df78a91c9ceb569c56520f13329
drwx------. 5 matheus root     69 Oct 19 d7f4b90503fa2bba199564c7714d553080bb45ed1425501da8cdd698208a0803
drwx------. 2 matheus root   8192 Nov  9 l
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Novamente, 06 camadas!&lt;/p&gt;

&lt;p&gt;Tínhamos uma hipótese se a instrução &lt;code&gt;WORKDIR&lt;/code&gt; quando cria um diretório não existente resultaria em uma camada de persistência. Pois bem, apesar do tamanho mostrado lá no comando &lt;code&gt;history&lt;/code&gt; estar &lt;code&gt;SIZE 0&lt;/code&gt;, a instrução &lt;code&gt;WORKDIR /myapp&lt;/code&gt; de nosso Dockerfile cria uma camada no filesystem para persistir.&lt;/p&gt;

&lt;p&gt;Se olharmos o &lt;code&gt;diff&lt;/code&gt;de cada camada (explicarei em outro post), encontrarei uma que representa a instrução em questão. Em nosso exemplo, foi a seguinte layer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ll /var/lib/docker/overlay2/6efd98d05213572a70e59f16840758d6072c7298f42621609cd7b286354cda9b/diff
drwx------. 5 matheus root     69 Oct 19 myapp

ll /var/lib/docker/overlay2/6efd98d05213572a70e59f16840758d6072c7298f42621609cd7b286354cda9b/diff/myapp/
drwx------. 5 matheus root     69 Oct 19 ./
drwx------. 5 matheus root     69 Oct 19 ../
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assim, a Dúvida 02 é respondida com um SIM.&lt;/p&gt;

&lt;p&gt;Por fim, podemos também responder a Dúvida 01. Repare que o &lt;code&gt;Step 11/15&lt;/code&gt;, que é a instrução &lt;code&gt;RUN&lt;/code&gt; executando um &lt;em&gt;export&lt;/em&gt; e um &lt;em&gt;echo&lt;/em&gt; gera uma &lt;em&gt;layer&lt;/em&gt; de tamanho zero. Se você tentar procurar no sistema de arquivos, não vai achar a representação desta instrução também. Assim, podemos perceber que nem sempre a instrução &lt;code&gt;RUN&lt;/code&gt; vai alterar o sistema de arquivos e consequentemente persistir em uma camada &lt;em&gt;FS Layer&lt;/em&gt;, consumindo espaço em disco.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Com a popularização da containerização, entender um pouco mais como dá-se a construção e formação das imagens pode proporcionar condições de melhorias futuras no processo de desenvolvimento e implantação das aplicações.&lt;/p&gt;

&lt;p&gt;Vimos que, para entender o que é uma Imagem Docker, precisamos internalizar o conceito de &lt;em&gt;Layer&lt;/em&gt;, parte fundamental e indissociável de sua formação. Também faz-se importante destacar a interpretação correta e o contexto do termo &lt;em&gt;layer&lt;/em&gt; presentes em livros, documentações, etc, pois muitas vezes referenciam somente à um tipo de layer: aquelas que criam alterações em sistemas de arquivos, consumindo espaço em disco. Contudo, sabemos que na formação de Imagens Docker, há &lt;em&gt;layers&lt;/em&gt; que não geram persistência, mas sim, guardam outras informações cruciais e indispensáveis para a caracterização de uma imagem final.&lt;/p&gt;

&lt;p&gt;Abraços!&lt;/p&gt;

&lt;p&gt;:D&lt;/p&gt;

&lt;p&gt;Post originalmente publicado em meu site pessoal &lt;a href="https://matheuslao.dev/posts/docker-imagens-empty-filesystem-layers/"&gt;https://matheuslao.dev/posts/docker-imagens-empty-filesystem-layers/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>layers</category>
      <category>docker</category>
      <category>dockerfile</category>
      <category>container</category>
    </item>
    <item>
      <title>06 Exemplos de Uso de Credenciais (04 não recomendadas) durante o Build de Imagens Docker</title>
      <dc:creator>Matheus Andrade</dc:creator>
      <pubDate>Wed, 23 Dec 2020 18:59:52 +0000</pubDate>
      <link>https://forem.com/matheuslao/dicas-credenciais-x-imagens-docker-1gdg</link>
      <guid>https://forem.com/matheuslao/dicas-credenciais-x-imagens-docker-1gdg</guid>
      <description>&lt;p&gt;Em quase todo o processo de construção de imagens Docker, há a necessidade de baixar artefatos (ex: zip, war, jar, etc.) de alguma URL para compor a imagem de nossa aplicação. Por vezes, estas URLs exigem autenticação e precisamos de credenciais para ter acesso ao conteúdo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Como construir imagens Docker sem comprometer credenciais, como usuários e senhas de acesso?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Os exemplos abaixo seguirão uma ordem, aparentemente natural de boas práticas, onde há uma preocupação em não expor informação sensível na imagem Docker gerada, além de continuar garantindo sua portabilidade.&lt;/p&gt;

&lt;h3&gt;
  
  
  O Desafio: Contextualizando a situação
&lt;/h3&gt;

&lt;p&gt;Suponha que tenhamos a missão de construir a imagem de uma simples aplicação Java, cujo artefato &lt;em&gt;buildado&lt;/em&gt; encontra-se disponível em uma URL que é o repositório de artefatos de sua empresa. (&lt;a href="https://artefatos.empresa.com.br/"&gt;https://artefatos.empresa.com.br/&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Detalhe 01 : a URL do repositório exige autenticação e você possui as credenciais de acesso.&lt;/p&gt;

&lt;p&gt;Detalhe 02 : a imagem será compatilhada para outras empresas/clientes implantarem a aplicação.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemplo 01: Codando "na mão grande" as credenciais
&lt;/h3&gt;

&lt;p&gt;Eu nem deveria começar por este exemplo, porque acredito que ninguém deve fazer assim. Contudo, vamos evoluindo exemplo a exemplo. Analisemos o &lt;em&gt;Dockerfile&lt;/em&gt; abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;FROM alpine
WORKDIR /
RUN apk add curl
RUN curl &lt;span class="nt"&gt;-u&lt;/span&gt; francisco:abc123 &lt;span class="nt"&gt;-o&lt;/span&gt; app.jar &lt;span class="s2"&gt;"https://artefatos.empresa.com.br/app-1.2.3.jar"&lt;/span&gt;
ENTRYPOINT &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"java"&lt;/span&gt;, &lt;span class="s2"&gt;"-XX:+UnlockExperimentalVMOptions"&lt;/span&gt;, &lt;span class="s2"&gt;"-Djava.security.egd=file:/dev/./urandom"&lt;/span&gt;,&lt;span class="s2"&gt;"-jar"&lt;/span&gt;,&lt;span class="s2"&gt;"app.jar"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se preocupe somente com a segunda linha da intrução &lt;code&gt;RUN&lt;/code&gt;, onde foi escrito literalmente as credenciais de acesso. Nem preciso dizer que isso aqui é &lt;strong&gt;bem ruim&lt;/strong&gt;, não é? Mas vamos &lt;em&gt;buildar&lt;/em&gt; a imagem e taguear com uma versão:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; app:01 &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A partir da imagem gerada (e que será distribuída para outras pessoas), façamos uma inspeção:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker image &lt;span class="nb"&gt;history &lt;/span&gt;app:01
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Está lá, para todo o mundo ver, as credenciais de acesso:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;IMAGE          CREATED         CREATED BY                                      SIZE      COMMENT
e4d60e8650d7   2 minutes ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  ENTRYPOINT ["java" "-XX:+…   0B&lt;/span&gt;
68e3c9068540   2 minutes ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; curl &lt;span class="nt"&gt;-u&lt;/span&gt; francisco:abc123 &lt;span class="nt"&gt;-o&lt;/span&gt; app.j…   1.23kB
c1a9701b7132   5 minutes ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; apk add curl                         3.1MB
c44f6da443d7   5 minutes ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop) WORKDIR /                     0B&lt;/span&gt;
389fef711851   6 days ago      /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  CMD ["/bin/sh"]              0B&lt;/span&gt;
&amp;lt;missing&amp;gt;      6 days ago      /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop) ADD file:ec475c2abb2d46435…   5.58MB&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Exemplo 02: Usando ENVs para as credenciais
&lt;/h3&gt;

&lt;p&gt;Uma evolução do exemplo acima, seria a tentativa de &lt;em&gt;buildar&lt;/em&gt; a imagem com a utilização de &lt;em&gt;ENVs&lt;/em&gt;. Segue o &lt;em&gt;Dockerfile&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;FROM alpine
ENV USER francisco
ENV PASSWORD abc123
WORKDIR /
RUN apk add curl
RUN curl &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="nv"&gt;$USER&lt;/span&gt;:&lt;span class="nv"&gt;$PASSWORD&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; app.jar &lt;span class="s2"&gt;"https://artefatos.empresa.com.br/app-1.2.3.jar"&lt;/span&gt;
ENTRYPOINT &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"java"&lt;/span&gt;, &lt;span class="s2"&gt;"-XX:+UnlockExperimentalVMOptions"&lt;/span&gt;, &lt;span class="s2"&gt;"-Djava.security.egd=file:/dev/./urandom"&lt;/span&gt;,&lt;span class="s2"&gt;"-jar"&lt;/span&gt;,&lt;span class="s2"&gt;"app.jar"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Possa ser que você ache que agora não vai persistir as credenciais de acesso, pois leu que a &lt;a href="https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#minimize-the-number-of-layers"&gt;instrução ENV não cria layer na imagem&lt;/a&gt;. Vamos conferir?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; app:02 &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inspecionando a imagem com o comando &lt;code&gt;docker image inspect app:02&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;...]
 &lt;span class="s2"&gt;"Config"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Hostname"&lt;/span&gt;: &lt;span class="s2"&gt;""&lt;/span&gt;,
            &lt;span class="s2"&gt;"Domainname"&lt;/span&gt;: &lt;span class="s2"&gt;""&lt;/span&gt;,
            &lt;span class="s2"&gt;"User"&lt;/span&gt;: &lt;span class="s2"&gt;""&lt;/span&gt;,
            &lt;span class="s2"&gt;"AttachStdin"&lt;/span&gt;: &lt;span class="nb"&gt;false&lt;/span&gt;,
            &lt;span class="s2"&gt;"AttachStdout"&lt;/span&gt;: &lt;span class="nb"&gt;false&lt;/span&gt;,
            &lt;span class="s2"&gt;"AttachStderr"&lt;/span&gt;: &lt;span class="nb"&gt;false&lt;/span&gt;,
            &lt;span class="s2"&gt;"Tty"&lt;/span&gt;: &lt;span class="nb"&gt;false&lt;/span&gt;,
            &lt;span class="s2"&gt;"OpenStdin"&lt;/span&gt;: &lt;span class="nb"&gt;false&lt;/span&gt;,
            &lt;span class="s2"&gt;"StdinOnce"&lt;/span&gt;: &lt;span class="nb"&gt;false&lt;/span&gt;,
            &lt;span class="s2"&gt;"Env"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"&lt;/span&gt;,
                &lt;span class="s2"&gt;"USER=francisco"&lt;/span&gt;,
                &lt;span class="s2"&gt;"PASSWORD=abc123"&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;,
            &lt;span class="s2"&gt;"Cmd"&lt;/span&gt;: null,
&lt;span class="o"&gt;[&lt;/span&gt;...]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E com o mesmo comando do exemplo anterior &lt;code&gt;docker image history&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;IMAGE          CREATED         CREATED BY                                      SIZE      COMMENT
284ee6fffad5   3 minutes ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  ENTRYPOINT ["java" "-XX:+…"   0B&lt;/span&gt;
904ec10bf219   3 minutes ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; curl &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="nv"&gt;$USER&lt;/span&gt;:&lt;span class="nv"&gt;$PASSWORD&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; app.ja…   14B
cc4d45436465   3 minutes ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; apk add curl                         3.1MB
35e0fe7f8c92   3 minutes ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop) WORKDIR /                     0B&lt;/span&gt;
51c378578679   3 minutes ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  ENV PASSWORD=abc123          0B&lt;/span&gt;
9ab41a3c7fa5   3 minutes ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  ENV USER=francisco           0B&lt;/span&gt;
389fef711851   6 days ago      /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  CMD ["/bin/sh"]              0B&lt;/span&gt;
&amp;lt;missing&amp;gt;      6 days ago      /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop) ADD file:ec475c2abb2d46435…   5.58MB&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Abordarei em outro post, com mais detalhes, as questões de quando &lt;code&gt;layers&lt;/code&gt; são geradas ou não. Por enquanto, nos atentemos que é possível a identificação/visualização das credencenciais com a inspeção da imagem gerada.&lt;/p&gt;

&lt;h3&gt;
  
  
  Código 03: Usando variáveis de ambiente e RUN em uma mesma LAYER
&lt;/h3&gt;

&lt;p&gt;Nova ideia: utilizar variáveis de ambiente junto instrução RUN para a construção de uma única camada (layer) da imagem. O novo Dockerfile ficaria assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;FROM alpine
WORKDIR /
RUN apk add curl
RUN &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"francisco"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"abc123"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; curl &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="nv"&gt;$USER&lt;/span&gt;:&lt;span class="nv"&gt;$PASSWORD&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; app.jar &lt;span class="s2"&gt;"https://artefatos.empresa.com.br/app-1.2.3.jar"&lt;/span&gt;
ENTRYPOINT &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"java"&lt;/span&gt;, &lt;span class="s2"&gt;"-XX:+UnlockExperimentalVMOptions"&lt;/span&gt;, &lt;span class="s2"&gt;"-Djava.security.egd=file:/dev/./urandom"&lt;/span&gt;,&lt;span class="s2"&gt;"-jar"&lt;/span&gt;,&lt;span class="s2"&gt;"app.jar"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Gerando versão 03 da aplicação:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; app:03
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E vamos conferir o resultado, analisando a imagem gerada com o &lt;code&gt;docker image history&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
406c7ce82cf0   37 seconds ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  ENTRYPOINT ["java" "-XX:+…   0B&lt;/span&gt;
325c0a507c68   37 seconds ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"francisco"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;export&lt;/span&gt; …  14B
c1a9701b7132   24 minutes ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; apk add curl                         3.1MB
c44f6da443d7   24 minutes ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop) WORKDIR /                     0B&lt;/span&gt;
389fef711851   6 days ago       /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  CMD ["/bin/sh"]              0B&lt;/span&gt;
&amp;lt;missing&amp;gt;      6 days ago       /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop) ADD file:ec475c2abb2d46435…   5.58MB&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;É... também não deu certo. :( &lt;/p&gt;

&lt;h3&gt;
  
  
  Código 04: Usando ARGS
&lt;/h3&gt;

&lt;p&gt;Conhecemos o atributo &lt;em&gt;ARGS&lt;/em&gt;, 'similar' a &lt;em&gt;ENV&lt;/em&gt;, e percebemos que podemos ganhar uma mobilidade ao passar as credenciais de acesso no comando de execução do &lt;em&gt;build&lt;/em&gt; da imagem (não ter as credenciais escritas no &lt;em&gt;Dockerfile&lt;/em&gt;!)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;FROM alpine
ARG &lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;fake
ARG &lt;span class="nv"&gt;PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;fake
WORKDIR /
RUN apk add curl
RUN curl &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="nv"&gt;$USER&lt;/span&gt;:&lt;span class="nv"&gt;$PASSWORD&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; app.jar &lt;span class="s2"&gt;"https://artefatos.empresa.com.br/app-1.2.3.jar"&lt;/span&gt;
ENTRYPOINT &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"java"&lt;/span&gt;, &lt;span class="s2"&gt;"-XX:+UnlockExperimentalVMOptions"&lt;/span&gt;, &lt;span class="s2"&gt;"-Djava.security.egd=file:/dev/./urandom"&lt;/span&gt;,&lt;span class="s2"&gt;"-jar"&lt;/span&gt;,&lt;span class="s2"&gt;"app.jar"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E o comando para &lt;em&gt;buildar&lt;/em&gt; a imagem seria:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;--build-arg&lt;/span&gt; &lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;francisco &lt;span class="nt"&gt;--build-arg&lt;/span&gt; &lt;span class="nv"&gt;PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;abc123 &lt;span class="nt"&gt;-t&lt;/span&gt; app:04 &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Contudo, ao analisar a imagem com o &lt;code&gt;docker image history&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;IMAGE          CREATED         CREATED BY                                      SIZE      COMMENT
e9956a610c1f   5 minutes ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  ENTRYPOINT ["java" "-XX:+…   0B&lt;/span&gt;
4bcdfdea08f9   5 minutes ago   |2 &lt;span class="nv"&gt;PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;abc123 &lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;francisco /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt;…   14B
1f56fb7ca086   5 minutes ago   |2 &lt;span class="nv"&gt;PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;abc123 &lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;francisco /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt;…   3.1MB
0ccf29f3aadf   5 minutes ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop) WORKDIR /                     0B&lt;/span&gt;
556f62d21750   5 minutes ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  ARG PASSWORD=fake            0B&lt;/span&gt;
a726e9660660   5 minutes ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  ARG USER=fake                0B&lt;/span&gt;
389fef711851   6 days ago      /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  CMD ["/bin/sh"]              0B&lt;/span&gt;
&amp;lt;missing&amp;gt;      6 days ago      /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop) ADD file:ec475c2abb2d46435…   5.58MB&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se olharmos a documentação &lt;a href="https://docs.docker.com/engine/reference/builder/#arg"&gt;neste link&lt;/a&gt;, perceberemos que aconteceu exatamente como o descrito: credenciais ainda visíveis.&lt;/p&gt;

&lt;h3&gt;
  
  
  Código 05: Adicionando Script auxiliar
&lt;/h3&gt;

&lt;p&gt;Podemos tentar fazer um &lt;code&gt;workaround&lt;/code&gt;: utilizar um script intermediário para auxiliar no download do artefato, atrás de uma URL autenticada. Nosso projeto agora ficaria com os seguintes arquivos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dockerfile&lt;/li&gt;
&lt;li&gt;build.sh&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Conteúdo do &lt;em&gt;build.sh&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;
curl &lt;span class="nt"&gt;-u&lt;/span&gt; francisco:abc123 &lt;span class="nt"&gt;-o&lt;/span&gt; app.jar &lt;span class="s2"&gt;"https://artefatos.empresa.com.br/app-1.2.3.jar"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E o &lt;em&gt;Dockerfile&lt;/em&gt;, faz uso do artefato já baixado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;FROM alpine
WORKDIR /
COPY app.jar /
ENTRYPOINT &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"java"&lt;/span&gt;, &lt;span class="s2"&gt;"-XX:+UnlockExperimentalVMOptions"&lt;/span&gt;, &lt;span class="s2"&gt;"-Djava.security.egd=file:/dev/./urandom"&lt;/span&gt;,&lt;span class="s2"&gt;"-jar"&lt;/span&gt;,&lt;span class="s2"&gt;"app.jar"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A sequência de ações seria:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chmod +x build.sh
./build.sh
docker build -t app:05 .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Percebe-se claramente ao inspecionar a imagem que não há credenciais de acesso nela, confere? Coube a um script auxiliar realizar a autenticação (utilizando as credenciais de acesso), baixar o artefato e apresentá-lo ao contexto do build da imagem.&lt;/p&gt;

&lt;p&gt;It works!&lt;/p&gt;

&lt;h3&gt;
  
  
  Código 06: multi-stage builds
&lt;/h3&gt;

&lt;p&gt;Apesar do exemplo anterior ter cumprido seu propósito (imagem docker sem exposição de credenciais sensíveis), tive a sensação (e espero que você também) de que algo ficou estranho: Tivemos que recorrer a arquivos auxiliares, fora do escopo do Docker para resolver o problema.&lt;/p&gt;

&lt;p&gt;Se analisarmos um pouco, basicamente o que fizemos foi dividir o processo de build em 2 estágios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;estágio 01 que baixou os artefatos sob credenciais (script auxiliar)&lt;/li&gt;
&lt;li&gt;estágio 02 que compilou a imagem (Docker)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lendo mais a documentação da Docker, percebemos que podemos fazer similar utilizando o conceito de &lt;a href="https://docs.docker.com/develop/develop-images/multistage-build/"&gt;multi-stage builds&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Nosso Dockerfile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;FROM alpine AS download
ARG USER
ARG PASSWORD
RUN apk add curl
RUN curl &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="nv"&gt;$USER&lt;/span&gt;:&lt;span class="nv"&gt;$PASSWORD&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /app.jar &lt;span class="s2"&gt;"https://artefatos.empresa.com.br/app-1.2.3.jar"&lt;/span&gt;

FROM alpine
WORKDIR /
COPY &lt;span class="nt"&gt;--from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;download /app.jar &lt;span class="nb"&gt;.&lt;/span&gt;
ENTRYPOINT &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"java"&lt;/span&gt;, &lt;span class="s2"&gt;"-XX:+UnlockExperimentalVMOptions"&lt;/span&gt;, &lt;span class="s2"&gt;"-Djava.security.egd=file:/dev/./urandom"&lt;/span&gt;,&lt;span class="s2"&gt;"-jar"&lt;/span&gt;,&lt;span class="s2"&gt;"app.jar"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perceba que fizemos exatamente a mesma coisa, agora usando apenas o Docker: Dividimos nosso build em &lt;em&gt;2 estágios&lt;/em&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no primeiro estágio, uma imagem intermediária é criada (e suas respectivas layers e informações) com o download da aplicação, atrás da autenticação.&lt;/li&gt;
&lt;li&gt;no segundo estágio, a imagem em construção (a oficial) copia apenas o &lt;code&gt;app.jar&lt;/code&gt; da imagem anterior.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fácil perceber que, na imagem final não visualizaremos as credenciais. Além disso, a imagem intermediária é destruída ao final do processo de build.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;IMAGE          CREATED         CREATED BY                                      SIZE      COMMENT
72ef8382df33   3 minutes ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  ENTRYPOINT ["java" "-XX:+…   0B&lt;/span&gt;
32a3816fdcd3   3 minutes ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop) COPY file:297d62e63eaf8490…   14B&lt;/span&gt;
29385377e66f   3 minutes ago   /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop) WORKDIR /                     0B&lt;/span&gt;
389fef711851   6 days ago      /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  CMD ["/bin/sh"]              0B&lt;/span&gt;
&amp;lt;missing&amp;gt;      6 days ago      /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop) ADD file:ec475c2abb2d46435…   5.58MB&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Funciona! E parece-nos uma solução bem inteligente, não acha?&lt;/p&gt;

&lt;h3&gt;
  
  
  PLUS: BuildKit
&lt;/h3&gt;

&lt;p&gt;Uma funcionalidade "nova" no Docker é o uso do &lt;em&gt;BuildKit&lt;/em&gt; para ajudar no manuseio de credenciais durante o processo de construção de imagens.&lt;/p&gt;

&lt;p&gt;Ainda não brinquei com este recurso, assim tentarei em breve atualizar este post com um exemplo adicional.&lt;/p&gt;

&lt;p&gt;Caso deseje ver como funciona, &lt;a href="https://docs.docker.com/develop/develop-images/build_enhancements/"&gt;não deixe de ler a documentação oficial&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Post originalmente publicado em meu site pessoal &lt;a href="https://matheuslao.dev/posts/uso-credenciais-construcao-imagens-docker/"&gt;https://matheuslao.dev/posts/uso-credenciais-construcao-imagens-docker/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>dockerfile</category>
      <category>multistage</category>
      <category>containers</category>
    </item>
  </channel>
</rss>
