<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Computando-Arte on Crimideias do caioau</title>
    <link>https://caioau.net/tags/computando-arte/</link>
    <description>Recent content in Computando-Arte on Crimideias do caioau</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>pt-br</language>
    <copyright>This site is licensed under a CC-BY-SA 4.0 licence</copyright>
    <lastBuildDate>Mon, 16 Feb 2026 10:00:00 -0300</lastBuildDate><atom:link href="https://caioau.net/tags/computando-arte/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Dockerfile: Hardening e boas práticas</title>
      <link>https://caioau.net/blog/dockerfile-hardening/</link><category>computando-arte</category>
		  <category>texto</category>
		  <category>devops</category>
		  <category>docker</category>
		  <category>security</category>
		  <category>sbom</category>
		  <category>chainguard</category>
		  
      <pubDate>Mon, 16 Feb 2026 10:00:00 -0300</pubDate>
      
      <guid>https://caioau.net/blog/dockerfile-hardening/</guid><description>&lt;p&gt;Obs.: Originalmente publicado no &lt;a href=&#34;https://caioau.net/blog/computando-arte/&#34;&gt;computando-arte&lt;/a&gt; dia 28Jan2026&lt;/p&gt;
&lt;p&gt;Dockerfile é tudo igual? Se a imagem está sendo buildada e a aplicação está rodando, posso mandar bala? Vamos ver nesse texto que não. Existem outras considerações a serem feitas, principalmente de segurança. Vamos nos debruçar para encontrar o Dockerfile mínimo contendo apenas o necessário para rodar nosso app em Python.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/dockerfile-hardening/feature-img.png&#34; loading=&#34;lazy&#34;
         alt=&#34;Foto de S. Laiba Ali, unsplash&#34; width=&#34;600px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Foto de S. Laiba Ali, &lt;a href=&#34;https://unsplash.com/photos/blue-red-green-and-yellow-lego-blocks-zncK6BaaDgo&#34;&gt;unsplash&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;nosso-exemplo-api-em-python-com-flask&#34;&gt;Nosso exemplo: API em Python com Flask&lt;/h2&gt;
&lt;p&gt;Nesse texto vamos explorar bastante esse exemplo, que retorna um &amp;ldquo;Hello world&amp;rdquo; simples, e pra fazer uma graça um endpoint que retorna de volta o que foi enviado no caminho da url.&lt;/p&gt;
&lt;p&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d75f00&#34;&gt;from&lt;/span&gt; flask &lt;span style=&#34;color:#d75f00&#34;&gt;import&lt;/span&gt; Flask
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;app = Flask(__name__)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;@app.route&lt;/span&gt;(&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;/hello&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#0087ff&#34;&gt;hello_default&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#5f8700&#34;&gt;return&lt;/span&gt; hello(&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;@app.route&lt;/span&gt;(&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;/hello/&amp;lt;string:hellomsg&amp;gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#0087ff&#34;&gt;hello&lt;/span&gt;(hellomsg: &lt;span style=&#34;color:#0087ff&#34;&gt;str&lt;/span&gt;) -&amp;gt; &lt;span style=&#34;color:#0087ff&#34;&gt;str&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    res = &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;hello world!&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#5f8700&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#0087ff&#34;&gt;len&lt;/span&gt;(hellomsg) &amp;gt; &lt;span style=&#34;color:#00afaf&#34;&gt;0&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        res = hellomsg
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#5f8700&#34;&gt;return&lt;/span&gt; res
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;if&lt;/span&gt; __name__ == &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    app.run(host=&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;0.0.0.0&amp;#34;&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
app.py&lt;/p&gt;
&lt;p&gt;Pra quem quiser brincar com eles, todos os códigos e arquivos utilizados nesse texto estão disponíveis no seguinte repositório &lt;a href=&#34;https://gitlab.com/caioau/caioau.gitlab.io/-/tree/master/static/blog/dockerfile-hardening/exemplo?ref_type=heads&#34;&gt;gitlab.com/caioau/caioau.gitlab.io&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Junto do Dockerfile temos o nosso requirements.txt:&lt;/p&gt;
&lt;p&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Flask~=3.1.2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gunicorn~=23.0.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
requirements.txt&lt;/p&gt;
&lt;p&gt;Para quem não está familiarizado com a notação ~= estamos usando apontando para versão compatível, como as bibliotecas utilizam versionamento semântico (&lt;a href=&#34;https://semver.org/lang/pt-BR/&#34;&gt;semver.org&lt;/a&gt;) vamos utilizar versões mais novas mas dentro do mesmo menor (minor), mas sem mudanças que quebrem as funcionalidades atuais. A linha Flask~=3.1.2 equivale a Flask&amp;gt;=3.1.2,Flask==3.1.*&lt;/p&gt;
&lt;h2 id=&#34;dockerfile-v0&#34;&gt;Dockerfile v0&lt;/h2&gt;
&lt;p&gt;Com o código-fonte do nosso app, podemos seguir com o Dockerfile.&lt;/p&gt;
&lt;p&gt;A fim de ajudar no debug do app, vamos incluir o vim e curl nas imagens.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;22
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-dockerfile&#34; data-lang=&#34;dockerfile&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; debian:bullseye&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;RUN&lt;/span&gt; apt-get update &amp;amp;&amp;amp; &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    apt-get install -y &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    python3-pip python3-dev &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    build-essential &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    curl &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    vim
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;RUN&lt;/span&gt; apt-get clean &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;WORKDIR&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; /usr/src/app&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;COPY&lt;/span&gt; . /usr/src/app/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;RUN&lt;/span&gt; pip3 install -r requirements.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;RUN&lt;/span&gt; rm -rf ~/.cache/pip
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;EXPOSE&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; 8000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;CMD&lt;/span&gt; [ &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;gunicorn&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;-w&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;-b&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;0.0.0.0:8000&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;--access-logfile&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt; , &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;--error-logfile&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;app:app&amp;#34;&lt;/span&gt; ]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Dockerfile-v0&lt;/p&gt;
&lt;p&gt;O que está acontecendo? Utilizando uma imagem base do Debian, instalamos o Python com outros pacotes que fazem a compilação (build-essential e python3-dev). E daí na próxima instrução deletamos o índice do apt-get.&lt;/p&gt;
&lt;p&gt;Mudamos a pasta de trabalho (WORKDIR) e copiamos o código-fonte da aplicação lá, instalamos as dependências da aplicação e similarmente com os índices do apt-get deletamos o cache do pip.&lt;/p&gt;
&lt;p&gt;Por fim, configuramos o comando que sobe a aplicação, utilizando o gunicorn como servidor web Python.&lt;/p&gt;
&lt;p&gt;Quando colocamos para rodar a imagem, a aplicação funciona \o/&lt;/p&gt;
&lt;p&gt;Porém, além de outros problemas de que vamos falar logo, o tamanho da imagem: 570MB, tá bom pra você quase 600 megabytes por um simples hello world?&lt;/p&gt;
&lt;p&gt;Fica até o final, porque &lt;del&gt;vai ter bolo&lt;/del&gt; vamos reduzir o tamanho dessa imagem para 10x menor.&lt;/p&gt;
&lt;p&gt;Observação: Nesse texto, quando estivermos falando do tamanho da imagem, estamos nos referindo ao tamanho sem compressão, ou seja, o valor reportado por docker image ls, ao passo que o tamanho que aparece na página WEB no dockerhub ou outros registries é o tamanho com compressão. Por exemplo, uma imagem de 522 MB sem compressão resulta em 192 MB com compressão.&lt;/p&gt;
&lt;h2 id=&#34;dissecando-imagens-com-dive&#34;&gt;Dissecando imagens com dive&lt;/h2&gt;
&lt;p&gt;A nossa primeira dica é usar o dive para &amp;ldquo;dissecar&amp;rdquo; a imagem. Uma vez carregada, conseguimos acompanhar como estão os arquivos, então podemos ir &amp;ldquo;caminhando&amp;rdquo; a partir da camada inicial até a final como os arquivos foram sendo alterados e dessa forma conseguimos mais facilmente visualizar o que está acontecendo e identificar pontos de melhoria.&lt;/p&gt;
&lt;p&gt;Para instalar, basta baixar o binário do github: &lt;a href=&#34;https://github.com/wagoodman/dive&#34;&gt;github.com/wagoodman/dive&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Com ele instalado basta executar com o nome da imagem&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/dockerfile-hardening/dive.gif&#34; loading=&#34;lazy&#34; width=&#34;800px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Bora ver como o dive analisa nossa imagem? Carregando ele podemos o histórico das instruções do nosso Dockerfile, cada instrução gera uma camada e vamos caminhando nesse histórico. Como são muitos arquivos na imagem base, podemos mostrar apenas os arquivos modificados (pressionando Ctrl+U). Vamos retomar esse ponto importante, mas preste atenção na instrução &lt;code&gt;COPY . .&lt;/code&gt; quais arquivos são copiados, além do código-fonte.&lt;/p&gt;
&lt;p&gt;Com a imagem analisada percebemos dois erros: os índices do apt e o cache do pip não foram limpos, aumentando o tamanho da imagem final desnecessariamente. Isso aconteceu pois a deleção dos arquivos não está na mesma instrução (RUN) do que a criação deles, propagando para a próxima camada.&lt;/p&gt;
&lt;p&gt;Repare no canto inferior esquerdo que a ferramenta dá algumas dicas de onde melhorar, para a imagem ficar mais eficiente.&lt;/p&gt;
&lt;h2 id=&#34;use-dockerignore&#34;&gt;Use dockerignore&lt;/h2&gt;
&lt;p&gt;O outro erro da nossa v0 foi que alguns arquivos sensíveis vazaram, em particular o arquivo .env com credenciais. Isso aconteceu pois quando copiamos os arquivos em COPY . . todos arquivos no contexto do docker são copiados.&lt;/p&gt;
&lt;p&gt;Como resolver? Podemos colocar tudo o que podemos copiar no Docker dentro de uma pasta dedicada, mas teríamos que manter esse controle.&lt;/p&gt;
&lt;p&gt;Uma solução mais robusta é utilizar o arquivo .dockerignore (&lt;a href=&#34;https://docs.docker.com/build/concepts/context/#dockerignore-files&#34;&gt;documentação&lt;/a&gt;), que funciona de uma forma similar ao .gitignore, limitando a quais arquivos é permitido o acesso no contexto Docker.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# ignora tudo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# permite codigos fonte
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!/src
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!*.py
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!requirements.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!entrypoint.sh
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# especifico do python
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;**/__pycache__/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;**/*.py[cod]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# C extensions
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*.so
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;**/.ipynb_checkpoints/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;.dockerignore&lt;/p&gt;
&lt;p&gt;Acima temos um exemplo de dockerignore que resolve nosso problema, onde todos os arquivos são por padrão bloqueados, e então vamos criando exceções como arquivos de código-fonte.&lt;/p&gt;
&lt;h2 id=&#34;dockerfile-v1&#34;&gt;Dockerfile v1&lt;/h2&gt;
&lt;p&gt;Com as lições aprendidas na versão anterior, bora arrumar os erros que encontramos?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;26
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-dockerfile&#34; data-lang=&#34;dockerfile&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; debian:bullseye&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;RUN&lt;/span&gt; apt-get update &amp;amp;&amp;amp; &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    apt-get install -y --no-install-recommends &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    python3-pip python3-dev python3-venv &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    build-essential &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    curl &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    vim &amp;amp;&amp;amp; &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    apt-get clean &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;RUN&lt;/span&gt; useradd -u &lt;span style=&#34;color:#00afaf&#34;&gt;1000&lt;/span&gt; -U -m --shell /bin/bash python
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;USER&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; python&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;WORKDIR&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; /home/python/app&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;COPY&lt;/span&gt; --chown=python:python . /home/python/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;RUN&lt;/span&gt; python3 -m venv .venv &amp;amp;&amp;amp; . .venv/bin/activate &amp;amp;&amp;amp; &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    pip3 install --no-cache-dir -r requirements.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;ENV&lt;/span&gt; &lt;span style=&#34;color:#0087ff&#34;&gt;PATH&lt;/span&gt;=&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;/home/python/app/.venv/bin:&lt;/span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;$PATH&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#4e4e4e&#34;&gt;# &amp;#34;ativa&amp;#34; o venv&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;EXPOSE&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; 8000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;CMD&lt;/span&gt; [ &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;gunicorn&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;-w&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;-b&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;0.0.0.0:8000&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;--access-logfile&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt; , &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;--error-logfile&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;app:app&amp;#34;&lt;/span&gt; ]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Dockerfile-v1&lt;/p&gt;
&lt;p&gt;O que mudamos da versão anterior? Colocamos a deleção dos arquivos desnecessários na mesma instrução (no caso do pip install utilizamos a opção &amp;ndash;no-cache-dir).&lt;/p&gt;
&lt;p&gt;Também usamos um ambiente virtual (venv) para melhor lidar com as dependências Python.&lt;/p&gt;
&lt;p&gt;E por fim, para não rodar como root, criamos um usuário não root e o utilizamos sempre que possível. Se atente que o pip install foi executado como não root.&lt;/p&gt;
&lt;p&gt;E o tamanho? Apesar de só termos mexido no cache do pip e os índices, a nova imagem é tem 520MB , aproximadamente 50MB menor (~10%).&lt;/p&gt;
&lt;h2 id=&#34;user-não-root-basta&#34;&gt;User não root basta?&lt;/h2&gt;
&lt;p&gt;Criamos um usuário não root e paramos de usar o root, mas isso basta? A resposta é não, pois caso a aplicação esteja comprometida, o ataque pode usar qualquer binário presente na imagem para realizar ações mal-intencionadas. Um excelente site explorando isso é o &lt;a href=&#34;https://gtfobins.github.io/&#34;&gt;GTFOBins&lt;/a&gt; que mostra como fazer essas explorações para cada binário.&lt;/p&gt;
&lt;p&gt;Outro argumento é o princípio do privilégio mínimo que dita que devemos apenas usar as permissões mínimas necessárias para o funcionamento dos nossos sistemas, caso contrário as permissões excedentes podem ser abusadas.&lt;/p&gt;
&lt;p&gt;Bora para uma revisão rápida de permissão de arquivos no Linux? O octeto de permissão é definido pelas permissões (do mais significativo para menos) ler (Read), escrever (Write) e executar (eXecute). E temos esse octeto três vezes (da esquerda pra direita): Para o dono, para o grupo e para outros.&lt;/p&gt;
&lt;p&gt;Bora para um exemplo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;O dono vai poder ler (4), escrever (2) e executar (1) -&amp;gt; 4 + 2 + 1 = 7&lt;/li&gt;
&lt;li&gt;O grupo vai poder ler (4) e executar (1) -&amp;gt; 4 + 1 = 5&lt;/li&gt;
&lt;li&gt;Por fim outros vão poder apenas ler (4) -&amp;gt; 4&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Resultado: Executando chmod 754 vai gerar o resultado que queremos.&lt;/p&gt;
&lt;p&gt;Até aí tudo bem, mas além desses 3 dígitos tem um quarto dígito, normalmente omitido, à esquerda que define mais um octeto o Suid , Guid e o Sticky Bit. Se a gente setar o suid no nosso exemplo anterior, a permissão que tínhamos 754 vira 4754 (adicionando o 4 à esquerda).&lt;/p&gt;
&lt;p&gt;E o que faz esse suid? Quando setado o arquivo quando executado não é executado por quem executa, mas por quem é dono do arquivo, que tipicamente é o root, ou seja, qualquer usuário &amp;ldquo;vira root&amp;rdquo; (o sudo funciona assim).&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/dockerfile-hardening/commitstrip-chmod.png&#34; loading=&#34;lazy&#34;
         alt=&#34;commitstrip.com/en/2016/06/29/chmod-what/&#34; width=&#34;500px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;a href=&#34;https://www.commitstrip.com/en/2016/06/29/chmod-what/&#34;&gt;commitstrip.com/en/2016/06/29/chmod-what/&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Bora mostrar na prática?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-dockerfile&#34; data-lang=&#34;dockerfile&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; debian:bullseye&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;RUN&lt;/span&gt; cp /bin/bash /bin/bash-suid &amp;amp;&amp;amp; chmod u+s /bin/bash-suid
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;RUN&lt;/span&gt; useradd -u &lt;span style=&#34;color:#00afaf&#34;&gt;1000&lt;/span&gt; -U -m --shell /bin/bash python
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;USER&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; python&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;WORKDIR&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; /home/python/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Dockerfile-setuid&lt;/p&gt;
&lt;p&gt;No dockerfile acima criamos um novo bash chamado bash-uid, com a permissão suid, agora mesmo que estejamos rodando como um usuário não root, se invocado esse bash especial escalamos o privilégio para root.&lt;/p&gt;
&lt;p&gt;Para desarmar essa possibilidade, suba o container com a opção &lt;strong&gt;no-new-privileges&lt;/strong&gt; que efetivamente protege contra a escalação de privilégio.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/dockerfile-hardening/demo-suid.png&#34; loading=&#34;lazy&#34;
         alt=&#34;demonstrando o setuid&#34; width=&#34;800px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;demonstrando o setuid&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Repare que quando executamos o bash especial efetivamente se tornamos root, porém com a opção no-new-privileges habilitada resolvemos o problema.&lt;/p&gt;
&lt;p&gt;Para outras boas práticas de segurança para containers docker consulte a excelente cartilha da OWASP (comunidade que publica diversas boas práticas de segurança para aplicações web): &lt;a href=&#34;https://cheatsheetseries.owasp.org/cheatsheets/Docker_Security_Cheat_Sheet.html&#34;&gt;OWASP Docker Security Cheat Sheet&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;dockerfile-v2-introduzindo-multistage&#34;&gt;Dockerfile v2: introduzindo multistage&lt;/h2&gt;
&lt;p&gt;Até então estamos instalando compiladores necessários para o pip install, utilizando o pacote build-essential, porém em tempo de execução os mesmos não são necessários, esse é o cenário que a funcionalidade do multi-stage do docker resolve.&lt;/p&gt;
&lt;p&gt;O multi-stage acontece quando utilizamos a instrução FROM múltiplas vezes, criando estágios separados, tipicamente para o build e um estágio final utilizado em tempo de execução, dessa forma os artefatos resultantes do build são passados pro estágio final, e os compiladores e outras ferramentas do build são instalados apenas no estágio de build, resultando uma imagem final menor.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;28
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-dockerfile&#34; data-lang=&#34;dockerfile&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; python:3.13 AS builder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;RUN&lt;/span&gt; useradd -u &lt;span style=&#34;color:#00afaf&#34;&gt;1000&lt;/span&gt; -U -m --shell /bin/bash python
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;USER&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; python&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;WORKDIR&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; /home/python/app&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;COPY&lt;/span&gt; --chown=python:python . /home/python/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;RUN&lt;/span&gt; python3 -m venv .venv &amp;amp;&amp;amp; . .venv/bin/activate &amp;amp;&amp;amp; &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    pip3 install --no-cache-dir -r requirements.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; python:3.13-slim AS runtime&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;RUN&lt;/span&gt; useradd -u &lt;span style=&#34;color:#00afaf&#34;&gt;1000&lt;/span&gt; -U -m --shell /bin/bash python
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;USER&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; python&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;WORKDIR&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; /home/python/app&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;COPY&lt;/span&gt; --chown=python:python --from=builder /home/python/app/ /home/python/app/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;ENV&lt;/span&gt; &lt;span style=&#34;color:#0087ff&#34;&gt;PATH&lt;/span&gt;=&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;/home/python/app/.venv/bin:&lt;/span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;$PATH&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;EXPOSE&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; 8000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;CMD&lt;/span&gt; [ &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;gunicorn&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;-w&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;-b&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;0.0.0.0:8000&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;--access-logfile&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt; , &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;--error-logfile&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;app:app&amp;#34;&lt;/span&gt; ]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Dockerfile-v2&lt;/p&gt;
&lt;p&gt;Dessa vez optamos por usar as imagens oficiais do python, então não precisamos instalar o python em si e os compiladores que precisamos em tempo de build. Agora o grande pulo do gato do multi-stage, as imagens de build e runtime são diferentes, a de build (python:3.13) têm 1.1GB e a de runtime (python:3.13-slim) aproximadamente 10% do seu tamanho com 120MB.&lt;/p&gt;
&lt;p&gt;Outra mudança na imagem base, até então estávamos usando a release bullseye do Debian, mas consultando o &lt;a href=&#34;https://endoflife.date/&#34;&gt;endoflife.date&lt;/a&gt; podemos ver que essa release perdeu suporte principal, agora com a imagem python a tag 3.13 aponta para a release corrente do stable do Debian. Além de usarmos a variante slim da imagem do debian, sempre que possível opte por essa opção.&lt;/p&gt;
&lt;p&gt;Uma dica valiosa para sempre manter suas dependências atualizadas é utilizar o dependabot ou similares como o renovate, que periodicamente atualiza as dependências automaticamente abrindo um pull request com a atualização.&lt;/p&gt;
&lt;p&gt;Como ficou o tamanho? Essa versão ficou com 130 MB, um quarto da nossa primeira versão.&lt;/p&gt;
&lt;h2 id=&#34;fazendo-nosso-app-em-golang&#34;&gt;Fazendo nosso app em Golang&lt;/h2&gt;
&lt;p&gt;Até agora estávamos usando Python no nosso app, porém para o próximo conceito de imagens distroless, usar uma linguagem compilada, em particular Go, pois ele permite a compilação estática, ou seja toda a aplicação fica &amp;ldquo;empacotada&amp;rdquo; em apenas um binário, sem precisar de outros arquivos/pacotes para que a nossa app funcione.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;28
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;29
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;30
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;31
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;32
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;33
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;34
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;35
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;36
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;37
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;38
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;39
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;40
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;41
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;42
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;43
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;44
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;45
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;46
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;47
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;48
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;49
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;50
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;51
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;52
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;53
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;54
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;55
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;56
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;57
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;58
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;59
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;60
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;61
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;62
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;63
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;64
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;65
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d75f00&#34;&gt;package&lt;/span&gt; main
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d75f00&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;io&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;log&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;net/http&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;time&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#0087ff&#34;&gt;rootHandler&lt;/span&gt;(w http.ResponseWriter, req *http.Request) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    log.&lt;span style=&#34;color:#0087ff&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;%v&amp;#34;&lt;/span&gt;, req)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    fmt.&lt;span style=&#34;color:#0087ff&#34;&gt;Fprintf&lt;/span&gt;(w, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;hello world!\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#0087ff&#34;&gt;helloHandler&lt;/span&gt;(w http.ResponseWriter, req *http.Request) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    log.&lt;span style=&#34;color:#0087ff&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;%v&amp;#34;&lt;/span&gt;, req)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    msg := req.&lt;span style=&#34;color:#0087ff&#34;&gt;PathValue&lt;/span&gt;(&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;msg&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    fmt.&lt;span style=&#34;color:#0087ff&#34;&gt;Fprintf&lt;/span&gt;(w, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;%s&amp;#34;&lt;/span&gt;, msg+&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#0087ff&#34;&gt;weatherHandler&lt;/span&gt;(w http.ResponseWriter, req *http.Request) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    url := &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;https://wttr.in/?T&amp;amp;lang=pt-br&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ua := &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;curl/8.5.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    log.&lt;span style=&#34;color:#0087ff&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;making a GET request to url=&amp;#34;&lt;/span&gt;, url, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;...&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    client := http.Client{ &lt;span style=&#34;color:#4e4e4e&#34;&gt;// set a request timeout
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4e4e4e&#34;&gt;&lt;/span&gt;        Timeout: &lt;span style=&#34;color:#00afaf&#34;&gt;20&lt;/span&gt; * time.Second,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    r, err := http.&lt;span style=&#34;color:#0087ff&#34;&gt;NewRequest&lt;/span&gt;(&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;, url, &lt;span style=&#34;color:#d75f00&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#5f8700&#34;&gt;if&lt;/span&gt; err != &lt;span style=&#34;color:#d75f00&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;panic&lt;/span&gt;(err)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    r.Header.&lt;span style=&#34;color:#0087ff&#34;&gt;Add&lt;/span&gt;(&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;User-Agent&amp;#34;&lt;/span&gt;, ua)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    resp, err := client.&lt;span style=&#34;color:#0087ff&#34;&gt;Do&lt;/span&gt;(r)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#5f8700&#34;&gt;if&lt;/span&gt; err != &lt;span style=&#34;color:#d75f00&#34;&gt;nil&lt;/span&gt; || resp.StatusCode != http.StatusOK {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        log.&lt;span style=&#34;color:#0087ff&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;making a GET request to url=&amp;#34;&lt;/span&gt;, url, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;Failed! Returning a 500&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        log.&lt;span style=&#34;color:#0087ff&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;err=&amp;#34;&lt;/span&gt;, err)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        w.&lt;span style=&#34;color:#0087ff&#34;&gt;WriteHeader&lt;/span&gt;(&lt;span style=&#34;color:#00afaf&#34;&gt;500&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        fmt.&lt;span style=&#34;color:#0087ff&#34;&gt;Fprintf&lt;/span&gt;(w, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;request failed!\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#5f8700&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#5f8700&#34;&gt;defer&lt;/span&gt; resp.Body.&lt;span style=&#34;color:#0087ff&#34;&gt;Close&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    log.&lt;span style=&#34;color:#0087ff&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;making a GET request to url=&amp;#34;&lt;/span&gt;, url, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;Done! Response code=&amp;#34;&lt;/span&gt;, resp.Status)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    written, err := io.&lt;span style=&#34;color:#0087ff&#34;&gt;Copy&lt;/span&gt;(w, resp.Body)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#5f8700&#34;&gt;if&lt;/span&gt; err != &lt;span style=&#34;color:#d75f00&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        log.&lt;span style=&#34;color:#0087ff&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;Error writing response after %d bytes: %v&amp;#34;&lt;/span&gt;, written, err)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#0087ff&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    apiPort := &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;8000&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    http.&lt;span style=&#34;color:#0087ff&#34;&gt;HandleFunc&lt;/span&gt;(&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;, rootHandler)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    http.&lt;span style=&#34;color:#0087ff&#34;&gt;HandleFunc&lt;/span&gt;(&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;/weather/&amp;#34;&lt;/span&gt;, weatherHandler)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    http.&lt;span style=&#34;color:#0087ff&#34;&gt;HandleFunc&lt;/span&gt;(&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;/hello/{msg}&amp;#34;&lt;/span&gt;, helloHandler)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    log.&lt;span style=&#34;color:#0087ff&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;Listening on port=&amp;#34;&lt;/span&gt;, apiPort)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;panic&lt;/span&gt;(http.&lt;span style=&#34;color:#0087ff&#34;&gt;ListenAndServe&lt;/span&gt;(&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt;+apiPort, &lt;span style=&#34;color:#d75f00&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;app.go&lt;/p&gt;
&lt;p&gt;Nosso app continua igual à versão em Python, mas agora temos um endpoint a mais que faz um request externo para o site &lt;a href=&#34;https://wttr.in/&#34;&gt;wttr.in&lt;/a&gt; obter a previsão do tempo.&lt;/p&gt;
&lt;p&gt;E como fica o nosso Dockerfile? Como Golang é uma linguagem compilada vamos mostrar nesse exemplo a funcionalidade do multi-stage ao extremo: Criando um container com apenas o binário da nossa app.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;23
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-dockerfile&#34; data-lang=&#34;dockerfile&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; golang:1.25 AS builder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;RUN&lt;/span&gt; useradd -u &lt;span style=&#34;color:#00afaf&#34;&gt;1000&lt;/span&gt; -U -m --shell /bin/bash nonroot
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;USER&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; nonroot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;WORKDIR&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; /home/nonroot/app&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;COPY&lt;/span&gt; --chown=nonroot:nonroot . /home/nonroot/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;RUN&lt;/span&gt; &lt;span style=&#34;color:#0087ff&#34;&gt;CGO_ENABLED&lt;/span&gt;=&lt;span style=&#34;color:#00afaf&#34;&gt;0&lt;/span&gt; go build -ldflags=&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;-s -w&amp;#34;&lt;/span&gt; app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; scratch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;COPY&lt;/span&gt; --from=builder /etc/passwd /etc/passwd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4e4e4e&#34;&gt;# truque pra rodar nonroot no scratch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;COPY&lt;/span&gt; --from=builder /home/nonroot/app/app /usr/local/bin/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;USER&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; nonroot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;EXPOSE&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; 8000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;ENTRYPOINT&lt;/span&gt; [ &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;app&amp;#34;&lt;/span&gt; ]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;golang/Dockerfile-scratch&lt;/p&gt;
&lt;p&gt;Como podemos ver, compilamos nosso app no estágio de build, usando uma imagem que contém os compiladores e outras ferramentas para gerar o nosso binário, e como estamos compilando estaticamente (usando opção CGO_ENABLED=0) apenas o nosso binário é necessário para a aplicação funcionar. E depois do estágio de build, o estágio final não está utilizando nenhuma imagem base (SCRATCH), ou seja, nossa imagem final vai conter apenas o binário do nosso app.&lt;/p&gt;
&lt;p&gt;Para quem ficou curioso, essa imagem tem apenas 6 MB, ao passo que a imagem base de build (golang:1.25) tem 850MB.&lt;/p&gt;
&lt;p&gt;Quem quiser se aprofundar em diminuir o tamanho do binário ainda mais dá pra usar o upx (&lt;a href=&#34;https://github.com/upx/upx&#34;&gt;github.com/upx/upx&lt;/a&gt;) que faz compressão de executáveis, que reduziu o tamanho para ~2MB. Porém, acho que não vale a pena adotar essa abordagem, pois o Docker já faz essa compressão quando faz o download das imagens, então usar o upx só vai fazer seu app demorar mais para inicializar.&lt;/p&gt;
&lt;p&gt;Se subirmos o container, vemos que os endpoints &amp;ldquo;hello world&amp;rdquo; funcionam, mas o endpoint de previsão de tempo não, com o erro: &amp;ldquo;tls: failed to verify certificate: x509: certificate signed by unknown authority&amp;rdquo;. Não temos a cadeia de certificados&lt;/p&gt;
&lt;p&gt;Essa foi a nossa deixa para falarmos do conceito de imagens distroless.&lt;/p&gt;
&lt;p&gt;Imagens distroless (&lt;a href=&#34;https://github.com/GoogleContainerTools/distroless&#34;&gt;github.com/GoogleContainerTools/distroless&lt;/a&gt;) foram introduzidos pela Google, e a ideia é que as imagens base tem o mínimo necessário para rodar a aplicação, sem ter uma distribuição base como o debian por trás, ou seja não tem o apt para instalar pacotes ou shell, etc &amp;hellip;&lt;/p&gt;
&lt;p&gt;Quem tiver interesse no repositório oficial, tem exemplos para várias linguagens. O que é chato dessas imagens é que caso você precise adicionar algum pacote que a imagem base não tem você precisa aprender o sistema de build pouco intuitivo chamado Bazel.&lt;/p&gt;
&lt;p&gt;No nosso caso a imagem base distroless é a gcr.io/distroless/static, ela tem apenas 2MB. Quais pacotes ela tem? Como não temos o apt, não vamos conseguir facilmente listar os pacotes.&lt;/p&gt;
&lt;p&gt;Para resolver esse problema de identificar os pacotes vamos introduzir um conceito do Software Bill of materials (SBOM), é um &amp;ldquo;inventário&amp;rdquo; identificando todos os componentes presentes em um determinado artefato de software. Ele tem alguns formatos padrão, o mais difundido é o System Package Data Exchange (SPDX) , tipicamente representado em um arquivo json. Nesse arquivo teremos as versões de todos os componentes, suas licenças e por fim os relacionamentos (como dependências).&lt;/p&gt;
&lt;p&gt;É uma boa prática gerar o SBOM junto ao build da imagem Docker, pois isso facilita demais auditorias de segurança, por exemplo, quando identificada uma vulnerabilidade em uma biblioteca que utilizamos, conseguimos facilmente encontrar se de fato estamos seguros ou onde precisamos atuar atualizando um pacote para uma versão não vulnerável.&lt;/p&gt;
&lt;p&gt;Vamos gerar o nosso SBOM utilizando o syft (&lt;a href=&#34;https://github.com/anchore/syft&#34;&gt;github.com/anchore/syft&lt;/a&gt;), nossa imagem tem os seguintes pacotes: a cadeia de certificados que precisamos e infos de fuso horários necessários para alguns apps.&lt;/p&gt;
&lt;p&gt;Usando essa imagem como base no estágio final, nosso endpoint de previsão do tempo funciona \o/&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/dockerfile-hardening/weather-working.png&#34; loading=&#34;lazy&#34;
         alt=&#34;endpoint weather funcioando \o/&#34; width=&#34;800px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;endpoint weather funcioando \o/&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;debugando-imagens-distroless&#34;&gt;Debugando imagens distroless&lt;/h2&gt;
&lt;p&gt;Uma das maiores dificuldades em utilizar as imagens mínimas distroless é a de fazer o debug das aplicações, por exemplo, rodar um debugger com breakpoints para investigar algum bug.&lt;/p&gt;
&lt;p&gt;Vamos abordar duas formas de resolver isso, a primeira é ter duas versões do Dockerfile, uma mínima utilizada em produção e uma versão &amp;ldquo;desenvolvedor&amp;rdquo; que inclui um shell, o gerenciador de pacotes como o apt e outros pacotes para esse fim.&lt;/p&gt;
&lt;p&gt;Outra abordagem é &amp;ldquo;anexar&amp;rdquo; um container de debug junto ao container da aplicação, também chamado de container sidecar, o container de debug tem um shell e as ferramentas necessárias para fazer o debug e atua lado-a-lado da aplicação rodando.&lt;/p&gt;
&lt;p&gt;Bora ver os pacotes da aplicação? Subi nosso app Golang com um container chamado golang, então vamos subir outro container usando o mesmo namespace de processos (pid) e na mesma rede, conforme o comando abaixo:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;docker run --rm -it --privileged --pid container:golang --network container:golang nicolaka/netshoot&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Observação: a imagem nicolaka/netshoot (&lt;a href=&#34;https://github.com/nicolaka/netshoot&#34;&gt;github.com/nicolaka/netshoot&lt;/a&gt;) é uma imagem com diversas ferramentas de rede instaladas. Para Kubernetes a imagem bretfisher/shpod (&lt;a href=&#34;https://github.com/bretfisher/shpod&#34;&gt;github.com/bretfisher/shpod&lt;/a&gt;) é ótima com diversas ferramentas para fazer debug do cluster.&lt;/p&gt;
&lt;p&gt;Por que o container precisa ser privilegiado? Para conseguirmos acessar os arquivos do outro arquivo, vá em /proc/1/root , e você estará no filesystem da aplicação. Onde 1 é o id do processo do app.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/dockerfile-hardening/wizardzines-procfs.png&#34; loading=&#34;lazy&#34;
         alt=&#34;wizardzines.com/comics/proc&#34; width=&#34;600px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;a href=&#34;https://wizardzines.com/comics/proc/&#34;&gt;wizardzines.com/comics/proc&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Antes de capturar os pacotes, bora dar um tutorial rápido de Wireshark? O wireguark é um aplicativo desktop que faz 2 coisas em uma, primeiro ele captura os pacotes passando na maquina e depois ele tem uma interface muito completa para visualizar o tráfego, vendo detalhes de cada pacote, possibilitando filtros e fazendo visualizações como  diagramas de estado e estatísticas para ajudar a entender o que está acontecendo.&lt;/p&gt;
&lt;p&gt;No nosso caso, como estamos utilizando containers, não vamos ter a interface gráfica do Wireshark, então podemos fazer de duas formas: capturar os pacotes utilizando o tcpdump (que não tem interface gráfica), salvar um arquivo pcap e visualizar no Wireshark. A outra opção é utilizar uma alternativa &amp;ldquo;terminal&amp;rdquo; do Wireshark, o termshark, com ele teremos uma experiência parecida com a original.&lt;/p&gt;
&lt;p&gt;Para abrir o termshark precisamos especificar uma interface da qual os pacotes serão capturados, no nosso caso só temos uma interface, então não precisamos. Uma vez aberto, podemos ver que mesmo sem mandar muitos requests pro nosso app tem muitos pacotes que não são do nosso interesse, como os pacotes do protocolo ARP. Então é uma mão na roda usar filtros, podemos filtrar por IP, por porta , protocolo, etc &amp;hellip;. Tem uma colinha dos filtros nesse link: &lt;a href=&#34;https://medium.com/hacker-toolbelt/wireshark-filters-cheat-sheet-eacdc438969c&#34;&gt;https://medium.comhacker-toolbelt/wireshark-filters-cheat-sheet-eacdc438969c&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Com o termshark aberto e filtrando apenas pacotes HTTP, no print abaixo podemos ver a aplicação rodando no terminal superior esquerdo, um request sendo feito com curl no terminal da direita e abaixo estamos rodando a versão&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/dockerfile-hardening/termshark.png&#34; loading=&#34;lazy&#34; width=&#34;800px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Fechando o parêntese do nosso tutorial 101 do wireshark, se tiver interesse em um texto aprofundado escreva pra gente :)&lt;/p&gt;
&lt;p&gt;Para facilitar nossa vida, tem uma ferramenta que faz essa abordagem de maneira simplificada, o cdebug (&lt;a href=&#34;https://github.com/iximiuz/cdebug&#34;&gt;github.com/iximiuz/cdebug&lt;/a&gt;), com uma feature adicional: fazer redirecionamento de portas não públicas (semelhante ao kubectl port-forward).&lt;/p&gt;
&lt;h2 id=&#34;fazendo-o-scan-de-vulnerabilidades-nas-imagens&#34;&gt;Fazendo o scan de vulnerabilidades nas imagens&lt;/h2&gt;
&lt;p&gt;Até agora o nosso intuito era diminuir o tamanho das imagens, pois dessa forma teríamos uma superfície de ataque menor, mas não medimos se de fato temos menos vulnerabilidades.&lt;/p&gt;
&lt;p&gt;Vamos adotar o grype (&lt;a href=&#34;https://github.com/anchore/grype&#34;&gt;github.com/anchore/grype&lt;/a&gt;), outra opção muito boa é o trivy (&lt;a href=&#34;https://github.com/aquasecurity/trivy&#34;&gt;github.com/aquasecurity/trivy&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;A nossa primeira versão (v1) tem 1334 CVEs :/ , das quais 6 são critical, 257 high, 894 medium, etc.&lt;/p&gt;
&lt;p&gt;Já a nossa versão multistage (v2) tem 10x menos vulnerabilidades: com 136 CVEs , das quais 4 critical, 6 high, 36 medium.&lt;/p&gt;
&lt;p&gt;Como pode um simples hello world ter 1300 CVEs? Em resumo, é porque imagens baseadas em Debian não atualizam por completo as versões para corrigir as CVEs, vamos falar em mais detalhes na próxima seção.&lt;/p&gt;
&lt;h2 id=&#34;debian-estamos-sendo-justos-com-ele&#34;&gt;Debian: Estamos sendo justos com ele?&lt;/h2&gt;
&lt;p&gt;Vimos que a nossa imagem tem mais de mil vulnerabilidades, mas por que isso acontece? Estou de fato em risco?&lt;/p&gt;
&lt;p&gt;A resposta é que provavelmente o problema não é tão grave quanto parece, só que a maneira que os scanners funcionam não bate bem da maneira que o Debian opera. O Debian quando tem sua versão stable declarada todos os pacotes são congelados na versão que estão e são feitos diversos testes para que tudo funcione até que seja lançada ao público a release.&lt;/p&gt;
&lt;p&gt;Quando bugs são encontrados, de segurança ou não, o Debian muitas vezes simplesmente aplica a mudança (patch) que corrige o problema em cima da versão que saiu no stable.&lt;/p&gt;
&lt;p&gt;Ao passo que os scanners de segurança funcionam identificando os pacotes e outros componentes de software (SBOM) e cruzar com um banco de dados de vulnerabilidades.&lt;/p&gt;
&lt;p&gt;Ou seja, os scanners não estão nem aí pras mudanças que o Debian aplicou.&lt;/p&gt;
&lt;p&gt;Por exemplo, nossa primeira versão de ambos o trivy e grype reportaram a CVE-2023-23914 (HSTS ignored on multiple requests) no curl, que de fato é uma vulnerabilidade crítica. Pois bora tentar reproduzir a vulnerabilidade?&lt;/p&gt;
&lt;p&gt;Na página da CVE (&lt;a href=&#34;https://curl.se/docs/CVE-2023-23914.html&#34;&gt;curl.se/docs/CVE-2023-23914.html&lt;/a&gt;), basta rodar o seguinte: &lt;code&gt;curl --hsts &amp;quot;&amp;quot; https://curl.se http://curl.se&lt;/code&gt;, quando vulnerável, o curl vai fazer o segundo request sem https, mesmo com o site esforçando HSTS. Porém, o comando falha pois a feature de HSTS nem foi introduzida na versão do curl adotada no Debian Bullseye. Ou seja, é um falso positivo.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/dockerfile-hardening/false-positive.png&#34; loading=&#34;lazy&#34; width=&#34;500px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Um excelente blog post falando sobre essa situação é &lt;a href=&#34;https://www.linuxserver.io/blog/image-vulnerability-scanning-and-you&#34;&gt;Image Vulnerability Scanning and You -- linuxserver&lt;/a&gt;, da linuxserver, grupo que disponibiliza imagens docker para diversas aplicações open source, no blog post eles mostram como esses resultados aparentemente alarmante de scanners de vulnerabilidades, são falsos positivos. Eles deram um exemplo de uma vulnerabilidade, a CVE-2020-16156, que só pode ser explorada caso um usuário altere configurações de maneira maliciosa, ou seja, para explorar a vulnerabilidade você já teria que estar comprometido, o que é um problema muito maior.&lt;/p&gt;
&lt;p&gt;O scanner grype tem uma opção para apenas considerar vulnerabilidades que de fato serão corrigidas (&amp;ndash;only-fixed), rodando essa opção na nossa v2, as 130 vulnerabilidades caem para 2, uma de severidade medium e outra unknown.&lt;/p&gt;
&lt;h2 id=&#34;imagens-chainguard&#34;&gt;Imagens chainguard&lt;/h2&gt;
&lt;p&gt;As imagens da Chainguard são imagens produzidas pela empresa de mesmo nome que, além de serem menores, fazem um grande esforço para as imagens estarem com os pacotes atualizados e com as correções de segurança aplicadas.&lt;/p&gt;
&lt;p&gt;Outra feature legal dessas imagens é que toda vez que um pacote é instalado o SBOM dele é automaticamente gerado, criando um melhor lastro do conteúdo da imagem.&lt;/p&gt;
&lt;p&gt;Para quem está acostumado com imagens baseadas em debian precisa se acostumar pois as imagens do chainguard são baseadas no alpine, ou seja, ao invés do gerenciador de pacotes apt é utilizado o apk, então tem uma certa &amp;ldquo;curva de aprendizado&amp;rdquo; para se acostumar, uma dica pra encontrar os pacotes equivalentes é utilizar o apk search com cmd para procurar o pacote que contém aquele comando, por exemplo para instalar o ldd, faça: apk search cmd:ldd e o pacote associado será o posix-libc-utils.&lt;/p&gt;
&lt;p&gt;Outra diferença entre as imagens baseadas no Debian e do Alpine é o shell, nas imagens Debian o shell adotado é o bash, enquanto no Alpine é um shell mais limitado o ash (provido pelo busybox), então se seus scripts contém &amp;ldquo;bashismos&amp;rdquo; você precisa ver o que faz mais sentido entre tornar eles interoperáveis (posix-compliant) ou instalar o bash na imagem.&lt;/p&gt;
&lt;p&gt;Apesar de ser baseada no alpine, as imagens chainguard não utilizam a biblioteca padrão musl do alpine, mas sim a implementação mais difundida da GNU a glibc, vamos retomar essa diferença mais a frente.&lt;/p&gt;
&lt;p&gt;Bora colocar nossa app Python para usar o Chainguard?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;21
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-dockerfile&#34; data-lang=&#34;dockerfile&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; cgr.dev/chainguard/wolfi-base&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;ARG&lt;/span&gt; &lt;span style=&#34;color:#0087ff&#34;&gt;pyversion&lt;/span&gt;=&lt;span style=&#34;color:#00afaf&#34;&gt;3&lt;/span&gt;.12
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;RUN&lt;/span&gt; apk add python-&lt;span style=&#34;color:#00afaf&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;pyversion&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;}&lt;/span&gt; py&lt;span style=&#34;color:#00afaf&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;pyversion&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;}&lt;/span&gt;-pip python-&lt;span style=&#34;color:#00afaf&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;pyversion&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;}&lt;/span&gt;-dev &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    build-base openssl-dev vim curl &amp;amp;&amp;amp; &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    rm -rf /var/cache/apk/*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;USER&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; nonroot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;WORKDIR&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; /home/nonroot/app&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;COPY&lt;/span&gt; --chown=nonroot:nonroot . /home/nonroot/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;RUN&lt;/span&gt; python3 -m venv .venv &amp;amp;&amp;amp; . .venv/bin/activate &amp;amp;&amp;amp; &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    pip3 install --no-cache-dir -r requirements.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;ENV&lt;/span&gt; &lt;span style=&#34;color:#0087ff&#34;&gt;PATH&lt;/span&gt;=&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;/home/nonroot/app/.venv/bin:&lt;/span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;$PATH&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;EXPOSE&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; 8000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;CMD&lt;/span&gt; [ &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;gunicorn&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;-w&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;-b&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;0.0.0.0:8000&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;--access-logfile&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt; , &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;--error-logfile&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;app:app&amp;#34;&lt;/span&gt; ]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Dockerfile-v3&lt;/p&gt;
&lt;p&gt;A imagem base da Chainguard é o wolfi, ela é uma imagem pequena da qual instalamos os pacotes de que precisamos.&lt;/p&gt;
&lt;p&gt;A principal diferença é que os pacotes têm outros nomes, por exemplo, o equivalente do build-essential é o build-base, e diferentemente do Debian podemos escolher qual versão do Python vamos adotar.&lt;/p&gt;
&lt;p&gt;Já vem com um usuário não root, então basta utilizar ele.&lt;/p&gt;
&lt;p&gt;Quem tiver curiosidade em inspecionar a imagem com o dive, os SBOMs SPDX de cada pacote estão em /var/lib/db/sbom/.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/dockerfile-hardening/chainguard-cves.png&#34; loading=&#34;lazy&#34; width=&#34;500px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;E as CVEs? É aqui que a Chainguard brilha, nenhuma CVE reportada no Trivy ^_^, porém apesar da Chainguard ter uma postura bastante proativa para manter toda cadeia de suprimento segura e atualizada, você precisa periodicamente rebuildar as imagens para usar as versões mais atuais dos pacotes e das nossas bibliotecas de que dependemos (que permitimos que sejam atualizadas para versões compatíveis).&lt;/p&gt;
&lt;p&gt;Quem tiver interesse em aprender mais sobre as imagens chainguard eles tem excelentes guias com passo-a-passo, exemplo e cursos em &lt;a href=&#34;https://edu.chainguard.dev/&#34;&gt;edu.chainguard.dev&lt;/a&gt; gostei bastante da dinâmica dos cursos, com vídeos curtos e acompanhados de um texto do que é mostrado no vídeo.&lt;/p&gt;
&lt;h2 id=&#34;criando-imagens-distroless-da-chainguard-com-melange&#34;&gt;Criando imagens distroless da Chainguard com Melange&lt;/h2&gt;
&lt;p&gt;No exemplo anterior utilizamos a imagem base da Chainguard para o nosso app Python, porém ela não é uma imagem distroless, visto que ela tem um shell, o apk e etc. &amp;hellip; A Chainguard tem imagens distroless do Python e outras linguagens e projetos, porém só podemos usar gratuitamente sua tag latest&lt;/p&gt;
&lt;p&gt;Para termos uma imagem distroless pra chamar de nossa, vamos utilizar o sistema de build da Chainguard, o Melange.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/dockerfile-hardening/chainguard-melange.png&#34; loading=&#34;lazy&#34;
         alt=&#34;edu.chainguard.dev/open-source/build-tools/melange/overview&#34; width=&#34;600px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;a href=&#34;https://edu.chainguard.dev/open-source/build-tools/melange/overview/&#34;&gt;edu.chainguard.dev/open-source/build-tools/melange/overview&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Primeiramente precisamos empacotar nossa app python em um pacote alpine apk usando o melange, para fazer esse empacotamento teremos uma pipeline de build no melange declarada a partir do arquivo yaml abaixo:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;28
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;29
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;30
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;31
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;32
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;33
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;34
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;35
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;36
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;37
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;38
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;39
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;40
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;41
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;42
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;43
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;44
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;45
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;46
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;47
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;48
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;49
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;50
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;51
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;52
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;package&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;name&lt;/span&gt;: hello-crud
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;version&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;0.0.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;epoch&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;description&lt;/span&gt;: REST hello world
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;copyright&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#0087ff&#34;&gt;license&lt;/span&gt;: Apache-2.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0087ff&#34;&gt;paths&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;dependencies&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;runtime&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - python-3.12
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;environment&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;accounts&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;groups&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#0087ff&#34;&gt;groupname&lt;/span&gt;: nonroot
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;gid&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;65532&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;users&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#0087ff&#34;&gt;username&lt;/span&gt;: nonroot
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;uid&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;65532&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;run-as&lt;/span&gt;: nonroot
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;contents&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;keyring&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - https://packages.wolfi.dev/os/wolfi-signing.rsa.pub
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - ./melange.rsa.pub
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;repositories&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - https://packages.wolfi.dev/os
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;packages&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - busybox
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - glibc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - glibc-locale-posix
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - openssl-dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - build-base
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - python-3.12
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - py3.12-pip
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;pipeline&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#0087ff&#34;&gt;name&lt;/span&gt;: Build Python application
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;runs&lt;/span&gt;: |&lt;span style=&#34;color:#00afaf&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;      VENVDIR=/usr/share/webapps/hello-server/venv
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;      EXECDIR=&amp;#34;${{targets.destdir}}/usr/bin&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;      WEBAPPDIR=&amp;#34;${{targets.destdir}}/usr/share/webapps/hello-server&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;      mkdir -p &amp;#34;${EXECDIR}&amp;#34; &amp;#34;${WEBAPPDIR}&amp;#34; /usr/share/webapps/hello-server
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;      cd /usr/share/webapps/hello-server
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;      echo -e &amp;#34;\n\n#########################################\n&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;      python3 -m venv ${VENVDIR}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;      cd /home/build
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;      sh -c &amp;#34;. ${VENVDIR}/bin/activate &amp;amp;&amp;amp; pip3 install --no-compile --no-cache-dir -r requirements.txt &amp;amp;&amp;amp; pip3 uninstall -y pip&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;      cp -r ${VENVDIR} ${WEBAPPDIR}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;      cp app.py ${WEBAPPDIR}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;      chown -R 65532:65532 ${WEBAPPDIR}&lt;/span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;melange.yaml&lt;/p&gt;
&lt;p&gt;Nesse yaml a gente declara as informações do nosso pacote, como nome, versão e licença e as dependências em tempo de execução dele, no nosso caso apenas o python3.12.&lt;/p&gt;
&lt;p&gt;Em seguida declaramos o que o nosso ambiente de build precisa: os pacotes de build, o usuário não root e os repositórios wolfi para usarmos os pacotes da chainguard (poderíamos usar o alpine se quiser).&lt;/p&gt;
&lt;p&gt;Por fim a pipeline de build em si, ou seja uma sequência de comandos shell que builda a app e copia tudo para uma pasta em targets.destdir.&lt;/p&gt;
&lt;p&gt;Fizemos uma pequena alteração no nosso pip install, utilizando a flag &amp;ndash;no-compile que não gera os arquivos .pyc, dessa forma o venv fica menor. Tem um excelente blog post explicando os trade-offs dessa abordagem: &lt;a href=&#34;https://aleksac.me/blog/dont-use-pythondontwritebytecode-in-your-dockerfiles/&#34;&gt;Stop putting this into your Python Dockerfiles  -- Aleksa Cukovic&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Bora buildar nosso pacote?&lt;/p&gt;
&lt;p&gt;Na primeira vez precisamos gerar uma chave privada para assinar o pacote:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;docker run --rm -v &amp;quot;${PWD}&amp;quot;:/work cgr.dev/chainguard/melange keygen&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Não se preocupe com os comandos, criei um makefile no repositório que executa os comandos em sequência.&lt;/p&gt;
&lt;p&gt;Então o build:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;docker run --privileged --rm -v &amp;quot;${PWD}&amp;quot;:/work cgr.dev/chainguard/melange build melange.yaml --arch amd64 --signing-key melange.rsa&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Pronto! Uma vez executado, teremos nosso pacote alpine na pasta packages.&lt;/p&gt;
&lt;p&gt;Com o nosso pacote alpine pronto, bora criar o container que faz o deploy do nosso app? É agora que surge o apko, nele declaramos o container usado em tempo de execução (runtime) contendo o pacote previamente gerado, é como se fosse um Dockerfile, mas feito de forma declarativa.&lt;/p&gt;
&lt;p&gt;Agora o nosso apko.yaml:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;22
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;contents&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;keyring&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - https://packages.wolfi.dev/os/wolfi-signing.rsa.pub
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - ./melange.rsa.pub
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;repositories&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - https://packages.wolfi.dev/os
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#39;@local /work/packages&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;packages&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - hello-crud@local
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;accounts&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;groups&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#0087ff&#34;&gt;groupname&lt;/span&gt;: nonroot
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0087ff&#34;&gt;gid&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;65532&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;users&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#0087ff&#34;&gt;username&lt;/span&gt;: nonroot
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0087ff&#34;&gt;uid&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;65532&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;run-as&lt;/span&gt;: nonroot
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;environment&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;PATH&lt;/span&gt;: /usr/share/webapps/hello-server/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/sbin:/sbin:/bin
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;work-dir&lt;/span&gt;: /usr/share/webapps/hello-server/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;entrypoint&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;command&lt;/span&gt;: gunicorn -w 2 -b 0.0.0.0:8000 --access-logfile - --error-logfile - app:app&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;apko.yaml&lt;/p&gt;
&lt;p&gt;No nosso apko declaramos os repositórios da chainguard (ou alpine), os pacotes: no nosso caso apenas o pacote da nossa app, o usuário não root e as condições pro nosso app rodar como variaveis de ambiente e o comando entrypoint.&lt;/p&gt;
&lt;p&gt;Para buildar nossa imagem:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;docker run --rm --workdir /work -v ${PWD}:/work cgr.dev/chainguard/apko build apko.yaml hello-crud:test hello-crud-server.tar --arch host&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Cuidado que a imagem não é carregada automaticamente no docker, você precisa fazer docker image load -i hello-crud-server.tar&lt;/p&gt;
&lt;p&gt;E o resultado? A imagem ficou com 65MB \o/&lt;/p&gt;
&lt;p&gt;Em retrospectiva a nossa primeira versão do dockerfile tinha 570MB, a versão multistage usando debian 190MB e agora quase 10x menor com 65MB, não vai embora ainda não porque vamos melhorar ainda mais.&lt;/p&gt;
&lt;h2 id=&#34;distroless-sem-o-melange-e-apko&#34;&gt;Distroless sem o melange e apko&lt;/h2&gt;
&lt;p&gt;Na seção anterior mostrei como usar o melange e o apko para declarativamente criar imagens mínimas para sua aplicação, porém é um sistema de build dedicado que você vai ter que aprender e manter, minha intenção era mostrar que não é um bicho de sete cabeças , pelo contrário o melange e o apko são bastante amigáveis.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/dockerfile-hardening/build-systems.png&#34; loading=&#34;lazy&#34; width=&#34;500px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Porém pra quem não quiser aprender um novo sistema de build e não se importa em quebrar a cabeça fazendo um Dockerfile especializado temos essa alternativa.&lt;/p&gt;
&lt;p&gt;A peça crítica para esse Dockerfile funcionar é que o gerenciador de pacotes apk suporta chroot, ou seja podemos instalar pacotes em outro sistema de arquivos por &amp;ldquo;fora da caixa&amp;rdquo;, sem precisarmos instalar o apk em si ou ter um shell para conseguir rodar qualquer comando durante o build.&lt;/p&gt;
&lt;p&gt;talk is cheap, show me the code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;28
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;29
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;30
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;31
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;32
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;33
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;34
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;35
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;36
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;37
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;38
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;39
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;40
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;41
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;42
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;43
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;44
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;45
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;46
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;47
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;48
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;49
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;50
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;51
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;52
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;53
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;54
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;55
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;56
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;57
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;58
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;59
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-dockerfile&#34; data-lang=&#34;dockerfile&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;ARG&lt;/span&gt; &lt;span style=&#34;color:#0087ff&#34;&gt;ROOTFS&lt;/span&gt;=/new_root
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;ARG&lt;/span&gt; &lt;span style=&#34;color:#0087ff&#34;&gt;pyversion&lt;/span&gt;=&lt;span style=&#34;color:#00afaf&#34;&gt;3&lt;/span&gt;.12
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4e4e4e&#34;&gt;# nonroot user&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;ARG&lt;/span&gt; &lt;span style=&#34;color:#0087ff&#34;&gt;PGID&lt;/span&gt;=&lt;span style=&#34;color:#00afaf&#34;&gt;1000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;ARG&lt;/span&gt; &lt;span style=&#34;color:#0087ff&#34;&gt;PUID&lt;/span&gt;=&lt;span style=&#34;color:#00afaf&#34;&gt;1000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; cgr.dev/chainguard/wolfi-base AS appbuilder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;ARG&lt;/span&gt; pyversion
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;RUN&lt;/span&gt; apk add python-&lt;span style=&#34;color:#00afaf&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;pyversion&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;}&lt;/span&gt; py&lt;span style=&#34;color:#00afaf&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;pyversion&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;}&lt;/span&gt;-pip python-&lt;span style=&#34;color:#00afaf&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;pyversion&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;}&lt;/span&gt;-dev build-base openssl-dev &amp;amp;&amp;amp; &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    rm -rf /var/cache/apk/*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;USER&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; nonroot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;WORKDIR&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; /home/nonroot/app&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;COPY&lt;/span&gt; --chown=nonroot:nonroot . /home/nonroot/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;RUN&lt;/span&gt; python3 -m venv .venv &amp;amp;&amp;amp; . .venv/bin/activate &amp;amp;&amp;amp; &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    pip3 install --no-compile --no-cache-dir -r requirements.txt &amp;amp;&amp;amp; &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    pip3 uninstall -y pip
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; cgr.dev/chainguard/wolfi-base AS chrootbuilder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;ARG&lt;/span&gt; ROOTFS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;ARG&lt;/span&gt; pyversion
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;ARG&lt;/span&gt; PGID
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;ARG&lt;/span&gt; PUID
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;RUN&lt;/span&gt; mkdir -p &lt;span style=&#34;color:#0087ff&#34;&gt;$ROOTFS&lt;/span&gt;/etc/apk/keys &amp;amp;&amp;amp; &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    cp -v /etc/apk/keys/* &lt;span style=&#34;color:#0087ff&#34;&gt;$ROOTFS&lt;/span&gt;/etc/apk/keys/ &amp;amp;&amp;amp; &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    cp -v /etc/apk/repositories  &lt;span style=&#34;color:#0087ff&#34;&gt;$ROOTFS&lt;/span&gt;/etc/apk/repositories
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;RUN&lt;/span&gt; apk add shadow &amp;amp;&amp;amp; &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    rm -rf /var/cache/apk/*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;RUN&lt;/span&gt; apk add --no-commit-hooks --root &lt;span style=&#34;color:#0087ff&#34;&gt;$ROOTFS&lt;/span&gt; --initdb glibc glibc-locale-posix &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    python-&lt;span style=&#34;color:#00afaf&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;pyversion&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;}&lt;/span&gt; &amp;amp;&amp;amp;&lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    rm -rf &lt;span style=&#34;color:#0087ff&#34;&gt;$ROOTFS&lt;/span&gt;/var/cache/apk/*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;RUN&lt;/span&gt; groupadd -g &lt;span style=&#34;color:#00afaf&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;PGID&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;}&lt;/span&gt; -R &lt;span style=&#34;color:#0087ff&#34;&gt;$ROOTFS&lt;/span&gt; nonroot &amp;amp;&amp;amp;&lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    useradd -u &lt;span style=&#34;color:#00afaf&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;PUID&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;}&lt;/span&gt; -g nonroot -m --shell /bin/sh -R &lt;span style=&#34;color:#0087ff&#34;&gt;$ROOTFS&lt;/span&gt; nonroot
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; scratch AS runtime&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;ARG&lt;/span&gt; ROOTFS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;COPY&lt;/span&gt; --from=chrootbuilder &lt;span style=&#34;color:#0087ff&#34;&gt;$ROOTFS&lt;/span&gt; /
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;USER&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; nonroot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;WORKDIR&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; /home/nonroot/app&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;COPY&lt;/span&gt; --chown=nonroot:nonroot --from=appbuilder /home/nonroot/app/ /home/nonroot/app/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;ENV&lt;/span&gt; &lt;span style=&#34;color:#0087ff&#34;&gt;PATH&lt;/span&gt;=&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;/home/nonroot/app/.venv/bin:&lt;/span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;$PATH&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;EXPOSE&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt; 8000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;CMD&lt;/span&gt; [ &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;gunicorn&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;-w&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;-b&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;0.0.0.0:8000&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;--access-logfile&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt; , &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;--error-logfile&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;app:app&amp;#34;&lt;/span&gt; ]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Dockerfile-v4&lt;/p&gt;
&lt;p&gt;O Dockerfile tem 3 estágios: um que faz o &amp;ldquo;build&amp;rdquo; do nosso venv e da app, um que gera o ambiente chroot com as dependências de tempo de execução e o estágio final que junta os dois. Fiz dessa forma para separar a nossa &amp;ldquo;imagem base&amp;rdquo; com o runtime de python, que é desacoplado da nossa app e o build do venv que aí sim depende da nossa app, dessa forma rebuilds com cache só fazem o build o que mudou.&lt;/p&gt;
&lt;p&gt;O grande pulo do gato é o uso das flags do apk: -R apontando para chroot, &amp;ndash;no-commit-hooks pois os hooks não se aplicam quando usando chroots e &amp;ndash;initdb para inicializar o database do apk, sem isso o database não será gerado e ferramentas de SBOM não funcionam.&lt;/p&gt;
&lt;p&gt;E o resultado? O tamanho ficou muito próximo do apko (65MB), com apenas alguns KBs de diferença.&lt;/p&gt;
&lt;h2 id=&#34;glibc-vs-musl-o-inimigo-agora-é-outro&#34;&gt;glibc vs musl: O inimigo agora é outro&lt;/h2&gt;
&lt;p&gt;Quanto comecei minha jornada com Docker e comecei a colocar meus apps Python no docker, na época pelo menos era inviável usar imagens base alpine pois não tinha os wheels pré-compilados para biblioteca padrão c musl do alpine então qualquer app que precisava do numpy o build demorava demais pra compilar, então deixei de lado as imagens alpine.&lt;/p&gt;
&lt;p&gt;Mas agora quando tentei novamente o pypi tem os wheels pré-compilados pro musl e outras arquiteturas como o arm \o/&lt;/p&gt;
&lt;p&gt;Porém as imagens da chainguard apesar de serem baseadas no alpine não utilizam a musl, mas sim a implementação mais difundida a glibc, tem um artigo deles bastante completo explicando o diversos aspectos por trás dessa decisão, como compatibilidade com binários dinamicamente linkados:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://edu.chainguard.dev/chainguard/chainguard-images/about/images-compiled-programs/glibc-vs-musl/&#34;&gt;glibc vs. musl -- Chainguard&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;O dockerfile ficou igual ao dockerfile-v4, porém mudando a imagem base do wolfi para a release mais recente do alpine (alpine:3.23). E o tamanho da imagem ficou uns ~15MB menor que a do melange (50MB).&lt;/p&gt;
&lt;p&gt;Bora fazer uma retrospectiva de como foi evoluindo o tamanho da nossa imagem Python? Podemos ver na tabela abaixo que começamos com o nosso Dockerfile v0 bem tradicional com quase 600MB e com o multistage o tamanho caiu para um quarto da v0 e metade disso usando distroless.&lt;/p&gt;





&lt;table class=&#34;table w-auto table-sm table-striped table-hover table-bordered&#34;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:left&#34;&gt;Versão&lt;/th&gt;
&lt;th style=&#34;text-align:left&#34;&gt;Tamanho [MB]&lt;/th&gt;
&lt;th style=&#34;text-align:left&#34;&gt;Percentual de v0&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;v0&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;570&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;v1 (delete dos caches e índices)&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;520&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;91%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;v2 (multistage)&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;130&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;22%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;v4 (distroless chroot/melange)&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;65&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;11%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;v5 (distroless com alpine+musl)&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;50&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;9%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Observação: Omitimos a v3 pois nela o objetivo era migrar para imagens baseadas em alpine, sem o foco em otimizar seu tamanho.&lt;/p&gt;
&lt;h2 id=&#34;hadolint&#34;&gt;Hadolint&lt;/h2&gt;
&lt;p&gt;Pra fechar o texto, a última dica é utilizar o Hadolint (&lt;a href=&#34;https://github.com/hadolint/hadolint&#34;&gt;github.com/hadolint/hadolint&lt;/a&gt;), ele dá excelentes dicas para as boas práticas de que falamos aqui, tem extensão pro VSCode e de quebra roda o outro linter excelente para shell &lt;a href=&#34;http://shellcheck.net/&#34;&gt;shellcheck.net&lt;/a&gt; dentro das instruções RUN, então você leva dois linters dentro de um.&lt;/p&gt;
&lt;h2 id=&#34;conclusão&#34;&gt;Conclusão&lt;/h2&gt;
&lt;p&gt;Resgatando a provocação inicial, espero a essa altura ter te convencido de que dockerfile não é tudo igual, que não posta a aplicação funcionar para termos um bom dockerfile.&lt;/p&gt;
&lt;p&gt;O princípio que mais exploramos é tornar a imagem enxuta possível, pois além de imagens menores serem mais performáticas, elas têm uma superfície de ataque menor e dessa forma conseguimos identificar quais dependências são realmente necessárias em tempo de execução da aplicação.&lt;/p&gt;
&lt;p&gt;Para &amp;ldquo;enxugar&amp;rdquo; as imagens vimos como o dive é uma ferramenta muito prática para dissecar camada a camada as imagens e identificar os pontos de melhoria, e o conceito de multi-stage para separar o build e o runtime.&lt;/p&gt;
&lt;p&gt;Por fim, levando ao extremo o objetivo do multi-stage , vimos o conceito das imagens distroless e como fazer elas com o melange e o apko, porém o desafio de debugar essas imagens.&lt;/p&gt;
&lt;p&gt;Espero que esse texto te auxilie a criar imagens Docker melhores e muito obrigado por chegar até aqui!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>ansible localhost -a &#34;/bin/echo Primeiros passos com o Ansible&#34;</title>
      <link>https://caioau.net/blog/intro-ansible/</link><category>computando-arte</category>
		  <category>texto</category>
		  <category>linux</category>
		  <category>devops</category>
		  <category>ansible</category>
		  
      <pubDate>Tue, 12 Jul 2022 10:00:00 -0300</pubDate>
      
      <guid>https://caioau.net/blog/intro-ansible/</guid><description>&lt;p&gt;Obs.: Originalmente publicado no &lt;a href=&#34;https://caioau.net/blog/computando-arte/&#34;&gt;computando-arte&lt;/a&gt; dia 12Jul2022&lt;/p&gt;
&lt;p&gt;Lembra quando precisou configurar pela primeira vez seu computador? Possivelmente precisou instalar o git, docker, VSCode, um navegador decente, um &lt;a href=&#34;https://medium.com/computando-arte/oh-my-zsh-deixando-seu-terminal-mais-interessante-61a34b3f8fde?source=collection_home---2------20-----------------------&#34;&gt;shell bacana como o zsh&lt;/a&gt;, mó trampo né?&lt;/p&gt;
&lt;p&gt;Hoje vamos falar de uma ferramenta de automação de configuração, o Ansible, que permite que a configuração e manutenção dos ambientes seja feita de forma automatizada, poupando bastante tempo.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/intro-ansible/ansible_logo.png&#34; loading=&#34;lazy&#34;
         alt=&#34;logo do Ansible&#34; width=&#34;200px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;logo do Ansible&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;O que é o Ansible? O &lt;a href=&#34;https://www.ansible.com/&#34;&gt;Ansible&lt;/a&gt; é uma ferramenta de automação de configuração e manutenção de ambientes, e atua agilizando e escalando essas atividades.&lt;/p&gt;
&lt;p&gt;As principais vantagens do Ansible são sua facilidade de aprendizado, e não ter a necessidade de instalar um agente da ferramenta nas máquinas gerenciadas. A desvantagem acaba sendo que como não existe um agente executando o Ansible este processo não escala bem, ou seja para gerenciar muitos computadores o nó de controle do Ansible precisa ser potente.&lt;/p&gt;
&lt;h2 id=&#34;instalando-o-ansible&#34;&gt;Instalando o Ansible&lt;/h2&gt;
&lt;p&gt;Para instalar o Ansible é necessária a instalação da linguagem python e então basta instalar o executável através do pip install&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pip install ansible&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Uma funcionalidade que gosto muito no python são os ambientes virtuais (venv), eles são nativos da linguagem e permitem que você possa ter um “ambiente python” diferente para cada projeto, e assim instalar as dependências adequadas de cada projeto sem interferir nos demais.&lt;/p&gt;
&lt;p&gt;Normalmente o venv fica dentro da pasta do projeto, e é ignorado no .gitignore. Para criar o venv faça&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;python3 -m venv venv&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Agora toda vez que for utilizar o venv ative com:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;source&lt;/span&gt; venv/bin/activate&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Obs: se estiver usando zsh ou outro shell coloque a extensão do seu shell (no zsh ficaria activate.zsh).&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/intro-ansible/venv_prompt.png&#34; loading=&#34;lazy&#34; width=&#34;800px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Repare que o prompt (PS1) ficou diferente, contendo o nome do venv (venv).&lt;/p&gt;
&lt;p&gt;Para evitar problemas, a primeira vez que crio o venv atualizo o pip e outras ferramentas:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pip install -U pip setuptools wheel&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Com venv criado basta só instalar o ansible normalmente (pip install ansible).&lt;/p&gt;
&lt;p&gt;Bora testar a instalação? Rode o seguinte&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ansible -m ping localhost&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Se tiver a seguinte saída significa que deu bom:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[WARNING]: No inventory was parsed, only implicit localhost is available
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;localhost | SUCCESS =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;#34;changed&amp;#34;: false,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;#34;ping&amp;#34;: &amp;#34;pong&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Bora para o hello world?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ansible localhost -a &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;/bin/echo ola mundo&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[WARNING]: No inventory was parsed, only implicit localhost is available
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;localhost | CHANGED | rc=0 &amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ola mundo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;como-o-ansible-funciona&#34;&gt;Como o Ansible funciona?&lt;/h2&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/intro-ansible/ansible_diagram.png&#34; loading=&#34;lazy&#34; width=&#34;600px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;O Ansible é executado no nó de controle e conecta via o protocolo ssh nos nós gerenciados. Para executar a ferramenta recebe como entrada um arquivo de texto que é o inventário com informações dos nós gerenciados, como os IPs e credenciais. A outra entrada é o playbook, um arquivo no formato yaml, que contém as instruções a serem executadas.&lt;/p&gt;
&lt;p&gt;Um requisito para o ansible é que os nós gerenciados precisam do python instalado, porém é possível rodar o ansible de forma limitada para instalar o python para contornar isso ;)&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/intro-ansible/ssh_meme.png&#34; loading=&#34;lazy&#34;
         alt=&#34;Fonte: twitter.com/scienceshitpost&#34; width=&#34;600px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Fonte: &lt;a href=&#34;https://twitter.com/scienceshitpost&#34;&gt;twitter.com/scienceshitpost&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;montando-o-inventário&#34;&gt;Montando o inventário&lt;/h2&gt;
&lt;p&gt;Antes de montar o inventário precisamos de pelo menos uma máquina para conectarmos via ssh, no meu caso utilizei uma raspberrypi e uma máquina virtual. Sem enrolação, vamos ao inventário:&lt;/p&gt;
&lt;p&gt;inventario.ini:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[pies]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rpi4 ansible_host=&lt;span style=&#34;color:#00afaf&#34;&gt;192.168&lt;/span&gt;.&lt;span style=&#34;color:#00afaf&#34;&gt;1.205&lt;/span&gt; ansible_user=piuser ansible_password=pipass ansible_become=yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[vms]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rockylinux ansible_host=&lt;span style=&#34;color:#00afaf&#34;&gt;192.168&lt;/span&gt;.&lt;span style=&#34;color:#00afaf&#34;&gt;121.182&lt;/span&gt; ansible_user=rockyuser ansible_password=rockypass
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[vms:vars]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ansible_become=yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[all:vars]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ansible_port=&lt;span style=&#34;color:#00afaf&#34;&gt;22&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ansible_become_method=sudo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ansible_python_interpreter=python3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ansible_become_password=&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;{{ ansible_password }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;O inventário pode ser escrito no &lt;a href=&#34;https://en.wikipedia.org/wiki/INI_file&#34;&gt;formato ini&lt;/a&gt; ou no formato yaml, aqui optei pelo ini.&lt;/p&gt;
&lt;p&gt;Nesse exemplo foram definidas duas máquinas a rpi4 pertencente ao grupo pies e rockylinux pertencente ao grupo vms.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;E essas variáveis&lt;/em&gt;?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ansible_host&lt;/strong&gt; é o ip ou domínio da máquina.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ansible_port&lt;/strong&gt; é porta usada pelo ssh, por padrão é a 22, ou seja nem precisaríamos mudar no nosso caso.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ansible_user&lt;/strong&gt; e &lt;strong&gt;ansible_password&lt;/strong&gt; usuário e senha do ssh utilizados para conectar.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ansible_become&lt;/strong&gt; indica se deve elevar privilégios ou não, ou seja rodar como usuário root.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ansible_become_method&lt;/strong&gt; indica o método utilizado para elevar privilégios, aqui estamos utilizando o sudo, mas poderia ser su e utilizar a senha do root.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;O inventário pode ser montado de diversas formas e tem várias outras variáveis, consulte a documentação para saber mais: &lt;a href=&#34;https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html&#34;&gt;How to build your inventory&lt;/a&gt;. Uma coisa que gosto de fazer é utilizar a opção ansible_ssh_common_args com -F ssh_config, onde ssh_config (&lt;a href=&#34;https://man.openbsd.org/ssh_config&#34;&gt;man page&lt;/a&gt;) é um arquivo de configuração do ssh.&lt;/p&gt;
&lt;p&gt;As vezes não conseguimos acessar diretamente todas as máquinas, pois é exposto apenas uma máquina, chamada de bastião que atua como proxy para acessar as outras máquinas dentro da rede privada. No ssh_config podemos usar a opção ProxyJump.&lt;/p&gt;
&lt;p&gt;Outra vantagem é que fica mais fácil de acessar manualmente uma máquina, basta fazer &lt;code&gt;ssh -F ssh_config nome_maquina&lt;/code&gt; e pronto ;)&lt;/p&gt;
&lt;p&gt;Bora testar o inventário? Rode&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ansible -m ping -i inventario.ini all&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Putz, deu ruim, &lt;strong&gt;to use the &amp;lsquo;ssh&amp;rsquo; connection type with passwords or pkcs11_provider, you must install the sshpass program .&lt;/strong&gt; Por padrão o ansible conecta autenticando com chaves ssh, não a senha, então precisamos instalar o sshpass. Bastou um sudo apt install sshpass , pra quem tem mac tem um pacote no brew (brew install hudochenkov/sshpass/sshpass).&lt;/p&gt;
&lt;p&gt;Agora foi:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rockylinux | SUCCESS =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;#34;changed&amp;#34;: false,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;#34;ping&amp;#34;: &amp;#34;pong&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rpi4 | SUCCESS =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;#34;changed&amp;#34;: false,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;#34;ping&amp;#34;: &amp;#34;pong&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;rodando-comandos-adhoc&#34;&gt;Rodando comandos adhoc&lt;/h2&gt;
&lt;p&gt;Até aqui só fizemos &lt;code&gt;-m ping&lt;/code&gt;, mas podemos fazer praticamente qualquer coisa, no ansible as tarefas são executadas através de módulos e vamos mostrar alguns deles aqui.&lt;/p&gt;
&lt;p&gt;Caso não seja especificado nenhum módulo o ansible executa por padrão o módulo command, vou executar o comando hostnamectl, que exibe diversas informações do computador:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ansible -i inventario.ini -a hostnamectl all&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rockylinux | CHANGED | rc=0 &amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   Static hostname: localhost.localdomain
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         Icon name: computer-vm
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           Chassis: vm
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Machine ID: 3d137ab51d6c4a1098281d0f08170bce
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           Boot ID: 95f4fb49069040b484410562dbbf344c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Virtualization: kvm
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Operating System: Rocky Linux 8.6 (Green Obsidian)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       CPE OS Name: cpe:/o:rocky:rocky:8:GA
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Kernel: Linux 4.18.0-372.9.1.el8.x86_64
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Architecture: x86-64
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rpi4 | CHANGED | rc=0 &amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   Static hostname: rpi4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         Icon name: computer
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Machine ID: 8e5eb04e49a74e26952554ad422b19fb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           Boot ID: 18563abe0fa6420fb55488b28401304e
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Operating System: Debian GNU/Linux 11 (bullseye)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Kernel: Linux 5.10.0-15-arm64
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Architecture: arm64
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Deu bom! Conseguimos visualizar as infos sobre as máquinas. Por curiosidade, &lt;em&gt;qual é desse rockylinux&lt;/em&gt;? A redhat descontinuou o centos em dez/2020, que é uma versão gratuita e comunitária do redhat enterprise linux (RHEL) e com o fim do centos dois projetos surgiram como sucessores compatíveis ao centos, o rockylinux e o almalinux.&lt;/p&gt;
&lt;p&gt;Bora instalar um pacote como o neofetch? &lt;em&gt;Só mandar um sudo apt install neofetch, certo&lt;/em&gt;? No nosso caso uma máquina tem uma distro baseada em redhat ou seja não utiliza o gerenciador de pacotes apt, mas o dnf. Por isso vamos utilizar o módulo package que é genérico e funciona com diversos gerenciadores de pacotes.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/intro-ansible/xkcd1654.png&#34; loading=&#34;lazy&#34;
         alt=&#34;xkcd #1654&#34; width=&#34;300px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;a href=&#34;https://xkcd.com/1654/&#34;&gt;xkcd #1654&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Vendo a documentação do &lt;a href=&#34;https://docs.ansible.com/ansible/2.9/modules/package_module.html#package-module&#34;&gt;módulo package&lt;/a&gt;, temos 3 argumentos, dos quais apenas 2 são obrigatórios, o nome dos pacotes (name) e o estado (state) como instalado (present) ou removido (absent).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ansible -i inventario.ini -m package -a &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;name=neofetch state=present&amp;#34;&lt;/span&gt; all&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rpi4 | CHANGED =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;cache_update_time&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;1655557364&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;cache_updated&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d75f00&#34;&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;changed&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d75f00&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;stderr&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;stderr_lines&amp;#34;&lt;/span&gt;: [],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;stdout&amp;#34;&lt;/span&gt;: &amp;#34;Reading &lt;span style=&#34;color:#d75f00&#34;&gt;package&lt;/span&gt; lists...\nBuilding dependency tree… [...]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Rodando o neofetch: &lt;code&gt;ansible -i inventario.ini -a neofetch all&lt;/code&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/intro-ansible/output_neofetch.png&#34; loading=&#34;lazy&#34; width=&#34;600px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Uma opção que facilita muito é a &lt;code&gt;--limit&lt;/code&gt; que como o nome sugere limita a execução a algumas máquinas, pode ser especificada múltiplas vezes. Até então utilizamos o all que executa em todas as máquinas. Você pode trocar o all por um grupo(s) ou máquina(s) . E também podemos limitar qual não queremos que sejam incluídas, utilizando o ! como operador de negação.&lt;/p&gt;
&lt;p&gt;Por exemplo, queremos reiniciar todas as máquinas, excepto as que pertencem ao grupo vms:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ansible -i inventario.ini -m reboot all --limit !vms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rpi4 | CHANGED =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;#34;changed&amp;#34;: true,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;#34;elapsed&amp;#34;: 68,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;#34;rebooted&amp;#34;: true
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;usando-o-ansible-vault-para-proteger-segredos&#34;&gt;Usando o ansible-vault para proteger segredos&lt;/h2&gt;
&lt;p&gt;Quando criamos o inventário, colocamos as credenciais de acesso, isso não é uma boa prática pois pode acabar expondo essas credenciais. O que podemos fazer nesses casos?&lt;/p&gt;
&lt;p&gt;Uma opção simples é tirar as senhas do inventário e digitar apenas quando precisar, utilizando as opções &amp;ndash;ask-pass (ou abreviando -k) e &amp;ndash;ask-become-pass (abreviando -K).&lt;/p&gt;
&lt;p&gt;Mas vamos focar na abordagem do ansible-vault, que funciona como um gerenciador de senhas, onde os  segredos ficam armazenados em um arquivo que está protegido por uma única senha.&lt;/p&gt;
&lt;p&gt;Para usar o ansible-vault vamos primeiro tirar as senhas do inventário:&lt;/p&gt;
&lt;p&gt;inventario.ini:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[pies]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rpi4 ansible_host=&lt;span style=&#34;color:#00afaf&#34;&gt;192.168&lt;/span&gt;.&lt;span style=&#34;color:#00afaf&#34;&gt;1.205&lt;/span&gt; ansible_user=piuser  ansible_password=&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;{{ rpi4_pass }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[vms]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rockylinux ansible_host=&lt;span style=&#34;color:#00afaf&#34;&gt;192.168&lt;/span&gt;.&lt;span style=&#34;color:#00afaf&#34;&gt;121.182&lt;/span&gt; ansible_user=rockyuser ansible_password=&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;{{ rocky_vm_pass }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[all:vars]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ansible_become=yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ansible_become_method=sudo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ansible_python_interpreter=python3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ansible_become_password=&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;{{ ansible_password }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Repare que em ambas as máquinas a variável a ansible_password estão sendo recebidas como referência.&lt;/p&gt;
&lt;p&gt;Crie um arquivo que vamos chamar de vault.yml&lt;/p&gt;
&lt;p&gt;vault.yml&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;rpi4_pass&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#39;pipass&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;rocky_vm_pass&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#39;rockypass&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Agora que a mágica acontece, vamos criptografar o arquivo: &lt;code&gt;ansible-vault encrypt vault.yml&lt;/code&gt; e digite a senha desejada. Por curiosidade, bora ver o conteúdo do arquivo?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ANSIBLE_VAULT;1.1;AES256
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;33303863323038363938333365326637343733313432626231623735666433303965333266383934
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;6332633534626465353436666539646466633633393362370a353161653663633263663635643466
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[...]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Quando precisar editar o vault, basta fazer &lt;code&gt;ansible-vault edit vault.yml&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;E para carregar os segredos definidos no vault vamos usar a opção &amp;ndash;extra-vars (abreviada por -e) onde podemos fazer -e “var=value” mas vamos apontar para um arquivo então -e @vault.yml. E a opção &amp;ndash;ask-vault-pass para entrar com a senha do vault&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ansible -i inventario.ini -m ping all -e @vault.yml --ask-vault-pass&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rockylinux | SUCCESS =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;#34;changed&amp;#34;: false,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;#34;ping&amp;#34;: &amp;#34;pong&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rpi4 | SUCCESS =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;#34;changed&amp;#34;: false,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;#34;ping&amp;#34;: &amp;#34;pong&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;Preciso digitar a senha do vault toda vez&lt;/em&gt;? Não necessariamente, uma abordagem é colocar a senha em um arquivo local e utilizar a opção &amp;ndash;vault-password-file , mas sou preguiçoso :P e vou deixar configurado em um arquivo de configuração, o ansible.cfg edai fica tudo setado lá 😊&lt;/p&gt;
&lt;p&gt;ansible.cfg&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[defaults]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;host_key_checking = True
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;inventory = inventario.ini
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vault_password_file = ../.arquivo_com_a_senha.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Documentação com todas opções do ansible.cfg: &lt;a href=&#34;https://docs.ansible.com/ansible/latest/reference_appendices/config.html&#34;&gt;Ansible Configuration Settings&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Outra abordagem é a conhecida pela buzzword GitOps, que consiste em rodar o ansible no próprio repositório onde ficam os playbooks do ansible, utilizando um sistema de integração contínua, como &lt;a href=&#34;https://medium.com/computando-arte/introdu%C3%A7%C3%A3o-a-ci-no-github-actions-5b6e9ad1bb64?source=collection_home---2------5-----------------------&#34;&gt;github actions que falamos anteriormente aqui&lt;/a&gt;. Dessa forma a senha do vault pode ser passada via variável de ambiente e colocada em temporariamente um arquivo ou via argumento do comando.&lt;/p&gt;
&lt;h2 id=&#34;escrevendo-nosso-primeiro-playbook&#34;&gt;Escrevendo nosso primeiro playbook&lt;/h2&gt;
&lt;p&gt;Chegou a hora! Bora escrever nosso primeiro playbook. Para isso vamos subir um servidor web, o apache, para hospedar um site um site estático.&lt;/p&gt;
&lt;p&gt;Quando fui instalar o apache no rockylinux deu ruim, porque o pacote no debian é o apache2 mas no rockylinux é httpd. &lt;em&gt;Como faz agora&lt;/em&gt;? &lt;em&gt;Como eu faço pro ansible detectar que a máquina é o rockylinux ou debian e tratar adequadamente cada caso&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;A ferramenta roda automaticamente um módulo chamado setup que obtém diversas infos das máquinas, e disponibiliza em uma variável chamada ansible_facts.&lt;/p&gt;
&lt;p&gt;Fazendo &lt;code&gt;ansible -m setup -e @vault.yml all&lt;/code&gt; obtive:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rpi4 | SUCCESS =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;ansible_facts&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;ansible_all_ipv4_addresses&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;192.168.1.205&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [...]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;ansible_distribution&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;Debian&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;ansible_distribution_file_parsed&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#0087ff&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;ansible_distribution_file_path&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;/etc/os-release&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;ansible_distribution_file_variety&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;Debian&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;ansible_distribution_major_version&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;11&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;ansible_distribution_release&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;bullseye&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;ansible_distribution_version&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;11&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;ansible_os_family&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;Debian&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [...]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rockylinux | SUCCESS =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;ansible_facts&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;ansible_all_ipv4_addresses&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;192.168.121.182&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [...]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;ansible_distribution&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;Rocky&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;ansible_distribution_file_parsed&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#0087ff&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;ansible_distribution_file_path&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;/etc/redhat-release&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;ansible_distribution_file_variety&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;RedHat&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;ansible_distribution_major_version&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;8&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;ansible_distribution_release&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;Green Obsidian&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;ansible_distribution_version&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;8.6&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;ansible_os_family&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;RedHat&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [...]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Com isso, podemos usar a variável ansible_distribution (Debian e Rocky) ou ansible_os_family (Debian e RedHat), optei pela ansible_os_family para que nosso playbook seja mais genérico.&lt;/p&gt;
&lt;p&gt;playbook.yml&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#0087ff&#34;&gt;name&lt;/span&gt;: Configura um site estatico.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;hosts&lt;/span&gt;: all
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;become&lt;/span&gt;: &lt;span style=&#34;color:#d75f00&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;vars&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;apache_name_dict&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0087ff&#34;&gt;&amp;#34;Debian&amp;#34;: &lt;/span&gt;apache2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0087ff&#34;&gt;&amp;#34;RedHat&amp;#34;: &lt;/span&gt;httpd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;handlers&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#0087ff&#34;&gt;name&lt;/span&gt;: restart apache
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0087ff&#34;&gt;service&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;{{ apache_name_dict[ansible_os_family] }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;state&lt;/span&gt;: restarted
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;tasks&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#0087ff&#34;&gt;name&lt;/span&gt;: Instala o apache.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0087ff&#34;&gt;package&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;{{ apache_name_dict[ansible_os_family] }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;state&lt;/span&gt;: present
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#0087ff&#34;&gt;name&lt;/span&gt;: Copia o html da pag.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0087ff&#34;&gt;copy&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;src&lt;/span&gt;: page.html
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;remote_src&lt;/span&gt;: &lt;span style=&#34;color:#d75f00&#34;&gt;no&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;dest&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;/var/www/html/index.html&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;0664&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0087ff&#34;&gt;notify&lt;/span&gt;: restart apache
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#0087ff&#34;&gt;name&lt;/span&gt;: Habilita o servico do apache.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0087ff&#34;&gt;service&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;{{ apache_name_dict[ansible_os_family] }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;state&lt;/span&gt;: started
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;enabled&lt;/span&gt;: &lt;span style=&#34;color:#d75f00&#34;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;O playbook funciona da seguinte forma:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Primeiro é instalado o pacote do apache, usando uma variável para mapear o nome correto do pacote.&lt;/li&gt;
&lt;li&gt;Copia o html do nosso site, o html precisa estar localizado ao lado do playbook, mas caso o arquivo já estivesse no nó gerenciado basta trocar a opção remote_src para yes.&lt;/li&gt;
&lt;li&gt;Habita o serviço do apache para que o mesmo seja iniciado automaticamente quando a máquina é iniciada.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;O que é esse notify na task de copiar o html? Pense no seguinte: depois de copiar o html preciso que o apache seja reiniciado para carregar o html da página que acabamos de enviar, mas e se o html que estiver lá não foi alterado? Dessa forma o Ansible só reinicia o apache caso necessário, chamando o handler previamente definido.&lt;/p&gt;
&lt;p&gt;Bora escrever sem usar o handler, pra ficar mais claro?&lt;/p&gt;
&lt;p&gt;playbook2.yml&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#0087ff&#34;&gt;name&lt;/span&gt;: Configura um site estatico.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;hosts&lt;/span&gt;: all
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;become&lt;/span&gt;: &lt;span style=&#34;color:#d75f00&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;vars&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;apache_name_dict&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0087ff&#34;&gt;&amp;#34;Debian&amp;#34;: &lt;/span&gt;apache2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0087ff&#34;&gt;&amp;#34;RedHat&amp;#34;: &lt;/span&gt;httpd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;tasks&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#0087ff&#34;&gt;name&lt;/span&gt;: Instala o apache.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0087ff&#34;&gt;package&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;{{ apache_name_dict[ansible_os_family] }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;state&lt;/span&gt;: present
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#0087ff&#34;&gt;name&lt;/span&gt;: Copia o html da pag.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0087ff&#34;&gt;copy&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;src&lt;/span&gt;: page.html
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;remote_src&lt;/span&gt;: &lt;span style=&#34;color:#d75f00&#34;&gt;no&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;dest&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;/var/www/html/index.html&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;0664&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0087ff&#34;&gt;register&lt;/span&gt;: html_copy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#0087ff&#34;&gt;name&lt;/span&gt;: restart apache.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0087ff&#34;&gt;service&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;{{ apache_name_dict[ansible_os_family] }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;state&lt;/span&gt;: restarted
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0087ff&#34;&gt;when&lt;/span&gt;: html_copy.changed
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#0087ff&#34;&gt;name&lt;/span&gt;: Habilita o servico do apache.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0087ff&#34;&gt;service&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;{{ apache_name_dict[ansible_os_family] }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;state&lt;/span&gt;: started
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;enabled&lt;/span&gt;: &lt;span style=&#34;color:#d75f00&#34;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Nessa versão do playbook, repare que na task de copiar o html estamos fazendo register: html_copy como o nome sugere estamos registrando o resultado daquela task em uma variável. E na task de reiniciar o apache é acionada apenas quando mudou, em when: html_copy.changed.&lt;/p&gt;
&lt;p&gt;Para rodar o comando é sugestivo: &lt;code&gt;ansible-playbook -e @vault.yml playbook.yml&lt;/code&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/intro-ansible/output_playbook.png&#34; loading=&#34;lazy&#34; width=&#34;800px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Será que o site tá de pé? Abrindo o navegador no ip da VM:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/intro-ansible/html_page.png&#34; loading=&#34;lazy&#34; width=&#34;600px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Uma coisa que você precisa ficar de olho quando escreve seus playbooks é se eles são idempotentes, que significa que o efeito de rodar o playbook é o mesmo independente de quantas vezes o mesmo foi executado. Para quem curte linguagens funcionais tá ligado qualé: O playbook não pode ter efeitos colaterais.&lt;/p&gt;
&lt;p&gt;Na prática, assim que rodar a primeira vez execute novamente e veja no final se teve alguma task como changed.&lt;/p&gt;
&lt;p&gt;O principal desafio para tornar os playbooks idempotentes acontece quando as tasks são do tipo command ou shell, afinal como o ansible vai saber se a task foi executada anteriormente com sucesso?&lt;/p&gt;
&lt;p&gt;Nesses casos, uma possibilidade é utilizar o parâmetro chamado creates, disponível nos módulos de command e shell, que aponta para um arquivo marcador que seu shell script ou command precisa criar quando executado com sucesso.&lt;/p&gt;
&lt;p&gt;Bora ver na prática?&lt;/p&gt;
&lt;p&gt;playbook3.yml&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#0087ff&#34;&gt;hosts&lt;/span&gt;: all
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;become&lt;/span&gt;: &lt;span style=&#34;color:#d75f00&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;tasks&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#0087ff&#34;&gt;name&lt;/span&gt;: inicializa um arquivo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0087ff&#34;&gt;shell&lt;/span&gt;: echo &amp;#34;passei por aqui&amp;#34; &amp;gt; /etc/marcador_xpto.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0087ff&#34;&gt;args&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0087ff&#34;&gt;creates&lt;/span&gt;: /etc/marcador_xpto.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Repare que quando executamos a primeira vez no recap a task foi changed, mas na segunda vez não houve mudanças.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/intro-ansible/output_playbook3.png&#34; loading=&#34;lazy&#34; width=&#34;800px&#34;/&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/intro-ansible/meme_shell.png&#34; loading=&#34;lazy&#34; width=&#34;500px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Quem tiver interesse, tem um texto excelente que até saiu no hacker news com várias dicas de como escrever scripts bash idempotentes: &lt;a href=&#34;https://arslan.io/2019/07/03/how-to-write-idempotent-bash-scripts/&#34;&gt;How to write idempotent Bash scripts &amp;ndash; Fatih Arslan&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;conclusão&#34;&gt;Conclusão&lt;/h2&gt;
&lt;p&gt;Uma regra de ouro é: Antes de sair automatizando, primeiro documente o processo manual, quais recursos sua aplicação precisa? Com os recursos disponíveis, como deve ser feita a configuração da aplicação? Dessa forma fica fácil de vislumbrar o todo e não precisa sair caçando nos códigos. Apesar do manifesto ágil dar preferência a ter um software funcional a documentação abrangente, sugiro não deixar de documentar no início essas definições.&lt;/p&gt;
&lt;p&gt;Para aprender ansible, a melhor referência é o livro do Jeff Geerling, &lt;a href=&#34;https://www.ansiblefordevops.com/&#34;&gt;Ansible for DevOps&lt;/a&gt; o livro tem vários exemplos e dicas. Pra quem prefere o formato de vídeos, no início da pandemia o autor trouxe o conteúdo do livro em forma de lives: &lt;a href=&#34;https://www.youtube.com/playlist?list=PL2_OBreMn7FqZkvMYt6ATmgC0KAGGJNAN&#34;&gt;Ansible 101 playlist&lt;/a&gt;. E pra quem prefere ir direto nos códigos os exemplos estão disponíveis nesse github: &lt;a href=&#34;https://github.com/geerlingguy/ansible-for-devops&#34;&gt;github.com/geerlingguy/ansible-for-devops&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Obrigado por acompanhar esse texto, espero que te ajude, caso tenha algum feedback ou dúvida não hesite em entrar em contato.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Como criar um pendrive de instalação com vários sistemas</title>
      <link>https://caioau.net/blog/ventoy/</link><category>computando-arte</category>
		  <category>texto</category>
		  <category>linux</category>
		  
      <pubDate>Sun, 08 May 2022 14:00:00 -0300</pubDate>
      
      <guid>https://caioau.net/blog/ventoy/</guid><description>&lt;h1 id=&#34;conheça-o-ventoy-a-ferramenta-que-nos-ajuda-a-fazer-isso&#34;&gt;Conheça o Ventoy, a ferramenta que nos ajuda a fazer isso&lt;/h1&gt;
&lt;p&gt;Obs.: Originalmente publicado no &lt;a href=&#34;https://caioau.net/blog/computando-arte/&#34;&gt;computando-arte&lt;/a&gt; dia 9Maio2022&lt;/p&gt;
&lt;p&gt;Quando vou ajudar alguém a formatar seu computador tenho esse problema, preciso levar vários pen drives preparados dependendo de qual sistema a pessoa quer instalar (como o Windows, o Ubuntu, PopOS, Manjaro e etc …). Isso acontece porque só dá para ter um sistema operacional por pen drive.&lt;/p&gt;
&lt;p&gt;Hoje vou falar de uma solução desse problema, criar um pen drive multiboot contendo vários sistemas em um único pen drive, utilizando o Ventoy 🤯&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/ventoy/feature_pic.jpg&#34; loading=&#34;lazy&#34;
         alt=&#34;Marvin Meyer, on unsplash&#34; width=&#34;600px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Marvin Meyer, on &lt;a href=&#34;https://unsplash.com/photos/SYTO3xs06fU&#34;&gt;unsplash&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;domando-o-destruidor-de-discos-dd&#34;&gt;Domando o destruidor de discos (dd)&lt;/h2&gt;
&lt;p&gt;Antes de mostrar o esquema multiboot, vou mostrar o esquema tradicional de gravar um pendrive usando o tradicional comando dd no Linux.&lt;/p&gt;
&lt;p&gt;Pra quem usa Windows calma aí que já mostro outra opção.&lt;/p&gt;
&lt;p&gt;A tarefa de gravar um pendrive bootável com o dd consiste de 6 tarefas, são elas:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Baixar a imagem do sistema operacional.&lt;/li&gt;
&lt;li&gt;Verificar se a imagem não está corrompida ou adulterada.&lt;/li&gt;
&lt;li&gt;Plugando o pendrive e identificando onde “subiu”.&lt;/li&gt;
&lt;li&gt;Fazer um umount no pendrive.&lt;/li&gt;
&lt;li&gt;De fato, gravando a imagem com o dd.&lt;/li&gt;
&lt;li&gt;Removendo o pendrive com segurança.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li&gt;Antes de tudo precisamos baixar a imagem .iso, que podemos encontrar no site do Ubuntu (&lt;a href=&#34;https://releases.ubuntu.com/&#34;&gt;releases.ubuntu.com&lt;/a&gt;). Usei o link abaixo:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget https://releases.ubuntu.com/20.04.4/ubuntu-20.04.4-desktop-amd64.iso&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;É de bom tom sempre verificar se imagem iso não está corrompida ou foi adulterada ;) , com este intuito vamos importar a chave de assinatura do ubuntu:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gpg --keyid-format long --keyserver hkp://keyserver.ubuntu.com --recv-keys 0x46181433FBB75451 0xD94AA3F0EFE21092&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Veja que as chaves foram importadas com sucesso:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gpg: key D94AA3F0EFE21092: public key &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;Ubuntu CD Image Automatic Signing Key (2012) &amp;lt;cdimage@ubuntu.com&amp;gt;&amp;#34;&lt;/span&gt; imported
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gpg: key 46181433FBB75451: public key &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;Ubuntu CD Image Automatic Signing Key &amp;lt;cdimage@ubuntu.com&amp;gt;&amp;#34;&lt;/span&gt; imported
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gpg: Total number processed: &lt;span style=&#34;color:#00afaf&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gpg:               imported: &lt;span style=&#34;color:#00afaf&#34;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Em seguida vamos baixar os hashes da imagem e a assinatura:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget https://releases.ubuntu.com/20.04.4/SHA256SUMS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget https://releases.ubuntu.com/20.04.4/SHA256SUMS.gpg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Verificando a assinatura:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gpg --verify SHA256SUMS.gpg SHA256SUMS&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Deu bom! Repare no resultado do comando (good signature &amp;hellip;)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gpg: Signature made qui &lt;span style=&#34;color:#00afaf&#34;&gt;24&lt;/span&gt; fev &lt;span style=&#34;color:#00afaf&#34;&gt;2022&lt;/span&gt; 17:36:20 -03
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gpg:                using RSA key 843938DF228D22F7B3742BC0D94AA3F0EFE21092
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gpg: Good signature from &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;Ubuntu CD Image Automatic Signing Key (2012) &amp;lt;cdimage@ubuntu.com&amp;gt;&amp;#34;&lt;/span&gt; [unknown] &lt;span style=&#34;color:#4e4e4e&#34;&gt;# &amp;lt;--------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gpg: WARNING: This key is not certified with a trusted signature!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gpg:          There is no indication that the signature belongs to the owner.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Primary key fingerprint: &lt;span style=&#34;color:#00afaf&#34;&gt;8439&lt;/span&gt; 38DF 228D 22F7 B374  2BC0 D94A A3F0 EFE2 &lt;span style=&#34;color:#00afaf&#34;&gt;1092&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Por fim, verificando a imagem:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sha256sum --ignore-missing -c SHA256SUMS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ubuntu-20.04.4-desktop-amd64.iso: OK&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&#34;3&#34;&gt;
&lt;li&gt;
&lt;p&gt;Tá safe! Bora gravar essa imagem. Para isto, antes de plugar o pen drive execute o comando lsblk para listar os dispositivos de armazenamento, então plugue o pendrive e execute o lsblk novamente e veja se “onde o pendrive subiu” (comparando quando rodou o lsblk a primeira vez), isto é, se foi conectado ao sdb, sdc ou sdd etc … Aqui “subiu” como sdb.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sempre bom fazer umount antes:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo umount /dev/sdb*&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&#34;5&#34;&gt;
&lt;li&gt;Finalmente gravando a imagem:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo dd &lt;span style=&#34;color:#5f8700&#34;&gt;if&lt;/span&gt;=ubuntu-20.04.4-desktop-amd64.iso &lt;span style=&#34;color:#0087ff&#34;&gt;of&lt;/span&gt;=/dev/sdb &lt;span style=&#34;color:#0087ff&#34;&gt;bs&lt;/span&gt;=1M &lt;span style=&#34;color:#0087ff&#34;&gt;status&lt;/span&gt;=progress ; sync&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Aponte para o endereço da imagem no argumento if, e aponte para o endereço do pen drive no argumento of. Preste atenção se de fato está apontando para o pen drive em /dev/sdb, não coloque a partição /dev/sdb1 ou 2, é só sdb!&lt;/p&gt;
&lt;p&gt;Observação: O comando sync faz com que a imagem completa seja de fato escrita no pendrive, não somente no cache.&lt;/p&gt;
&lt;ol start=&#34;6&#34;&gt;
&lt;li&gt;Espere a gravação finalizar (demora alguns minutos) e por fim vamos remover com segurança o pendrive:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo udisksctl power-off -b /dev/sdb&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;gravando-utilizando-o-etcher&#34;&gt;Gravando utilizando o etcher&lt;/h2&gt;
&lt;p&gt;Uma alternativa ao dd é utilizar o etcher, que está disponível no Windows, Mac e Linux, super simples de usar! Basta entrar no site &lt;a href=&#34;https://www.balena.io/etcher/&#34;&gt;balena.io/etcher/&lt;/a&gt; e baixar o programa, então selecionar a imagem iso, o pen drive e clicar em Flash!, conforme a figura abaixo:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/ventoy/print_ether.png&#34; loading=&#34;lazy&#34; width=&#34;600px&#34;/&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;multiboot-com-ventoy&#34;&gt;Multiboot com Ventoy&lt;/h2&gt;
&lt;p&gt;Chegou a hora de falar do Ventoy \o/&lt;/p&gt;
&lt;p&gt;Instalar o ventoy é tranquilo, basta ir na pagina de releases no Github do Ventoy &lt;a href=&#34;https://github.com/ventoy/Ventoy/releases/&#34;&gt;github.com/ventoy/Ventoy/releases/&lt;/a&gt;, estou utilizando a versão 1.0.73:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget https://github.com/ventoy/Ventoy/releases/download/v1.0.73/ventoy-1.0.73-linux.tar.gz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Verificando o download:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sha256sum ventoy-1.0.73-linux.tar.gz | grep ba1b61864598af2db662e393043c8759213869419ad95adb71fb5d92484f4b7d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Extraindo o tar:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tar xvf ventoy-1.0.73-linux.tar.gz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Gravando o ventoy:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo umount /dev/sdb*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;cd&lt;/span&gt; ventoy-1.0.73/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo ./Ventoy2Disk.sh -i /dev/sdb&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Quando finalizar a gravação, basta copiar as isos para uma partição que foi criada e sucesso.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/ventoy/print_particao.png&#34; loading=&#34;lazy&#34; width=&#34;600px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Quando ligar o computador, e apertar F12 (ou a tecla do seu fabricante) com esse pendrive a tela do ventoy vai aparecer, no qual você pode escolher qual das imagens será utilizada.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/ventoy/print_ventoy.png&#34; loading=&#34;lazy&#34;
         alt=&#34;Captura de tela do Ventoy, Fonte: ventoy.net/en/screenshot.html&#34; width=&#34;600px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Captura de tela do Ventoy, Fonte: &lt;a href=&#34;https://www.ventoy.net/en/screenshot.html&#34;&gt;ventoy.net/en/screenshot.html&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Quando precisar de outro sistema basta colocar a iso na partição do ventoy e usar! Muito prático!&lt;/p&gt;
&lt;p&gt;Testei e funcionou bootar tanto no modo legacy (MBR) quanto UEFI ^_^&lt;/p&gt;
&lt;p&gt;Adorei o Ventoy :) daqui para frente só preciso de um pendrive na minha caixa de ferramentas quando for atender alguém.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Por que e como fazer um blog técnico</title>
      <link>https://caioau.net/blog/comece-blog/</link><category>computando-arte</category>
		  <category>texto</category>
		  <category>medium</category>
		  <category>divulgacao-cientifica</category>
		  <category>rss</category>
		  
      <pubDate>Mon, 21 Mar 2022 14:00:00 -0300</pubDate>
      
      <guid>https://caioau.net/blog/comece-blog/</guid><description>&lt;p&gt;Obs.: Originalmente publicado no &lt;a href=&#34;https://caioau.net/blog/computando-arte/&#34;&gt;computando-arte&lt;/a&gt; dia 21Março2022&lt;/p&gt;
&lt;p&gt;Hoje vou falar de um hábito inesperado que passei a praticar durante a quarentena, o de compartilhar o conhecimento através de textos.&lt;/p&gt;
&lt;p&gt;Eu não era um bom aluno de português :/ mas hoje percebo a importância de conseguir se comunicar bem, e como faz toda diferença!&lt;/p&gt;
&lt;p&gt;Antes da pandemia, participava de algumas comunidades, hackerspaces e eventos (como a Cryptorave e a CasaHacker), e nesses espaços físicos são construídas diversas atividades colaborativamente.&lt;/p&gt;
&lt;p&gt;Edai veio a pandemia que mudou essas interações então comecei a criar esses registros dessas trocas.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/comece-blog/feature_pic.jpg&#34; loading=&#34;lazy&#34;
         alt=&#34;Mika Baumeister, unsplash&#34; width=&#34;600px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Mika Baumeister, &lt;a href=&#34;https://unsplash.com/photos/LaqL8nxiacc&#34;&gt;unsplash&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;acompanhe-referências-da-sua-área&#34;&gt;Acompanhe referências da sua área&lt;/h2&gt;
&lt;p&gt;O primeiro passo para começar a escrever é ler ;) quem escreve bem normalmente lê muito e na comunicação científica isso não é diferente. Veja o que outras pessoas falam, procure e acompanhe blogs e talks dessas pessoas. Preste atenção em alguns pontos: Como elas explicam determinado conceito? Quais analogias/comparações ela usa? E, principalmente, como apresentar isso para quem está começando e quais detalhes são importantes?&lt;/p&gt;
&lt;h2 id=&#34;decida-se-quer-ser-anônimo-ou-não&#34;&gt;Decida se quer ser anônimo ou não&lt;/h2&gt;
&lt;p&gt;Uma possibilidade é escrever sem se identificar, dessa forma você não “contamina” o debate com quem você é, onde você trabalha, onde você estudou, com que você interage, sua aparência, enfim, de onde você vem.&lt;/p&gt;
&lt;p&gt;Um exemplo disso é o &lt;a href=&#34;https://startupdareal.medium.com/&#34;&gt;Startup da Real&lt;/a&gt;, ele criou um perfil para expor os discursos de empreendedorismo. Depois de produzir vários textos aqui no medium ele amarrou esses textos em um livro chamado “Este livro não vai te deixar rico: Descubra a verdade sobre empreendedorismo, startups e a arte de ganhar dinheiro”. O startup da real, ou Alberto Brandão, revelou sua identidade no talk show do Ronald Rios. Confira aqui ele contando a história: &lt;a href=&#34;https://www.youtube.com/watch?v=Aca1ZbHDQ3g&#34;&gt;STARTUP DA REAL - Ronald Rios Talk Show #12&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Apesar dessas vantagens, vou trazer no próximo tópico um bom motivo para não fazer de forma anônima.&lt;/p&gt;
&lt;h2 id=&#34;use-seu-conteúdo-para-construir-rastros-digitais-positivos&#34;&gt;Use seu conteúdo para construir rastros digitais positivos&lt;/h2&gt;
&lt;p&gt;A internet não esquece! Já deu um google no seu nome completo? O que encontrou? Possivelmente seu currículo lattes ou algum trabalho publicado, talvez até seu perfil no LinkedIn. Mas às vezes tem coisas que você não gostaria que aparecesse (pelo menos com tanto destaque), como por exemplo um processo no JusBrasil, no Diário Oficial ou então alguma nota em disciplina da faculdade. E o mais triste disso é que não temos muito como deletar essas pegadas digitais de forma fácil e rápida.&lt;/p&gt;
&lt;p&gt;Ao invés de tentar deletar toda sua presença online e ocupar esses espaços online da forma mais anônima possível, que tal criar um conteúdo legal e que quando pesquisarem você isso vai causar uma ótima primeira impressão?&lt;/p&gt;
&lt;p&gt;Quando pesquisarem seu nome no Google vão encontrar seu artigo, seu blog pessoal, uma talk que você fez em algum evento, uma participação em podcast ou live. E as coisas que não tem tanto orgulho só irão aparecer nas últimas páginas da pesquisa, que normalmente as pessoas não procuram.  Vi essa excelente proposta no texto da Casey Fiesler, ela estuda os espaços online há anos, e propôs essa abordagem no contexto da hashtag #10YearChallenge, quando acabaram trazendo à tona coisas que a pessoa postou e que hoje em dia não se orgulham. Veja o texto dela: &lt;a href=&#34;https://cfiesler.medium.com/if-youre-worried-about-your-digital-footprint-don-t-destroy-it-make-it-better-cce67263c587&#34;&gt;If you&amp;rsquo;re worried about your digital footprint, don&amp;rsquo;t destroy it — make it bigger. | by Casey Fiesler&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;outros-porquês-para-divulgar-conhecimento&#34;&gt;Outros porquês para divulgar conhecimento&lt;/h2&gt;
&lt;p&gt;Além de ter uma presença online mais positiva, quais outras vantagens de divulgar conhecimento?&lt;/p&gt;
&lt;p&gt;Uma habilidade que você acaba desenvolvendo é de colocar em uma ordem linear como abordar determinado assunto. No fundo, você vai escrever uma história com começo, meio e fim. E quando você registra isso logo depois que começou a aprender um assunto novo, vai te ajudar bastante no seu processo de aprendizado.&lt;/p&gt;
&lt;p&gt;Quando criar uma documentação quando você tiver que configurar seu ambiente, se você documentar vai ficar mais fácil de reproduzir quando precisar novamente. Como você já escreveu essa documentação, terá pouco trabalho para publicar e vai ajudar quem estiver precisando. Por exemplo, quer aprender como montei meu setup de backups automatizados? Confira aqui: &lt;a href=&#34;https://caioau.net/blog/backups/&#34;&gt;Como parei de me preocupar e passei a adorar minha solução de backups&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;ninguém-se-importa-com-seu-conteúdo&#34;&gt;Ninguém se importa com seu conteúdo&lt;/h2&gt;
&lt;p&gt;E isso é bom! Esse post do Gabs Ferreira, do grupo Alura: &lt;a href=&#34;http://gabsferreira.com/ninguem-se-importa-com-o-seu-conteudo-e-isso-e-bom/&#34;&gt;Ninguém se importa com o seu conteúdo: e isso é bom - Gabs Ferreira&lt;/a&gt; trouxe essa perspectiva, só vai!&lt;/p&gt;
&lt;p&gt;Se estiver com receio de começar a escrever, pois vão te criticar ou te julgar de alguma forma, não se preocupe! A maioria das pessoas nem vai consumir seu conteúdo. Então escreva pensando em você, como isso vai te ajudar a aprender melhor, a se expressar melhor, a colocar as coisas em uma ordem linear e etc … E se conseguir impactar positivamente mesmo que for apenas uma pessoa isso já valeu a pena.&lt;/p&gt;
&lt;p&gt;Pra quem curte estatísticas, na pegada do princípio de pareto (80% dos efeitos vêm de 20% das causas) temos a regra &lt;a href=&#34;https://en.wikipedia.org/wiki/1%25_rule&#34;&gt;90-9-1 (ou regra do 1%)&lt;/a&gt; que mostra que via de regra para qualquer comunidade na internet 90% dos internautas vão apenas consumir de forma passiva, sem interagir de nenhuma forma (os “Lurkers”). Dos 10% restantes, 9% vão participar pouco através das “micro-reações”, como like ou claps no medium, e apenas 1% dos internautas serão responsáveis pela maioria das discussões.&lt;/p&gt;
&lt;p&gt;Na reportagem de Janeiro de 2012 da Revista Galileu (&lt;a href=&#34;https://web.archive.org/web/20120102101719/http://revistagalileu.globo.com/Revista/Common/0,,EMI281132-17773,00-OS+COMENTADORES+DA+INTERNET.html&#34;&gt;web archive&lt;/a&gt;) entrevistou uma pessoa que foi responsável por mais de CINCO MIL comentários, de forma anônima, na folha.com.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/comece-blog/xkcd_duty_calls.png&#34; loading=&#34;lazy&#34;
         alt=&#34;xkcd #386&#34; width=&#34;400px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;a href=&#34;https://xkcd.com/386/&#34;&gt;xkcd #386&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;melhor-escrever-em-português-ou-inglês&#34;&gt;Melhor escrever em português ou inglês?&lt;/h2&gt;
&lt;p&gt;A língua é uma barreira! Com isso em vista, devo escrever em português ou em inglês?&lt;/p&gt;
&lt;p&gt;Se optar pelo inglês, possivelmente seu conteúdo vai atingir mais pessoas, mas em compensação tem muito conteúdo em inglês então fica mais difícil do seu texto se destacar.&lt;/p&gt;
&lt;p&gt;Caso seja algo específico, como um tutorial de um framework recém lançado, talvez seja melhor fazer em inglês.&lt;/p&gt;
&lt;h2 id=&#34;alguns-exemplos&#34;&gt;Alguns exemplos&lt;/h2&gt;
&lt;p&gt;Vou trazer alguns textos de formatos diferentes para trazer inspirações.&lt;/p&gt;
&lt;p&gt;O primeiro exemplo é uma dica de ouro, é o texto da Anna sobre &lt;a href=&#34;https://anna.flourishing.stream/pt-br/today-i-learned/cancelamento-de-ruido-pulseaudio/&#34;&gt;Como ativar o cancelamento de eco no PulseAudio — Anna escreve&lt;/a&gt;. No texto, a autora apresenta o problema (a captação de áudio do microfone embutido do notebook não funciona bem) e apresenta como atacar o problema.&lt;/p&gt;
&lt;p&gt;Outro formato é falar sobre seu setup (um site que gosto muito de acompanhar é o &lt;a href=&#34;https://manualdousuario.net/&#34;&gt;manualdousuario.net&lt;/a&gt;).No tipo de texto como &lt;a href=&#34;https://manualdousuario.net/home-office-camila/&#34;&gt;O escritório em casa da designer de UI/UX Camila&lt;/a&gt;,você vai falar como é o seu escritório, quais equipamentos tem e como usa. É bem divertido e ajuda quem está em dúvida do que comprar, ou até mesmo repensar a forma de trabalhar.&lt;/p&gt;
&lt;p&gt;Para fechar os exemplos vou falar do texto do Gabriel Arruda que eu adoraria ter lido na faculdade quando estudava sobre o assunto. O texto se chama &lt;a href=&#34;https://gdarruda.github.io/2021/04/04/ferias-otimizadas.html&#34;&gt;Organizando férias com otimização&lt;/a&gt;. A proposta é encontrar os melhores períodos para entrar de férias para ter o máximo de dias de descanso. No texto o autor fala do problema, como vai ser modelado, a linguagem &lt;a href=&#34;https://www.minizinc.org/&#34;&gt;MiniZinc&lt;/a&gt;, o código e o resultado. Atente-se em como o autor conta uma história, com começo, meio e fim, e tenha isso em mente quando estiver escrevendo seu texto.&lt;/p&gt;
&lt;h2 id=&#34;use-memes&#34;&gt;Use memes&lt;/h2&gt;
&lt;p&gt;Uma imagem vale por mil palavras, para deixar seu textão mais atraente e prender a atenção dos leitores, use e abuse de memes!&lt;/p&gt;
&lt;p&gt;Por exemplo se estiver escrevendo sobre como a mediana é mais uma medida mais robusta que a média a valores aberrantes (outliers), o meme abaixo encaixa como uma luva:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/comece-blog/meme_outliar.png&#34; loading=&#34;lazy&#34; width=&#34;500px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Entretanto em alguns contextos mais formais não pega muito bem usar memes :/ nesses casos sugiro usar outros recursos visuais como diagramas ou tirinhas como do XKCD. Uma obra prima foi o texto aqui no computando arte &lt;a href=&#34;https://medium.com/computando-arte/entendendo-m%C3%A9tricas-de-modelos-preditivos-problemas-de-classifica%C3%A7%C3%A3o-desbalanceados-11aa406f6aac&#34;&gt;Métricas de Modelos Preditivos: Acurácia em Problemas de Classificação Desbalanceados | by Mikael Souza | Computando Arte&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/comece-blog/meme_acuracia.png&#34; loading=&#34;lazy&#34; width=&#34;900px&#34;/&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;onde-escrever&#34;&gt;Onde escrever&lt;/h2&gt;
&lt;p&gt;O Medium é a opção mais conhecida para publicar textos. Nele seu texto é “impulsionado” para pessoas que estão na plataforma, porém a desvantagem é que ele tem um paywall que impede a leitura de mais de 5 textos por dia :/&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/comece-blog/paywall.png&#34; loading=&#34;lazy&#34;
         alt=&#34;@linhadotrem/Twitter&#34; width=&#34;500px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;a href=&#34;https://twitter.com/linhadotrem/status/1451596753032069125&#34;&gt;@linhadotrem/Twitter&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Uma plataforma mais focada para o público de tecnologia é o &lt;a href=&#34;https://dev.to/&#34;&gt;dev.to&lt;/a&gt;, nele os textos devem estar no formato markdown, ao passo que o Medium tem um editor próprio. Mas o dev.to não tem paywall \o/&lt;/p&gt;
&lt;p&gt;Dependendo do seu objetivo, uma opção é escrever e publicar no próprio Linkedin. Para isso, você precisa habilitar o modo criador (&lt;a href=&#34;https://www.linkedin.com/help/linkedin/answer/a522537/linkedin-creator-mode?lang=pt&#34;&gt;instruções&lt;/a&gt;) então no seu perfil aparece sobre quais tópicos você escreve. Um exemplo é a Vanessa Moura (WonderWanny).&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/comece-blog/linkedin_creator.png&#34; loading=&#34;lazy&#34;
         alt=&#34;linkedin.com/in/vannessamoura&#34; width=&#34;600px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;a href=&#34;https://www.linkedin.com/in/vannessamoura/&#34;&gt;linkedin.com/in/vannessamoura&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;em&gt;Qual plataforma devo escolher?&lt;/em&gt; Minha sugestão é que não se preocupe muito com isso, só comece a escrever! Mas sugiro que tenha um blog pessoal pelo menos como “backup” para não ficar refém das plataformas.&lt;/p&gt;
&lt;h2 id=&#34;blog-pessoal&#34;&gt;Blog pessoal&lt;/h2&gt;
&lt;p&gt;Poucas plataformas da internet sobreviveram à prova do tempo. Lembra do Orkut? Já teve um MSN? Ter um blog pessoal te ajuda a evitar isso, vou dar algumas dicas de ter um blog pessoal.&lt;/p&gt;
&lt;p&gt;Devo usar o WordPress, Ghost, Jekyll ou Hugo? A ferramenta não importa! Só comece a escrever!&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/comece-blog/blog_tools.png&#34; loading=&#34;lazy&#34;
         alt=&#34;rakhim.org/honestly-undefined/19&#34; width=&#34;500px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;a href=&#34;https://rakhim.org/honestly-undefined/19/&#34;&gt;rakhim.org/honestly-undefined/19&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id=&#34;analytics&#34;&gt;Analytics&lt;/h3&gt;
&lt;p&gt;Quando estiver criando seu cantinho da internet, evite os analytics comerciais, principalmente o Google Analytics. O Google Analytics está presente na esmagadora maioria dos sites, tenha carinho pelos seus leitores e considere uma alternativa mais privativa.&lt;/p&gt;
&lt;p&gt;Já ouviu que “se o produto é de graça, você é o produto”? O produto de verdade do Google Analytics são os dados de navegação dos internautas. Que tal, pelo menos no seu cantinho, experimentar opções mais privativas?&lt;/p&gt;
&lt;p&gt;Dentre as alternativas vou destacar o &lt;a href=&#34;https://www.goatcounter.com/&#34;&gt;goatcounter.com&lt;/a&gt;: é gratuito para até 100k pageviews por mês e tem a opção self-hosting.&lt;/p&gt;
&lt;p&gt;Para quem optar pela via de hospedar por sua conta o site, tem o &lt;a href=&#34;https://goaccess.io/&#34;&gt;goaccess.io&lt;/a&gt; que cria dashboards apartir dos logs de acessos dos webserver como Nginx e Apache, ou seja, zero scripts de rastreamento ^_^&lt;/p&gt;
&lt;h3 id=&#34;usuários-de-rss-existem-e-resistem&#34;&gt;Usuários de RSS existem e resistem&lt;/h3&gt;
&lt;p&gt;Já falamos sobre RSS aqui no computando arte: &lt;a href=&#34;https://medium.com/computando-arte/utilizando-o-rss-para-furar-a-bolha-507f8b0ed410&#34;&gt;Utilizando o RSS para “furar a bolha” | Computando Arte&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;O RSS é um dos principais meios dos usuários acompanharem seu site, mas fique tranquilo pois provavelmente a ferramenta do seu site já deve gerar o feed sozinho.&lt;/p&gt;
&lt;p&gt;Só se atente que o link do feed está presente no HTML, caso contrário a pessoa vai ter que “caçar” o seu feed, por exemplo:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#0087ff&#34;&gt;link&lt;/span&gt; rel=&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;alternate&amp;#34;&lt;/span&gt; type=&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;application/rss+xml&amp;#34;&lt;/span&gt; href=&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#39;https://caioau.net/blog/index.xml&amp;#39;&lt;/span&gt; title=&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;Blogs on Pagina do caioau&amp;#34;&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/comece-blog/meme_rss.jpg&#34; loading=&#34;lazy&#34; width=&#34;300px&#34;/&gt;
&lt;/figure&gt;

&lt;h3 id=&#34;sobre-ter-um-domínio-próprio&#34;&gt;Sobre ter um domínio próprio&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Vou criar um site, preciso ter um domínio?&lt;/em&gt; Absolutamente não precisa! Você pode usar a hospedagens gratuitas como Github Pages. Pessoalmente, prefiro o Gitlab ou até mesmo o Wordpress.&lt;/p&gt;
&lt;p&gt;De novo, não se preocupe com isso! Só comece a escrever! Se depois de alguns meses ou anos que começou você sempre pode migrar para um domínio novo.Quando você for migrar, você pode colocar um atributo no HTML para redirecionar automaticamente para o domínio novo, o &lt;a href=&#34;https://developer.mozilla.org/pt-BR/docs/Web/HTML/Element/meta#attr-http-equiv&#34;&gt;http-equiv&lt;/a&gt;. Por exemplo:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#0087ff&#34;&gt;meta&lt;/span&gt; http-equiv=&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;refresh&amp;#34;&lt;/span&gt; content=&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;0;url=https://caioau.net/&amp;#34;&lt;/span&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Não caia nas extensões como .xyz! Pode parecer um preço tentador, mas muitas vezes o preço só é vantajoso para registrar o domínio na primeira vez, mas quando levar em conta as renovações não vale tanto a pena assim se comparado com extensões tradicionais como .net, .com ou .org.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;E um .br?&lt;/em&gt; O .br até que tem um preço bom, mas infelizmente no registro br seus dados pessoais (nome completo e CPF) ficam públicos no whois :/&lt;/p&gt;
&lt;h3 id=&#34;um-onion-onion-service-cai-bem&#34;&gt;Um .onion (onion service) cai bem&lt;/h3&gt;
&lt;p&gt;Para o seu cantinho ficar ainda mais privado você pode disponibilizar seu site em um onion service, trazendo anonimato para quem o visita com o navegador Tor.&lt;/p&gt;
&lt;p&gt;É tranquilo fazer! A documentação é muito boa: &lt;a href=&#34;https://community.torproject.org/onion-services/&#34;&gt;community.torproject.org/onion-services&lt;/a&gt;. Dá pra facilitar ainda mais usando o &lt;a href=&#34;https://onionshare.org/&#34;&gt;onionshare.org&lt;/a&gt; (só apontar a pasta que fica os HTML).&lt;/p&gt;
&lt;p&gt;Porém você vai precisar de um computador rodando 24 horas por dia para hospedar seu .onion, mas uma raspberry-pi dá conta do recado.&lt;/p&gt;
&lt;p&gt;Último cabeçalho, prometo! Coloque no HTML o atributo http-equiv=&amp;ldquo;onion-location”, dessa forma quando o navegador Tor abrir seu site na clearnet ele vai redirecionar automaticamente para a versão disponível no .onion, por exemplo:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#0087ff&#34;&gt;meta&lt;/span&gt; http-equiv=&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;onion-location&amp;#34;&lt;/span&gt; content=&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;http://zgjjgd2o7zh4u76b5d5fpyekeif4nmbtbktufe7z4vaa6sazeraz4nyd.onion&amp;#34;&lt;/span&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;join-computando-arte&#34;&gt;/join #computando-arte&lt;/h2&gt;
&lt;p&gt;Quando estiver escrevendo seus textos é importante pedir feedbacks, dessa forma você verá como pessoas com diferentes bagagens receberão seu conteúdo, por isso ter um grupo de divulgação onde todo mundo se ajuda é muito bom!&lt;/p&gt;
&lt;p&gt;Se gosta do nosso trabalho no Computando Arte e quiser escrever como convidado ou passar a compor o grupo, vamos te dar esse apoio! Basta nos enviar uma mensagem no twitter em &lt;a href=&#34;https://twitter.com/ComputandoArte&#34;&gt;@ComputandoArte&lt;/a&gt; ou no &lt;a href=&#34;mailto:computando.arte@protonmail.com&#34;&gt;computando.arte@protonmail.com&lt;/a&gt; que iremos te responder :)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Como contêineres funcionam?</title>
      <link>https://caioau.net/blog/intro-containers/</link><category>devops</category>
		  <category>computando-arte</category>
		  <category>texto</category>
		  <category>linux</category>
		  <category>docker</category>
		  <category>security</category>
		  
      <pubDate>Wed, 19 Jan 2022 14:00:00 -0300</pubDate>
      
      <guid>https://caioau.net/blog/intro-containers/</guid><description>&lt;p&gt;Obs.: Originalmente publicado no &lt;a href=&#34;https://caioau.net/blog/computando-arte/&#34;&gt;computando-arte&lt;/a&gt; dia 19Janeiro2022&lt;/p&gt;
&lt;p&gt;Existe muito &lt;del&gt;hype&lt;/del&gt; quando o assunto é contêineres e Kubernetes, isso acaba gerando uma expectativa e confusão do que são e como funcionam essas tecnologias.&lt;/p&gt;
&lt;p&gt;Hoje vamos falar o que de fato é um contêiner, como funciona e se cria um contêiner do zero (sem o docker).&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/intro-containers/foto_unsplash.jpg&#34; loading=&#34;lazy&#34;
         alt=&#34;Foto de ines mills, unsplash&#34; width=&#34;600px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Foto de ines mills, &lt;a href=&#34;https://unsplash.com/photos/TGs0tHMk4eg&#34;&gt;unsplash&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;o-que-é-um-contêiner&#34;&gt;O que é um contêiner?&lt;/h2&gt;
&lt;p&gt;Um contêiner é um processo rodando no kernel linux. E esse processo é isolado dos outros processos/contêineres e do host (através de features do kernel).&lt;/p&gt;
&lt;p&gt;Essa é a principal diferença dos contêineres para máquinas virtuais (VM). Todos os contêineres compartilham o mesmo kernel, no passo que cada VM tem seu kernel.&lt;/p&gt;
&lt;p&gt;Mas se é um kernel linux, como funciona quando uso o docker no Windows ou Mac? No fundo no Windows (mesmo WSL) e Mac tem uma máquina virtual rodando o linux.&lt;/p&gt;
&lt;p&gt;E quais são essas features do kernel que fazem tudo isso acontecer? Vamos falar delas nesse texto.&lt;/p&gt;
&lt;h2 id=&#34;namespaces&#34;&gt;Namespaces&lt;/h2&gt;
&lt;p&gt;Namespaces controlam o que um processo/contêiner consegue ver, existem atualmente os seguintes namespaces:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Processes ID (pid)&lt;/li&gt;
&lt;li&gt;mount points (mnt)&lt;/li&gt;
&lt;li&gt;Network (net)&lt;/li&gt;
&lt;li&gt;IDs do usúario e group (user)&lt;/li&gt;
&lt;li&gt;Interprocess communication (ipc)&lt;/li&gt;
&lt;li&gt;Control Group (cgroup)&lt;/li&gt;
&lt;li&gt;Unix Timesharing System (uts), apesar do nome complicado, representa o hostname e domínios.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;proc&#34;&gt;/proc&lt;/h2&gt;
&lt;p&gt;O procfs (montado em /proc) é um tipo de filesystem especial, nele existem diversas informações do sistema como CPU, memória e principalmente os processos.&lt;/p&gt;
&lt;p&gt;Se quiser entender como ler as infos do /proc, veja em &lt;a href=&#34;https://linux.die.net/man/5/proc&#34;&gt;man proc&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Para que os processos do host ficarem isolados do contêiner, o contêiner precisa ter um /proc próprio (além de um namespace pid).&lt;/p&gt;
&lt;h2 id=&#34;chroot&#34;&gt;chroot&lt;/h2&gt;
&lt;p&gt;Para que o contêiner não acesse os arquivos do host, o chroot (change root directory) faz com que o contêiner só consiga acessar um diretório do host.&lt;/p&gt;
&lt;p&gt;Por exemplo, se fizermos um &lt;code&gt;chroot /mnt/root&lt;/code&gt;, um arquivo em &lt;code&gt;/mnt/root/arq1.txt&lt;/code&gt; no host será apenas &lt;code&gt;/arq01.txt&lt;/code&gt; no chroot. Neste chroot só consegue acessar o que está em /mnt/root&lt;/p&gt;
&lt;h2 id=&#34;control-groups-cgroup&#34;&gt;Control groups (cgroup)&lt;/h2&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/intro-containers/cgroup_meme.jpg&#34; loading=&#34;lazy&#34; width=&#34;600px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;code&gt;:(){ :|:&amp;amp; };:&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Provavelmente é a forkbomb mais conhecida. Uma forkbomb é um ataque que quando executada são rapidamente criados muitos processos que que se multiplicam exponencialmente incapacitando totalmente o computador, sério! Só tirando da tomada pra conseguir parar.&lt;/p&gt;
&lt;p&gt;Precisamos de uma forma de limitar quantos recursos um determinado contêiner consegue utilizar. Os control group (cgroup) limitam os recursos como CPU, memória, rede que cada contêiner pode utilizar.&lt;/p&gt;
&lt;h2 id=&#34;demo-criando-um-contêiner-do-zero&#34;&gt;Demo: Criando um contêiner do zero&lt;/h2&gt;
&lt;p&gt;Bora criar nosso contêiner sem usar o docker! Antes de tudo precisamos instalar o que vamos precisar:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo apt install debootstrap cgroup-tools util-linux&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Primeiramente vamos criar uma instalação base do debian, para que o que fizermos no contêiner não contamine nossa máquina (o host), rode o seguinte no terminal:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo debootstrap bullseye ./deb11-rootfs https://deb.debian.org/debian/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;O comando acima vai criar uma instalação do Debian 11 (bullseye) na pasta deb11-rootfs.&lt;/p&gt;
&lt;p&gt;Agora vamos criar um cgroup&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#0087ff&#34;&gt;cgroup_name&lt;/span&gt;=&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;cg_&lt;/span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;$(&lt;/span&gt;shuf -i 2000-3000 -n 1&lt;span style=&#34;color:#5f8700&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cgcreate -g &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;cpu,cpuacct,memory,pids:&lt;/span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;$cgroup_name&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Colocando limites no cgroup:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cgset -r cpu.shares=&lt;span style=&#34;color:#00afaf&#34;&gt;256&lt;/span&gt; &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;$cgroup_name&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cgset -r memory.limit_in_bytes=100M &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;$cgroup_name&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cgset -r pids.max=&lt;span style=&#34;color:#00afaf&#34;&gt;100&lt;/span&gt; &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;$cgroup_name&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Então nosso cgroup vai ter no máximo 100MB de RAM, 1/4 de cpu (256/1024 shares) e 100 processos simultâneos então uma forkbomb vai ser contida.&lt;/p&gt;
&lt;p&gt;É agora, bora disparar um contêiner nesse cgroup:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cgexec -g &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;cpu,cpuacct,memory,pids:&lt;/span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;$cgroup_name&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    unshare --fork --mount --uts --ipc --pid --mount-proc &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    chroot &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;./debian11-rootfs&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    /bin/sh -c &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;/bin/mount -t proc proc /proc &amp;amp;&amp;amp; hostname container &amp;amp;&amp;amp; /bin/bash&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Calma, muita coisa ao mesmo tempo, vamos rodar o unshare no cgroup, o unshare vai criar os namespaces que queremos (uts, ipc e pid), então fazer um chroot no debian, montar um /proc próprio, mudar o hostname para contêiner e abrir um shell bash.&lt;/p&gt;
&lt;p&gt;Sucesso! Temos um contêiner! O que vamos fazer?&lt;/p&gt;
&lt;p&gt;Vamos ver que o contêiner não consegue ver os processos do host, faça &lt;code&gt;ps aux&lt;/code&gt; (para listar os processos) e veja que são apenas listados os processos do contêiner, isso aconteceu porque o contêiner está num namespace pid (veja &amp;ndash;pid no unshare e um /proc próprio).&lt;/p&gt;
&lt;p&gt;Mas o host consegue ver o contêiner, faça &lt;code&gt;sleep 1000&lt;/code&gt; no contêiner e no host faça &lt;code&gt;ps aux | grep &#39;sleep 1000&#39;&lt;/code&gt;, o host consegue ver todos os contêineres, repare que os mesmos processos no host tem um pid enquanto no contêiner tem outro PID.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/intro-containers/demo_htop.png&#34; loading=&#34;lazy&#34; width=&#34;800px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Veja que o contêiner só consegue enxergar seus processos, ao passo que o host (parte inferior) consegue ver os processos do(s) contêiner(s), veja também que o processo bash no contêiner tem PID 4 enquanto no host 12885.&lt;/p&gt;
&lt;p&gt;Faça &lt;code&gt;cat /proc/self/cgroup&lt;/code&gt; no contêiner e compare com o host, esse arquivo lista os cgroups do processo, repare que os cgroup pids,memory,cpu,cpuacct são o cgroup que criamos.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/intro-containers/demo_cgroup_ls.png&#34; loading=&#34;lazy&#34; width=&#34;600px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;No host vá em /sys/fs/cgroup/ e navegue por exemplo em pid/nome_do_cgroup veja que tem vários arquivos informando infos e limites como pids.current e pids.max.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/intro-containers/demo_cgroup_limits.png&#34; loading=&#34;lazy&#34; width=&#34;600px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Por fim vamos testar esses limites, no contêiner instale o python (&lt;code&gt;apt update &amp;amp;&amp;amp; apt install python3&lt;/code&gt;) então abra o python e faça &lt;code&gt;vet = int(1e9)*[None]&lt;/code&gt;, tentamos alocar um vetor com 1 bilhão (1e9) valores, apareceu o Killed. O que aconteceu? No host faça dmesg (que exibe mensagens do kernel) e veja que o kernel (out of memory (oom)) matou processo pois ele passou do constraint.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/intro-containers/demo_oom.png&#34; loading=&#34;lazy&#34; width=&#34;700px&#34;/&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/intro-containers/meme_unix_file.png&#34; loading=&#34;lazy&#34; width=&#34;400px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Para facilitar coloquei os comandos que usamos para criar um contêiner em um script:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;28
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;29
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;30
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;31
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;32
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;33
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;34
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;35
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;36
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;37
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;38
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;39
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;40
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;41
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;if&lt;/span&gt; [ &lt;span style=&#34;color:#0087ff&#34;&gt;$USER&lt;/span&gt; != &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#39;root&amp;#39;&lt;/span&gt; ]; &lt;span style=&#34;color:#5f8700&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;esse script deve rodar como root, rodeo novamente com sudo&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;exit&lt;/span&gt; &lt;span style=&#34;color:#00afaf&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;script para demonstrar como containers funcionam (namespaces, cgroups, chroot)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4e4e4e&#34;&gt;# instala dependencias, caso nao tenha instaladas descomente&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;echo&lt;/span&gt; -e &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;instalando as dependencias necessarias (debootstrap cgroup-tools util-linux)\n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt update &amp;amp;&amp;amp; apt install debootstrap cgroup-tools util-linux
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4e4e4e&#34;&gt;# cria a raiz de uma instalação debian na pasta debian11-rootfs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4e4e4e&#34;&gt;# descomente caso nao tenha feito ainda&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;if&lt;/span&gt; [ ! -d &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;./debian11-rootfs&amp;#34;&lt;/span&gt; ]; &lt;span style=&#34;color:#5f8700&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;echo&lt;/span&gt; -e &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;\n\ninstalando o debian 11 (bullseye) na pasta debian11-rootfs\n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    debootstrap bullseye ./debian11-rootfs https://deb.debian.org/debian/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;criando o cgroup: &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4e4e4e&#34;&gt;# cria um numero aleatorio entre 2000~3000 para ter cgroup unico&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;cgroup_name&lt;/span&gt;=&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;cg_&lt;/span&gt;&lt;span style=&#34;color:#5f8700&#34;&gt;$(&lt;/span&gt;shuf -i 2000-3000 -n 1&lt;span style=&#34;color:#5f8700&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cgcreate -g &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;cpu,cpuacct,memory,pids:&lt;/span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;$cgroup_name&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cgset -r cpu.shares=&lt;span style=&#34;color:#00afaf&#34;&gt;256&lt;/span&gt; &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;$cgroup_name&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#4e4e4e&#34;&gt;# 0.25 cpu&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cgset -r memory.limit_in_bytes=100M &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;$cgroup_name&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#4e4e4e&#34;&gt;# limite de 100MB RAM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cgset -r pids.max=&lt;span style=&#34;color:#00afaf&#34;&gt;100&lt;/span&gt; &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;$cgroup_name&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#4e4e4e&#34;&gt;# no maximo 100 procesos simultaneos (forkbomb prevetion)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;echo&lt;/span&gt; -e &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;\n\ncgroup criado, seu nome eh: &lt;/span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;$cgroup_name&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;echo&lt;/span&gt; -e &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;iniciando o container, divirta-se\n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4e4e4e&#34;&gt;# calma, muita coisa ao mesmo tempo: usa o cgroup que acabamos de criar (cgexec),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#4e4e4e&#34;&gt;#     cria namespaces novos (unshare), faz chroot e muda o hostname do container&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cgexec -g &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;cpu,cpuacct,memory,pids:&lt;/span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;$cgroup_name&lt;/span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    unshare --fork --mount --uts --ipc --pid --mount-proc &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    chroot &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;./debian11-rootfs&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#af0000&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#af0000&#34;&gt;&lt;/span&gt;    /bin/sh -c &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;/bin/mount -t proc proc /proc &amp;amp;&amp;amp; hostname container &amp;amp;&amp;amp; /bin/bash&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;overlay-filesystems&#34;&gt;Overlay filesystems&lt;/h2&gt;
&lt;p&gt;No nosso exemplo usamos uma instalação do debian como filesystem, dessa forma cada contêiner precisaria ter sua própria instalação, gastando muito espaço de disco (sem aproveitar o que é comum).&lt;/p&gt;
&lt;p&gt;Os filesystem overlay permitem que contêineres diferentes aproveitem o mesmo espaço em disco. Isso acontece através das camadas que são reutilizadas e empilhadas para criar o filesystem final de cada contêiner.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/intro-containers/layers.png&#34; loading=&#34;lazy&#34;
         alt=&#34;Fonte&#34; width=&#34;600px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;a href=&#34;https://www.freecodecamp.org/news/demystifying-containers-101-a-deep-dive-into-container-technology-for-beginners-d7b60d8511c1/&#34;&gt;Fonte&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Na figura acima temos uma visualização bacana, partimos de uma instalação do sistema operacional Ubuntu, então é instalado o java e por fim são copiados os binários da aplicação elasticsearch essa é a imagem 1 (representada na 3a camada b108&amp;hellip;). A imagem 2 são adicionados arquivos de configuração e por fim definidas algumas variáveis de ambiente.&lt;/p&gt;
&lt;p&gt;Cada passo é uma camada (representada à direita), aproveitando aquela ação para outras imagens que usam aquilo como base.&lt;/p&gt;
&lt;h2 id=&#34;features-de-segurança&#34;&gt;Features de segurança&lt;/h2&gt;
&lt;p&gt;Capabilities, seccomp e apparmor são features de segurança para restringir o que os contêineres podem fazer, vamos falar brevemente delas a seguir:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Capabilities: São permissões especiais que permitem processos fazer determinadas ações. Por exemplo &lt;strong&gt;cap_net_bind_service&lt;/strong&gt; permite usar portas privilegiadas (&amp;lt;=1024). As capabilities surgiram para dar permissões mais granulares aos programas, antes delas essas ações só eram permitidas para o root.&lt;/li&gt;
&lt;li&gt;seccomp-bpf: Define quais chamadas de sistema (syscalls) são permitidas.&lt;/li&gt;
&lt;li&gt;AppArmor ou SELinux: São sistemas concorrentes normalmente distribuições baseadas no RedHat (como fedora) usam o SELinux enquanto distros baseadas no Debian (como Ubuntu, linux mint e pop-os) usam o AppArmor. Eles tem um perfil que define quais arquivos podem ser acessados (ou não) e quais capabilities são permitidas.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;quem-faz-tudo-isso-acontecer&#34;&gt;Quem faz tudo isso acontecer?&lt;/h2&gt;
&lt;p&gt;Quem já usa docker não precisa criar os namespaces, cgroups etc &amp;hellip; que falamos aqui, então quem faz isso? O docker? Quem se ocupa disso são os contêiner runtime.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/intro-containers/docker-containerd-runc-2000-opt.png&#34; loading=&#34;lazy&#34;
         alt=&#34;Fonte&#34; width=&#34;800px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;a href=&#34;https://iximiuz.com/en/posts/container-learning-path/&#34;&gt;Fonte&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;O diagrama acima mostra como tudo se relaciona, ao longo dos anos foram sendo criadas interfaces padronizadas, primeiramente a OCI (open containers iniciative) em jun/2015 e nasceu o runc. Depois foi criada a CRI (contêiner runtime interface) em Dez/2016 e nasceu o containerd.&lt;/p&gt;
&lt;p&gt;Essas interfaces foram criadas principalmente por causa do Kubernetes, e com elas sendo padronizadas esses componentes podem ser substituídos facilmente. Por exemplo, se não quiser usar o &lt;a href=&#34;https://containerd.io/&#34;&gt;containerd&lt;/a&gt; você pode usar uma alternativa mais leve como o &lt;a href=&#34;https://cri-o.io/&#34;&gt;cri-o&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Lembra em 2020 que na versão 1.20 do Kubernetes que o docker não ia ser mais suportado? Isso aconteceu porque o Kubernetes interagia com o docker de uma forma não padronizada. O dockershim não era a interface padronizada CRI, então o Kubernetes tinha que manter duas implementações separadas. Mais detalhes aqui: &lt;a href=&#34;https://kubernetes.io/pt-br/blog/2020/12/02/dont-panic-kubernetes-and-docker/&#34;&gt;Não entre em pânico: Kubernetes e Docker&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Tem uma talk legal que conta a história dessas interfaces: &lt;a href=&#34;https://www.youtube.com/watch?v=MDsjINTL7Ek&#34;&gt;Below Kubernetes: Demystifying container runtimes&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;rootless&#34;&gt;Rootless&lt;/h2&gt;
&lt;p&gt;Por padrão o docker daemon (e o containerd) roda como root no host, caso um contêiner consiga escapar o isolamento isso vai comprometer totalmente o computador host.&lt;/p&gt;
&lt;p&gt;Uma vulnerabilidade grave no runc foi a &lt;a href=&#34;https://seclists.org/oss-sec/2019/q1/119&#34;&gt;CVE-2019-5736&lt;/a&gt; que permitia um contêiner escapar e ter acesso root no host.&lt;/p&gt;
&lt;p&gt;Rootless roda o docker (e os runtimes) como um usuário não root, trazendo um avanço significativo de segurança.&lt;/p&gt;
&lt;p&gt;Até então o modo rootless no docker era experimental, mas na versão &lt;a href=&#34;https://www.docker.com/blog/introducing-docker-engine-20-10/&#34;&gt;20.10&lt;/a&gt; (lançado em dez/2020) virou estável.&lt;/p&gt;
&lt;p&gt;Um site ótimo que fala sobre contêineres rootless é o &lt;a href=&#34;https://rootlesscontaine.rs/&#34;&gt;rootlesscontaine.rs&lt;/a&gt;, ele explica como tudo funciona e as instruções de como usar.&lt;/p&gt;
&lt;h2 id=&#34;conclusão&#34;&gt;Conclusão&lt;/h2&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/intro-containers/tirinha_containers.png&#34; loading=&#34;lazy&#34;
         alt=&#34;turnoff.us/geek/linux-containers/&#34; width=&#34;400px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;a href=&#34;https://turnoff.us/geek/linux-containers/&#34;&gt;turnoff.us/geek/linux-containers/&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Vimos as primitivas do kernel Linux que fazem os contêineres funcionarem e as diferenças com máquinas virtuais, quem se interessou e quiser aprender mais vou deixar algumas referências.&lt;/p&gt;
&lt;p&gt;Pra quem tá começando recomendo os seguintes materiais:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docker-curriculum.com/&#34;&gt;docker-curriculum.com&lt;/a&gt;: É um tutorial bem prático e completo.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://livro.descomplicandodocker.com.br/&#34;&gt;Descomplicando Docker&lt;/a&gt;: Curso do LINUXtips em português brasileiro, a LINUXtips tem vários cursos excelentes de Devops.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.udemy.com/course/docker-mastery/&#34;&gt;Docker Mastery&lt;/a&gt;: É o curso que mais gosto ;) ele é bem completo e passa várias dicas para depurar os contêineres e ainda faz uma breve introdução sobre orquestração de contêineres (docker swarm e kubernetes).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Para montar esse texto usei o livro da Liz Rice: &lt;a href=&#34;https://www.oreilly.com/library/view/container-security/9781492056690/&#34;&gt;Container Security: Fundamental Technology Concepts that Protect Containerized Applications&lt;/a&gt;, é bem completo e quem curte segurança vai adorar. A mesma autora tem uma talk legal &lt;a href=&#34;https://www.youtube.com/watch?v=Utf-A4rODH8&#34;&gt;Building a conteiner from scratch in Go&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Primeiros passos com self-hosting</title>
      <link>https://caioau.net/blog/selfhosting/</link><category>devops</category>
		  <category>computando-arte</category>
		  <category>texto</category>
		  <category>raspberry-pi</category>
		  <category>selfhost</category>
		  <category>linux</category>
		  <category>docker</category>
		  <category>ansible</category>
		  <category>security</category>
		  <category>monitoramento</category>
		  
      <pubDate>Sun, 04 Jul 2021 14:00:00 -0300</pubDate>
      
      <guid>https://caioau.net/blog/selfhosting/</guid><description>&lt;p&gt;Obs.: Originalmente publicado no &lt;a href=&#34;https://caioau.net/blog/computando-arte/&#34;&gt;computando-arte&lt;/a&gt; dia 05Julho2021&lt;/p&gt;
&lt;p&gt;Neste post vamos fazer uma visão geral das principais partes do self-hosting.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/selfhosting/rasp.png&#34; loading=&#34;lazy&#34;
         alt=&#34;Foto de Jainath Ponnala, unsplash&#34; width=&#34;600px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Foto de Jainath Ponnala, &lt;a href=&#34;https://unsplash.com/photos/9wWX_jwDHeM&#34;&gt;unsplash&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;vai-usar-a-nuvem-ou-apenas-on-premise-que-tal-ambos&#34;&gt;Vai usar a nuvem? Ou apenas on-premise? Que tal ambos?&lt;/h2&gt;
&lt;p&gt;Acredito que umas das primeiras considerações quando montamos nosso setup de self-hosting é pensar como isso vai se organizar e onde vai ficar cada coisa.&lt;/p&gt;
&lt;p&gt;Self-hosting não é ser “contra a nuvem” mas sim um movimento para ter controle dos nossos dados e aplicações que usamos, mesmo usando a nuvem nós que vamos configurar tudo e ter controle de como cada coisa funciona.&lt;/p&gt;
&lt;p&gt;Outro modelo é hospedar “tudo em casa” (chamado de on-premise), funciona muito bem. Mas um desafio que logo vamos abordar é abrir a conexão da sua operadora para acessar seus serviços fora de casa.&lt;/p&gt;
&lt;p&gt;Daí surge um terceiro modelo: o híbrido, parte das coisas que necessitam de velocidade ficam em casa e o restante que precisa acessar fora de casa na nuvem. No meu caso, coloco na nuvem (uma virtual private server (VPS) da digital ocean) o nextcloud com apenas meus contatos e calendário (no android uso o davx5 para sincronizar a agenda e os contatos com o nextcloud) e em casa guardo meus backups (com uma cópia no &lt;a href=&#34;https://www.rsync.net/&#34;&gt;rsync.net&lt;/a&gt;) e todo resto :P&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/selfhosting/setup_caioau.png&#34; loading=&#34;lazy&#34; width=&#34;600px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Além de ser muito bonito e divertido de fazer, recomendo fazer um diagrama de como vai se organizar suas aplicações e dispositivos, acima é como organizo tudo.&lt;/p&gt;
&lt;h2 id=&#34;hardware-usado-para-hospedar&#34;&gt;Hardware usado para hospedar&lt;/h2&gt;
&lt;p&gt;Para hospedar nossas coisas em casa, precisamos de um hardware para fazê-lo, pode ser usado com computador velho ou, outras opções populares, são usar a Raspberry Pi, mini pc (tipo intel NUC) ou por fim um servidor de armazenamento conectado em rede (NAS, de Network Attached Storage). Embora seja uma melhor opção pelo reuso e sobrevida de um equipamento obsoleto, é importante ficar ciente e atento a falhas por fadiga que podem comprometer a disponibilidade ou a confiabilidade do serviço.&lt;/p&gt;
&lt;p&gt;Quando eu comecei nessa jornada do self-hosting, havia comprado um SSD para meu notebook então peguei o disco que veio nele e conectei numa Raspberry Pi. Começar com uma Raspberry Pi é ótimo: é barato, consome pouca energia e atende aos requisitos de recursos de várias aplicações.&lt;/p&gt;
&lt;p&gt;Mas existem outras necessidades que uma Raspberry Pi não consegue atender, como por exemplo rodar máquinas virtuais, e daí surge a necessidade de outros hardwares apropriados. Como um mini-pc (ou Intel NUC) que é literalmente um mini pc e os componentes tradicionais como processador x86 (ao invés do ARM do Raspberry Pi), slots de memória RAM que pode ser trocada, etc.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/selfhosting/nas.png&#34; loading=&#34;lazy&#34;
         alt=&#34;NAS Synology DS920&amp;#43;&#34; width=&#34;400px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;NAS Synology DS920+&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Quer armazenar muitos arquivos? Talvez um NAS seja mais adequado. Este equipamento conta com conexão à rede e diversos slots para colocar os discos.&lt;/p&gt;
&lt;p&gt;Por fim, um item de hardware que é opcional mas recomendo é um “no break”, para que em caso de cair a energia na sua casa não aconteça nada.&lt;/p&gt;
&lt;h2 id=&#34;storage-e-backups&#34;&gt;Storage e backups&lt;/h2&gt;
&lt;p&gt;Tudo, inclusive toda forma de tecnologia, está sujeita a falhas, mas enquanto peças podem ser substituídas, arquivos perdidos podem não serem recuperáveis, por isso surge a necessidade de cópias de segurança, os famosos backups. A regra de ouro é quanto mais importante, raro ou caro mais versões e de mais difícil acesso elas devem ser.&lt;/p&gt;
&lt;p&gt;Isso é uma consideração importante principalmente com a Raspberry Pi, os SD cards não são muito confiáveis, depois de alguns anos de uso eles acabam “morrendo”. Comigo foi muito nítido isso, teve um SD card que me serviu fielmente por 2 anos, enquanto outros logo depois de 1 ano de uso contínuo eles morreram. Mesmo adotando alguns truques para diminuir sua leitura e escrita, como montar com a flag noatime, os logs e outras pastas como tmpfs e desativar o swap.&lt;/p&gt;
&lt;p&gt;Outra preocupação com os backups são os ataques ransomware, se seu computador teve os arquivos sequestrados, depois de sincronizar os backups também podem estar comprometidos. Por isso é aconselhável ter backups versionados, no qual teremos um &amp;ldquo;histórico&amp;rdquo; dos arquivos e no caso de um ransomware, basta restaurar a penúltima versão dos backups no qual os arquivos originais estarão lá.&lt;/p&gt;
&lt;p&gt;Uma prática indispensável quando falamos de storage é o Redundant Array of Independent Disks (RAID: Arranjo redundante de discos baratos) que permite combinar os discos para que o sistema operacional os enxergue tudo como um disco só. Os dois modos mais básicos são o RAID 0 e RAID 1. No RAID 0 temos 2 discos que vão somar suas capacidades, enquanto no RAID 1 teremos a capacidade de apenas 1 disco e outro é usado como redundância caso um disco falhe, bastando trocar o disco quebrado que os dados serão espelhados nele.&lt;/p&gt;
&lt;p&gt;Existem outros níveis de RAID, que são no fundo combinações do 0 e 1, como o RAID 5 (no qual teremos 4 discos, mas apenas podendo utilizar apenas o espaço de 3, pois 1 drive é usado como redundância).&lt;/p&gt;
&lt;p&gt;A fim de combinar os discos utilizando o RAID temos diversas implementações que podem ser usadas no Linux. A mais simples é o mdadm que mapeia os drives num “disco virtual”.&lt;/p&gt;
&lt;p&gt;Outra solução um pouco mais avançada é utilizar o LVM que é um gerenciador de volumes que permite coisas mais avançadas como diminuir e aumentar as partições usadas e realizar snapshots, que é um “retrato” do sistema de arquivos que pode ser acessado depois, dessa forma criando um “ponto de restauração”.&lt;/p&gt;
&lt;p&gt;Por fim os sistemas de arquivos recentes como BTRFS e ZFS podem ser usados RAID e tem recursos legais como os snapshots, compressão nativa dos arquivos (dessa forma aqueles arquivos de texto como dados em csv ficam bem menor) e por fim como esses sistemas de arquivos usam o conceito de copy-on-write ou seja para toda escrita será feita uma cópia para manter a versão anterior, isso permite que para realizar a manutenção dos disco (o fsck, a checagem da integridade do sistema de arquivos) não precise desligar tudo (nesses sistemas o equivalente do fsck é o scrub).&lt;/p&gt;
&lt;p&gt;A única ressalva para usar o ZFS e BTRFS são bancos de dados, o copy-on-write nos bancos de dados prejudica o desempenho, nesses casos talvez seja uma boa manter o sistema operacional num sistema de arquivos tradicional como ext4 e os bancos de dados nele e o armazenamento restante no ZFS ou BTRFS.&lt;/p&gt;
&lt;p&gt;Outra preocupação é a criptografia dos discos, para proteger os arquivos em caso de furto, nesses casos é uma boa instalar o pacote dropbear-initramfs (&lt;a href=&#34;https://www.cyberciti.biz/security/how-to-unlock-luks-using-dropbear-ssh-keys-remotely-in-linux/&#34;&gt;tutorial&lt;/a&gt;) que permite entrar com a senha da criptografia de forma remota (por ssh), sem precisar ter um teclado in loco.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/selfhosting/backups_meme.png&#34; loading=&#34;lazy&#34;
         alt=&#34;Fonte: https://twitter.com/nixcraft/status/1313909322905083905&#34; width=&#34;400px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Fonte: &lt;a href=&#34;https://twitter.com/nixcraft/status/1313909322905083905&#34;&gt;https://twitter.com/nixcraft/status/1313909322905083905&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Uma regra de ouro dos backups é a regra 3-2-1, que diz que devemos ter ao menos 3 cópias, em 2 mídias diferentes e 1 “fora de casa” em caso de incêndio. Para ter esse backup fora de casa é mais prático usar a nuvem, mas como utilizar a nuvem de forma segura? Podemos utilizar uma solução de backup que tenha criptografia, como o borgbackup, outra opção para utilizar o Google Drive, Dropbox e similares é utilizar o &lt;a href=&#34;https://cryptomator.org/&#34;&gt;cryptomator.org&lt;/a&gt; que criptografa seus dados antes de enviá-los para a nuvem.&lt;/p&gt;
&lt;p&gt;Partindo para as indicações, veja o vídeo do Fabio Akita: &lt;a href=&#34;https://www.youtube.com/watch?v=lxjBgxmDZAI&#34;&gt;Quebrei 3 HDs: Entendendo Armazenamento&lt;/a&gt; explicando como os discos rígidos funcionam. E o meu texto de como montei minha solução de backups criptografados com o borgbackup e &lt;a href=&#34;https://syncthing.net/&#34;&gt;syncthing&lt;/a&gt; no Android: &lt;a href=&#34;https://caioau.net/blog/backups/&#34;&gt;Como parei de me preocupar e passei a adorar minha solução de backups&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;como-acessar-meus-serviços-fora-de-casa&#34;&gt;Como acessar meus serviços fora de casa?&lt;/h2&gt;
&lt;p&gt;Em algumas operadoras como a NET, seu modem tem um IP “interno” dentro da rede da operadora, pois os IPs IPV4 são muito escassos, o famigerado Carrier-grade NAT (CGNAT), dessa forma não é possível acessar sua casa através da internet.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/selfhosting/nat.png&#34; loading=&#34;lazy&#34;
         alt=&#34;Explicação sobre o NAT (fonte)&#34; width=&#34;600px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Explicação sobre o NAT (&lt;a href=&#34;https://twitter.com/0x1shu/status/1401986638197116934/photo/1&#34;&gt;fonte&lt;/a&gt;)&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;O único jeito é ligar na operadora e pedir para sair do CGNAT, permitindo assim hospedar na internet seus serviços. Foi o que fiz (tenho NET), mas não consigo abrir algumas portas como a 80 (http) e 443 (https), pois na NET isso só é permitido comprando o plano para empresas 😞&lt;/p&gt;
&lt;p&gt;Pesquise e pergunte no &lt;a href=&#34;https://old.reddit.com/r/InternetBrasil/&#34;&gt;/r/InternetBrasil&lt;/a&gt;, lá tem muito conteúdo sobre isso.&lt;/p&gt;
&lt;p&gt;Outra questão é que os IPs não são fixos. Dentro da sua casa, quando a Raspberry Pi liga ela “pede” um IP pro seu roteador, o Dynamic Host Configuration Protocol (DHCP) que atribui um IP para a Raspberry Pi, mas os IPs muitas vezes são alocados de sequencial, ou seja nem sempre a Raspberry Pi vai ter o mesmo IP, quebrando o encaminhamento de portas do roteador. Então no roteador na configuração do DHCP atribua um IP fixo para a Raspberry Pi.&lt;/p&gt;
&lt;p&gt;Outro IP que não é fixo é o do seu modem, que é o seu IP público na internet, infelizmente às vezes ele acaba mudando (de novo no plano para empresas o IP é fixo), daí surgem os serviços de DNS dinâmico, como o DynDNS ou NOIP, eu utilizo o &lt;a href=&#34;https://www.duckdns.org/&#34;&gt;duckdns&lt;/a&gt; e no google domínios tem a &lt;a href=&#34;https://support.google.com/domains/answer/6147083?hl=pt-BR&#34;&gt;opção de DNS dinâmico&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A partir daí é só fazer os encaminhamentos de portas no seu modem, evite a opção DMZ, que expõe completamente a Raspberry Pi na internet, encaminhe apenas as portas que realmente precisa expor. Outra opção é ter um roteador próprio, e o usar o modem da operadora apenas como modem colocando no modo bridge e o seu roteador vai atuar como firewall encaminhando apenas algumas portas. Eu faço isso com meu roteador usando o OpenWRT e criei algumas VLANs (redes lógicas separadas para segregar os equipamentos) para minha rede.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/selfhosting/ngrok.png&#34; loading=&#34;lazy&#34;
         alt=&#34;Diagrama do proxy reverso (ngrok)&#34; width=&#34;500px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Diagrama do proxy reverso (ngrok)&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Outra opção é utilizar um serviço de proxy reverso, que basicamente torna seu localhost público, como &lt;a href=&#34;https://ngrok.com/&#34;&gt;ngrok&lt;/a&gt;, ou a solução open source &lt;a href=&#34;https://pagekite.net/&#34;&gt;pagekite&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Na mesma linha pode ser utilizada a sua VPS na cloud como proxy para acessar suas coisas em casa, pode ser algo simples como o &lt;a href=&#34;https://linux.die.net/man/1/autossh&#34;&gt;autossh&lt;/a&gt; que cria tunnels ssh permitindo acessar sua casa passando pela VPS.&lt;/p&gt;
&lt;p&gt;Ou criar uma VPN com &lt;a href=&#34;https://www.wireguard.com/&#34;&gt;wireguard&lt;/a&gt; na sua VPS e conectar sua Raspberry Pi, viabilizando seu acesso externo. O legal dessa solução é que você pode criar duas configurações no seu computador/celular: uma que usa a VPN apenas para acessar seus serviços e uma que passa todo seu tráfego pela VPN para usar em WiFis não confiáveis como WiFis públicos.&lt;/p&gt;
&lt;p&gt;Por fim, outra possibilidade é usar o Tor, para criar um .onion que permite hospedar seus serviços em casa, sem precisar abrir suas portas, veja a documentação: &lt;a href=&#34;https://community.torproject.org/onion-services/&#34;&gt;onion-services&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Uma preocupação em expor seus serviços na internet é a de segurança, pois os mesmos podem ser hackeados e o hacker estará na sua rede. Isso pode ser feito de forma segura adotando as medidas de segurança que falaremos, mas outra possibilidade é utilizar o port knocking, no qual as portas dos seus serviços ficam fechadas e depois de “bater” numa sequência de portas corretas (tipo uma senha) a porta é aberta, apenas para o IP, e por um período de tempo, escondendo e protegendo seus serviços. Utilizo o &lt;a href=&#34;https://linux.die.net/man/1/knockd&#34;&gt;knockd&lt;/a&gt; com o firewall ufw.&lt;/p&gt;
&lt;h2 id=&#34;contêiners&#34;&gt;Contêiners&lt;/h2&gt;
&lt;p&gt;Os contêineres vieram para ficar e são uma maneira simples e rápida para colocar seus serviços no ar. Mas é preciso tomar cuidado em usar apenas imagens confiáveis, no fundo você está rodando um software feito por um terceiro na sua máquina.&lt;/p&gt;
&lt;p&gt;Foram encontradas imagens maliciosas minerando bitcoin, ou imagens desatualizadas e vulneráveis. Antes de utilizar uma imagem dá uma olhada no Dockerfile no github para procurar por coisas suspeitas.&lt;/p&gt;
&lt;p&gt;Imagens oficiais do dockerhub são confiáveis, outra fonte excelente de imagens é o &lt;a href=&#34;https://www.linuxserver.io/&#34;&gt;LinuxServer.io&lt;/a&gt; com diversas imagens ótimas.&lt;/p&gt;
&lt;p&gt;Partiu para as indicações? Tem um site excelente para aprender docker, bem direto ao ponto o &lt;a href=&#34;https://docker-curriculum.com/&#34;&gt;docker-curriculum.com&lt;/a&gt;, curso eu indico o &lt;a href=&#34;https://www.udemy.com/course/docker-mastery/&#34;&gt;docker-mastery&lt;/a&gt; na udemy que até fala um pouco de clusters com docker swarm e kubernetes, por fim no youtube tem o vídeo excelente da TechWorld with Nana &lt;a href=&#34;https://www.youtube.com/watch?v=3c-iBn73dDE&#34;&gt;Docker Tutorial for Beginners&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;proxy-reverso&#34;&gt;Proxy Reverso&lt;/h2&gt;
&lt;p&gt;Quando vamos hospedar diversos serviços uma construção comum que é utilizada é o proxy reverso, com ele quando vamos acessar nossos serviços evitamos de ter que usar uma porta diferente para cada coisa, dessa forma podemos configurar o proxy reverso para como cada serviço vai ser acessado, normalmente por um subdomínio tipo nextcloud.seu-dominio.tld ou como uma subpasta seu-dominio.tld/nextcloud.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/selfhosting/traefik.png&#34; loading=&#34;lazy&#34;
         alt=&#34;Ilustração de um proxy reverso&#34; width=&#34;600px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Ilustração de um proxy reverso&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;As opções mais populares são o Secure Web Application Gateway (&lt;a href=&#34;https://github.com/linuxserver/docker-swag&#34;&gt;swag&lt;/a&gt;), da linuxservers.io, que é um nginx, com let’s encrypt (para ter o https) e fail2ban (que bloqueia bots e IPs que estão tentando te invadir).&lt;/p&gt;
&lt;p&gt;A outra opção é o &lt;a href=&#34;https://doc.traefik.io/traefik/&#34;&gt;traefik&lt;/a&gt; que tem a vantagem de já ser integrado com o docker e kubernetes, dessa forma ao invés de configurar as “rotas” de cada serviço em arquivos de configuração (como é feito no nginx) as configurações vivem nos labels do contêiner de cada serviço, muito mágico ✨&lt;/p&gt;
&lt;p&gt;Aliado com o proxy reverso, podemos utilizar o &lt;a href=&#34;https://www.authelia.com/&#34;&gt;authelia&lt;/a&gt;, que permite ter o mesmo usuário e senha (single sign-on) sincronizado com todos seus serviços e autenticação em 2 fatores integrada em todos seus serviços, tornando tudo mais prático e seguro.&lt;/p&gt;
&lt;p&gt;Bora para um exemplo?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;display:grid;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;display:grid;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;18
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;19
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;23
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;26
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;28
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;29
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;30
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;31
&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;32
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;33
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;34
&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;35
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;36
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;37
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;38
&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;39
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;40
&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;41
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;42
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;display:grid;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;version&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;2.1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;services&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;traefik&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;traefik:v2.4&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;container_name&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;traefik&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;restart&lt;/span&gt;: unless-stopped
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;command&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#4e4e4e&#34;&gt;#- &amp;#34;--log.level=DEBUG&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;--api.insecure=true&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;--providers.docker=true&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;--providers.docker.exposedbydefault=false&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;--entrypoints.web.address=:80&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;ports&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;80:80&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;8080:8080&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;/var/run/docker.sock:/var/run/docker.sock:ro&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;whoami&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;containous/whoami&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;restart&lt;/span&gt;: unless-stopped
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;labels&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;traefik.enable=true&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;traefik.http.routers.whoami.rule=PathPrefix(`/whoami/`)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;traefik.http.routers.whoami.entrypoints=web&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;bitwarden&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;image&lt;/span&gt;: bitwardenrs/server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;container_name&lt;/span&gt;: bitwarden
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;restart&lt;/span&gt;: unless-stopped
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#4e4e4e&#34;&gt;#environment: &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#4e4e4e&#34;&gt;#- SIGNUPS_ALLOWED=false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;      - ./docker_vols/bwdata/:/data/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;labels&lt;/span&gt;: 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;traefik.enable=true&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;traefik.http.routers.bitwarden.rule=PathPrefix(`/vault/`)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;traefik.http.routers.bitwarden.entrypoints=web&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;traefik.http.middlewares.bw.stripprefix.prefixes=/vault/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;traefik.http.routers.bitwarden.middlewares=bw&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Esse é um arquivo docker-compose, é um arquivo yaml que define vários contêineres, no fundo é como se o fizesse vários docker run, um para cada contêiner.&lt;/p&gt;
&lt;p&gt;Para executá lo, basta baixar esse arquivo como docker-compose.yml e rodar o docker-compose up -d&lt;/p&gt;
&lt;p&gt;Temos 3 contêineres definidos: o traefik, o whoami (usado para debugar o traefik) e o bitwarden (gerenciador de senhas). Repare como as “rotas” para o traefik estão definidas nos labels de cada contêiner ✨&lt;/p&gt;
&lt;p&gt;Espere um pouco e vamos testar tudo: abra seu navegador no endereço &lt;code&gt;localhost/whoami/&lt;/code&gt; , e veja a rota para o whoami funcionando. Depois vá para &lt;code&gt;localhost/vault/&lt;/code&gt; e acesse o bitwarden. Por fim &lt;code&gt;localhost:8080&lt;/code&gt; e veja o dashboard do traefik (não se esqueça de colocar uma senha depois).&lt;/p&gt;
&lt;p&gt;No bitwarden, repare na parte volumes, aqui os dados da aplicação serão salvos na pasta docker_vols/bwdata, para ser feito o backup.&lt;/p&gt;
&lt;p&gt;No traefik, veja em volumes: &lt;code&gt;/var/run/docker.sock:/var/run/docker.sock:ro&lt;/code&gt;, isso vai “conectar” o docker no contêiner do traefik, fazemos isso para que o mesmo consiga “mapear” os outros contêineres e ler suas regras de roteamento em suas labels. Tome cuidado e só faça isso com contêineres que confia pois isso pode dar a permissão de acessar e comprometer os todos seus contêineres e seu computador.&lt;/p&gt;
&lt;p&gt;Por fim repare que todos os contêineres têm &lt;code&gt;restart: unless-stopped&lt;/code&gt;, isso é a política de restart do docker, dessa forma caso o computador seja desligado quando for ligado os contêineres serão iniciados automaticamente, unless stopped, ou seja a menos que sejam parados.&lt;/p&gt;
&lt;p&gt;Ultimo exemplo:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;display:grid;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;display:grid;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;15
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;16
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;28
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;29
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;30
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;31
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;32
&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;33
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;34
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;35
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;36
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;37
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;38
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;39
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;40
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;41
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;42
&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;43
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;44
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;45
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;46
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;47
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;48
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;49
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;50
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;51
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;52
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;53
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;54
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;55
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;56
&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;57
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;background-color:#323232&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;58
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;59
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;60
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;61
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;62
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;63
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#454545&#34;&gt;64
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;display:grid;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;version&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;2.1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;networks&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;web&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;external&lt;/span&gt;: &lt;span style=&#34;color:#d75f00&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;internal_net&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;external&lt;/span&gt;: &lt;span style=&#34;color:#d75f00&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;services&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;traefik&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;traefik:v2.4&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;container_name&lt;/span&gt;: &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;traefik&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;restart&lt;/span&gt;: unless-stopped
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;networks&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;      - web
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;command&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#4e4e4e&#34;&gt;#- &amp;#34;--log.level=DEBUG&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;--api.insecure=true&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;--providers.docker=true&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;--providers.docker.exposedbydefault=false&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;--entrypoints.web.address=:80&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;ports&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;80:80&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;8080:8080&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;/var/run/docker.sock:/var/run/docker.sock:ro&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;ttrss&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;image&lt;/span&gt;: wangqiru/ttrss:latest
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;container_name&lt;/span&gt;: ttrss
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;restart&lt;/span&gt;: unless-stopped
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;networks&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;    - internal_net
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;    - web
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;environment&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - DB_PASS=E7WaTdu9KPLXxYXTqtrA
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - SELF_URL_PATH=http://localhost/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - DB_HOST=ttrss_db
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - PUID=1000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - PGID=1000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - TZ=America/Sao_Paulo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;depends_on&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;      - ttrss_db
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;labels&lt;/span&gt;: 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;traefik.enable=true&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;traefik.http.routers.ttrss.rule=PathPrefix(`/ttrss/`)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;traefik.http.routers.ttrss.entrypoints=web&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;traefik.http.middlewares.sp1.stripprefix.prefixes=/ttrss/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;traefik.http.routers.ttrss.middlewares=sp1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;traefik.docker.network=web&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#0087ff&#34;&gt;ttrss_db&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;image&lt;/span&gt;: postgres:13-alpine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;container_name&lt;/span&gt;: ttrss_db
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;restart&lt;/span&gt;: unless-stopped
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;networks&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#323232&#34;&gt;&lt;span&gt;      - internal_net
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;environment&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - POSTGRES_PASSWORD=E7WaTdu9KPLXxYXTqtrA
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - ./docker_vols/ttrss_db/:/var/lib/postgresql/data
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0087ff&#34;&gt;labels&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;traefik.enable=false&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Continuamos com o nosso conhecido traefik, mas agora vamos colocar no ar o &lt;a href=&#34;https://tt-rss.org/&#34;&gt;tt-rss&lt;/a&gt;, que é um leitor de feeds RSS, que utiliza um banco de dados postgres, essa é a primeira coisa diferente nesse exemplo repare que no topo estão definidas 2 redes (uma chamada web e outra internal_net). O traefik que é o contêiner que está exposto está apenas na web, a aplicação (ttrss) em ambas as redes e o banco de dados apenas na internal_net. Fizemos isso para segregar o banco de dados (que contêm dados sensíveis) do traefik para que o mesmo caso comprometido não acesse o(s) banco de dados.&lt;/p&gt;
&lt;p&gt;Outra coisa a destacar é a opção depends_on, que cria um relação de dependência entre o contêiner da aplicação (ttrss) e o seu banco de dados, iniciando o banco de dados antes da da aplicação.&lt;/p&gt;
&lt;h2 id=&#34;segurança&#34;&gt;Segurança&lt;/h2&gt;
&lt;p&gt;A fim de manter tudo isso seguro, existem diversas práticas e níveis de segurança, um bom começo é ter senhas fortes e únicas (evitar o famoso usuário admin com senha admin) com um gerenciador de senhas e realizar as atualizações de segurança.&lt;/p&gt;
&lt;p&gt;Para deixar todos seus contêineres atualizados, tem o &lt;a href=&#34;https://crazymax.dev/diun/&#34;&gt;Diun&lt;/a&gt;, que “conecta” no docker (como fizemos com o traefik) e verifica periodicamente se existem atualizações para seus contêineres, disparando uma notificação via email ou telegram etc &amp;hellip;&lt;/p&gt;
&lt;p&gt;Já para manter o host atualizado, uma possibilidade é utilizar o &lt;a href=&#34;https://wiki.debian.org/UnattendedUpgrades&#34;&gt;UnattendedUpgrades&lt;/a&gt; que atualiza os pacotes automaticamente, e se quiser pode até reiniciar automaticamente quando necessário. Porém, talvez seja melhor assinar as listas de email/rss de segurança da sua distro (&lt;a href=&#34;https://www.debian.org/security/&#34;&gt;debian security-announce&lt;/a&gt;, &lt;a href=&#34;https://ubuntu.com/security/notices&#34;&gt;Ubuntu USN&lt;/a&gt;), do docker e das suas aplicações e frameworks e veja se faz aquelas atualizações de fato te afetam e se realmente faz sentido aplica-lás.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/selfhosting/forkbomb.png&#34; loading=&#34;lazy&#34;
         alt=&#34;https://twitter.com/nixcraft/status/878903460871061504&#34; width=&#34;500px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;a href=&#34;https://twitter.com/nixcraft/status/878903460871061504&#34;&gt;https://twitter.com/nixcraft/status/878903460871061504&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Um site excelente para deixar nos favoritos é o Open Web Application Security Project (&lt;a href=&#34;https://owasp.org/&#34;&gt;owasp&lt;/a&gt;) é uma comunidade de segurança com diversas dicas e recomendações, por exemplo: &lt;a href=&#34;https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html&#34;&gt;como armazenar senhas de forma segura&lt;/a&gt; e no nosso caso &lt;a href=&#34;https://cheatsheetseries.owasp.org/cheatsheets/Docker_Security_Cheat_Sheet.html&#34;&gt;Docker security&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Uma forma excelente para aprender segurança é praticar nas Capture the flag (CTF) que são ambientes controlados para testar a segurança como um todo e revelar a flag (tipo uma senha), comprovando que conseguiu comprometer a segurança. Tem vários sites, tenho mais contato com o &lt;a href=&#34;https://overthewire.org/wargames/&#34;&gt;overthewire&lt;/a&gt; e o &lt;a href=&#34;https://www.hackthebox.eu/&#34;&gt;hackthebox&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Um vídeo que gostei foi do LiveOverflow: &lt;a href=&#34;https://www.youtube.com/watch?v=fKuqYQdqRIs&#34;&gt;Protect Linux Server From Hackers&lt;/a&gt;, no qual ele disseca as dicas populares de boas práticas para proteger seus servidores linux e ele mostrou que essas boas práticas nem sempre são tão positivas e “preto no branco”. Depois ele fez uma continuação bem interessante: &lt;a href=&#34;https://www.youtube.com/watch?v=lKzsNp4AveY&#34;&gt;Understand Security Risk vs. Security Vulnerability!&lt;/a&gt; pontuando as diferenças e semelhanças entre riscos de segurança e vulnerabilidades.&lt;/p&gt;
&lt;h2 id=&#34;monitoramento&#34;&gt;Monitoramento&lt;/h2&gt;
&lt;p&gt;Na seção anterior sobre storage, como saberemos se um disco falhou? Quando tudo parar de funcionar? Ou tem algum jeito de “ficar de olho”, por isso que precisamos ter uma solução de monitoramento.&lt;/p&gt;
&lt;p&gt;As soluções mais populares de monitoramento são o &lt;a href=&#34;https://www.zabbix.com/&#34;&gt;zabbix&lt;/a&gt; e o &lt;a href=&#34;https://prometheus.io/&#34;&gt;prometheus&lt;/a&gt;, que depois de configurados te notificam em caso de alguma falha.&lt;/p&gt;
&lt;p&gt;No caso dos discos, temos dois indicativos que os discos estão para falhar: As informações S.M.A.R.T. &amp;ndash; Self-Monitoring, Analysis, and Reporting Technology (tecnologia de automonitoramento, análise e relatório) geradas pelo próprio disco com diversas informações da &amp;ldquo;saúde&amp;rdquo; do disco, o disco não gera isso sozinho, sua solução de monitoramento precisa disparar os auto-testes e monitorar essas infos. Porém um &lt;a href=&#34;https://static.googleusercontent.com/media/research.google.com/en//archive/disk_failures.pdf&#34;&gt;estudo&lt;/a&gt; de 2007 do Google, mostrou que os dados S.M.A.R.T sozinho não são um bom indicativo da falha dos discos, daí surgem o segundo indicativo o tempo de escrita e leitura, se o disco começa a demorar muito para ler ou escrever isso pode indicar uma falha, essa informação é gerada na solução de monitoramento.&lt;/p&gt;
&lt;p&gt;Outra solução legal de monitoramento é o &lt;a href=&#34;https://healthchecks.io/&#34;&gt;healthchecks.io&lt;/a&gt;, serviço para monitorar seus cronjobs (tarefas executadas periodicamente), por exemplo imagine que você configurou para fazer backup do seu laptop na sua Raspberry Pi, mas por algum problema o backup para de ser feito com sucesso. Como vai saber que parou de funcionar? No healthchecks.io você configura uma periodicidade que os backups devem ser feitos e quando é feito o backup seu laptop “pinga” o serviço, e em caso de falha ou o backup deixou de rodar uma notificação é enviada.&lt;/p&gt;
&lt;h2 id=&#34;infraestrutura-como-código&#34;&gt;Infraestrutura como código&lt;/h2&gt;
&lt;p&gt;Essa é a parte mais legal 🤩, chegou o dia que seu SD card da Raspberry Pi morreu 😞 , tranquilo só fazer a restauração do backup no SD novo e instalar e configurar tudo mas isso pode ser demorado, com a infraestrutura como código (IaC) você cria uma “receita” que configura toda sua infra automaticamente.&lt;/p&gt;
&lt;p&gt;A ferramenta que tenho mais contato é o &lt;a href=&#34;https://www.ansible.com/&#34;&gt;ansible&lt;/a&gt;, ele é similar ao &lt;a href=&#34;https://www.chef.io/&#34;&gt;chef&lt;/a&gt; e &lt;a href=&#34;https://puppet.com/&#34;&gt;puppet&lt;/a&gt;. A principal vantagem do ansible é que ele é agentless, ou seja não precisa de um ter software instalado esperando por instruções do controle, basta ter o python instalado e acesso ssh e na máquina que vai disparar o ansible basta instalar com um pip install, super prático.&lt;/p&gt;
&lt;p&gt;Apesar de ser muito legal automatizar a configuração dos ambientes com IaC, se tudo é importante nada é importante, a IaC não precisa estar no topo das suas prioridades quando configurando seu setup.&lt;/p&gt;
&lt;h2 id=&#34;considerações-finais&#34;&gt;Considerações finais&lt;/h2&gt;
&lt;p&gt;Espero com essa visão geral dos aspectos do self-hosting tenha uma noção do que se trata e comece a aprender mais sobre o tema e adotar esse movimento.&lt;/p&gt;
&lt;p&gt;Além de todas indicações que já fiz vou fechar indicando um podcast: o &lt;a href=&#34;https://selfhosted.show/&#34;&gt;Self-Hosted podcast&lt;/a&gt; que me ajudou muito a aprender sobre esses tópicos e o canal do YouTube: &lt;a href=&#34;https://www.youtube.com/c/TechnoTimLive/featured&#34;&gt;Techno Tim&lt;/a&gt; que tem várias dicas de como montar seu homelab.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>O que é selfhosting e por que adotá-lo</title>
      <link>https://caioau.net/blog/intro-selfhosting/</link><category>devops</category>
		  <category>computando-arte</category>
		  <category>texto</category>
		  <category>raspberry-pi</category>
		  <category>selfhost</category>
		  
      <pubDate>Fri, 28 May 2021 16:00:00 -0300</pubDate>
      
      <guid>https://caioau.net/blog/intro-selfhosting/</guid><description>&lt;p&gt;Obs.: Originalmente publicado no &lt;a href=&#34;https://caioau.net/blog/computando-arte/&#34;&gt;computando-arte&lt;/a&gt; dia 28Maio2021&lt;/p&gt;
&lt;p&gt;Muitos dos serviços digitais que utilizamos no nosso dia a dia estão na &amp;ldquo;nuvem&amp;rdquo;, como Gmail, LinkedIn, Google Drive/Docs etc &amp;hellip; e como diria um famoso ditado “essa tal de &amp;ldquo;nuvem&amp;rdquo; não existe, são apenas computadores de outras pessoas”. Mas, então quais as implicações da maioria das nossas vidas digitais estar nesses computadores dessas grandes empresas? Essas implicações no geral são positivas para os usuários?&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/intro-selfhosting/fsfe-nocloud.jpg&#34; loading=&#34;lazy&#34; width=&#34;400px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Neste texto, que vai ser o primeiro de uma série, vamos falar de uma alternativa simples chamada self hosting, ou seja, hospedar os serviços que usamos em computadores que de fato temos controle, e como fazê-lo.&lt;/p&gt;
&lt;h2 id=&#34;motivos-para-adotar-o-self-hosting&#34;&gt;Motivos para adotar o self-hosting&lt;/h2&gt;
&lt;p&gt;Dentre todos os motivos para adotar o self-hosting, vale destacar os seguintes:&lt;/p&gt;
&lt;h3 id=&#34;segurança&#34;&gt;Segurança&lt;/h3&gt;
&lt;p&gt;Com muita frequência, vemos notícias de vazamentos envolvendo nossos dados, e mesmo assim muitos dos vazamentos não são percebidos pelas próprias empresas e logo não são noticiados, ou seja, a quantidade de vazamentos pode ser ainda maior.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/intro-selfhosting/dados-vazam.jpg&#34; loading=&#34;lazy&#34; width=&#34;400px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Hospedando as próprias coisas não é um alvo tão grande para os cibercriminosos quanto das big tech, pense nos incentivos, se comprometer uma big tech o cibercriminoso vai ter os dados de milhões de pessoas , enquanto comprometer sua pequena infra não rendera tanto dados assim. Além disso outro incentivo para atacar as big tech é que muitas delas tem programas de bug bounty para recompensar a descoberta da suas inseguranças.&lt;/p&gt;
&lt;p&gt;E também isso vai te ensinar quais são as boas práticas de segurança e como adota-lá.&lt;/p&gt;
&lt;h3 id=&#34;privacidade&#34;&gt;Privacidade&lt;/h3&gt;
&lt;p&gt;Outro ditado famoso diz que se o serviço é gratuito, o produto é você. E isso é verdade, você está pagando o serviço com seus dados.&lt;/p&gt;
&lt;p&gt;Com selfhosting, seus dados ficam apenas com você, retomando totalmente sua privacidade, afinal foi você quem montou o esquemas de criptografia de disco, gerenciamento de senhas (afinal como as senhas sempre vazam não pode usar a mesma senha em mais de um lugar, é bom se inscrever no &lt;a href=&#34;https://haveibeenpwned.com/&#34;&gt;haveibeenpwned.com&lt;/a&gt; para ser notificado se suas senhas vazaram)&lt;/p&gt;
&lt;h3 id=&#34;aprendizado-e-experiência&#34;&gt;Aprendizado e experiência&lt;/h3&gt;
&lt;p&gt;Pra min essa é a principal vantagem, hospedar suas próprias coisas vai proporcionar um conhecimento e experiência enorme em diversas disciplinas como:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sistemas operacionais (principalmente Linux e talvez BSD).&lt;/li&gt;
&lt;li&gt;Redes&lt;/li&gt;
&lt;li&gt;Segurança&lt;/li&gt;
&lt;li&gt;Contêineres&lt;/li&gt;
&lt;li&gt;Linguagens de script&lt;/li&gt;
&lt;li&gt;Infraestrutura como código&lt;/li&gt;
&lt;li&gt;Monitoramento&lt;/li&gt;
&lt;li&gt;E principalmente Inglês&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ter o seu &amp;ldquo;ambiente controlado&amp;rdquo; vai te possibilitar aprender, testar e quebrar as coisas que te proporcionará um aprendizado enorme que num ambiente profissional do trabalho muitas vezes não te permitiria.&lt;/p&gt;
&lt;h2 id=&#34;exemplos-de-aplicações&#34;&gt;Exemplos de aplicações&lt;/h2&gt;
&lt;p&gt;As aplicações mais comuns que normalmente são hospedadas são:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://pi-hole.net/&#34;&gt;Pi-Hole&lt;/a&gt;: Permite bloquear anúncios, domínios que te rastreia e maliciosos a nível de rede, ou seja em todos seus dispositivos não apenas no navegador.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://syncthing.net/&#34;&gt;syncthing&lt;/a&gt;: É um app pra Android no PC que permite sincronizar pastas do seu android com o PC e vice versa. Dessa forma você consegue fazer backup do seu celular e sincronizar arquivos sem precisar de uma nuvem das big tech. Se tiver interesse leia meu texto de como montei meu setup de backups: &lt;a href=&#34;https://caioau.net/blog/backups/&#34;&gt;Como parei de me preocupar e passei a adorar minha solução de backups&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://nextcloud.com/&#34;&gt;nextcloud&lt;/a&gt;: É uma solução de nuvem completa, permite sincronizar arquivos como dropbox, sincronizar contatos e agenda, quadro kanban (tipo trello), videochamadas e muito mais.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.home-assistant.io/&#34;&gt;Home Assistant&lt;/a&gt;: Gosta da sua alexa ou google assistant controlando suas luzes e outras coisas da sua smart home? Com o Home assistant você consegue ter seu próprio hub de automação com total privacidade e controle. Gosta de eletrônica? O projeto &lt;a href=&#34;https://esphome.io/&#34;&gt;esphome&lt;/a&gt; consegue integrar suas plaquinhas ESP8266/ESP32  com o Home Assistant.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;considerações-finais&#34;&gt;Considerações finais&lt;/h2&gt;
&lt;p&gt;Com o selfhosting você terá privacidade e controle total dos seus dados e vai aprender muito nessa jornada, nós próximos textos vamos abordar de fato começar.&lt;/p&gt;
&lt;p&gt;Vale uma pequena ressalva, casos você seja uma pessoa dev e só quer colocar seu app no ar, e seu objetivo principal agora é apenas isso, talvez ir pelo caminho do selfhosting não seja a melhor alternativa agora, administração de sistemas é muitas vezes um trabalho de tempo integral e talvez seja melhor usar serviços como &lt;a href=&#34;https://www.heroku.com/&#34;&gt;heroku&lt;/a&gt;, &lt;a href=&#34;https://vercel.com/&#34;&gt;vercel&lt;/a&gt; e &lt;a href=&#34;https://www.netlify.com/&#34;&gt;netlify&lt;/a&gt; que cuidaram de tudo para você, para que consiga fazer essa entrega mais rápido. E quanto tiver disponibilidade estudar e adotar o selfhosting :P&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Utilizando o RSS para &#34;furar a bolha&#34;</title>
      <link>https://caioau.net/blog/guia-rss/</link><category>dicas</category>
		  <category>computando-arte</category>
		  <category>rss</category>
		  <category>aaron-swartz</category>
		  <category>texto</category>
		  <category>raspberry-pi</category>
		  <category>selfhost</category>
		  
      <pubDate>Tue, 27 Apr 2021 13:00:00 -0300</pubDate>
      
      <guid>https://caioau.net/blog/guia-rss/</guid><description>&lt;p&gt;Obs.: Originalmente publicado no &lt;a href=&#34;https://caioau.net/blog/computando-arte/&#34;&gt;computando-arte&lt;/a&gt; dia 27Abr2021&lt;/p&gt;
&lt;p&gt;Já percebeu que o seu feed da rede social está cheio de notícias que fazem você &amp;ldquo;passar raiva&amp;rdquo;? O fenômeno é chamado de doomscrolling, e apesar que de termos mais notícias desse tipo, as redes sociais as exibem com mais frequência.&lt;/p&gt;
&lt;p&gt;A conhecida &amp;ldquo;bolha&amp;rdquo; (filter Bubble) das redes sociais faz com fiquemos mais tempo nas redes, exibindo apenas posts que engajamos mais, e isso está causando diversas consequências nefastas desde potencializar fake news e desinformação a ansiedade e depressão nos internautas.&lt;/p&gt;
&lt;p&gt;Mas se eu te disser que existe uma alternativa? Um meio de receber as informações diretamente, sem nenhum filtro ou algoritmo. É disto que vamos falar hoje, o RSS.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/guia-rss/rss-logo.png&#34; loading=&#34;lazy&#34;
         alt=&#34;Logo do RSS&#34; width=&#34;300px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Logo do RSS&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;o-que-é-orss&#34;&gt;O que é o RSS?&lt;/h2&gt;
&lt;p&gt;RSS é a sigla para Really Simple Syndication, sincronização realmente simples, é um arquivo XML gerado por muitos sites que exibe os posts que o site tem, dessa forma a pessoa com um leitor de RSS consegue acompanhar diversos blog, sites de noticia e etc … centralizados no seu leitor.&lt;/p&gt;
&lt;h2 id=&#34;quem-criou-orss&#34;&gt;Quem criou o RSS?&lt;/h2&gt;
&lt;p&gt;Uma das pessoas responsáveis pela criação do RSS foi o Aaron Swartz, um hacker conhecido por diversas coisas como o Creative Commons e da melhor rede social o Reddit 😛&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/guia-rss/Aaron-Swartz.jpeg&#34; loading=&#34;lazy&#34;
         alt=&#34;Aaron Swartz (2008), Fonte: wikimedia&#34; width=&#34;400px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Aaron Swartz (2008), Fonte: &lt;a href=&#34;https://commons.wikimedia.org/wiki/File:Aaron_Swartz_profile.jpg&#34;&gt;wikimedia&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Quem se interessou pela historia do Aaron recomendo os seguintes conteúdos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;O documentário: &lt;strong&gt;O Menino da Internet: A História de Aaron Swartz&lt;/strong&gt;: &lt;a href=&#34;https://libreflix.org/i/the-internets-own-boy&#34;&gt;LibreFlix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;E pra quem gosta de podcast Engenharia Reversa #1: &lt;a href=&#34;https://anchor.fm/engreversa/episodes/Aaron-Swartz--a-histria-do-ativista-e-co-criador-do-Reddit-e-do-RSS-1-eiif3j/a-a3166kn&#34;&gt;Aaron Swartz, a história do ativista e co-criador do Reddit e do RSS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;como-usar-o-rss-parte-1-osleitores&#34;&gt;Como usar o RSS? Parte 1: Os leitores&lt;/h2&gt;
&lt;p&gt;Para usar o RSS você precisa de um leitor de RSS, e não faltam opções! A primeira classe de leitores são os locais, um app local no seu computador ou celular que infelizmente não sincroniza entre seus dispositivos, se isso não é um problema para você é uma ótima opção.&lt;/p&gt;
&lt;p&gt;O &lt;a href=&#34;https://www.thunderbird.net/&#34;&gt;thunderbird&lt;/a&gt; (cliente livre de emails) é a opção mais tradicional.&lt;/p&gt;
&lt;p&gt;Gosta de programas que rodam no terminal? tem o &lt;a href=&#34;https://newsboat.org/&#34;&gt;newsboat&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Para Linux tem o liferea que está disponível na maioria das distribuições.&lt;/p&gt;
&lt;p&gt;No Android tem o &lt;a href=&#34;https://play.google.com/store/apps/details?id=com.nononsenseapps.feeder.play&#34;&gt;Feeder&lt;/a&gt;, que também está disponível na &lt;a href=&#34;https://f-droid.org/&#34;&gt;Fdroid&lt;/a&gt; (loja de aplicativos livres).&lt;/p&gt;
&lt;p&gt;Tem Mac ou iOS? Uma opção ótima é o &lt;a href=&#34;https://netnewswire.com/&#34;&gt;NetNewsWire&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Depois desse monte de opções, se não quiser instalar nada 😛 tem o &lt;a href=&#34;https://nodetics.com/feedbro/&#34;&gt;Feedbro&lt;/a&gt; extensão para os navegadores (chrome e firefox).&lt;/p&gt;
&lt;p&gt;Essas são todas as opções de leitores locais que conheço.&lt;/p&gt;
&lt;p&gt;Vamos agora para as opções online, que permitem sincronizar entre seus dispositivos, é muito prático pois se viu algo interessante no computador pode marcar para ler depois no celular e vice versa.&lt;/p&gt;
&lt;p&gt;O &lt;a href=&#34;https://feedly.com/&#34;&gt;Feedly&lt;/a&gt; é o serviço mais conhecido, tem um plano básico gratuito, bem amigável, para quem está começando recomendo ir com ele.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/guia-rss/feedly.png&#34; loading=&#34;lazy&#34;
         alt=&#34;Captura de tela do Feedly&#34; width=&#34;900px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Captura de tela do Feedly&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Por fim, a opção que eu uso, para quem gosta de software livre e se preocupa com sua privacidade, o Tiny Tiny RSS (&lt;a href=&#34;https://tt-rss.org/&#34;&gt;tt-rss.org&lt;/a&gt;). Você pode instalar numa raspberry-pi e acessar na sua rede local (caso precise acessar fora de casa pode usar serviços como &lt;a href=&#34;https://pagekite.net/&#34;&gt;Pagekite&lt;/a&gt; e &lt;a href=&#34;https://ngrok.com/&#34;&gt;ngrok&lt;/a&gt; para torna-ló acessível pela internet) ou alugar uma cloud e hospedar lá.&lt;/p&gt;
&lt;p&gt;Outra opção para usar o tt-rss é utilizar a instancia do &lt;a href=&#34;https://snopyta.org/&#34;&gt;Snopyta&lt;/a&gt; (grupo sustentado por doações que hospeda diversos softwares livres).&lt;/p&gt;
&lt;h2 id=&#34;como-usar-o-rss-parte-2-assinando-osfeeds&#34;&gt;Como usar o RSS? Parte 2: Assinando os feeds&lt;/h2&gt;
&lt;p&gt;Com um leitor de RSS da sua preferencia funcionando, bora assinar os feeds!&lt;/p&gt;
&lt;p&gt;Vamos começar pelo YouTube, os feeds são assim:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;www.youtube.com/feeds/videos.xml?channel_id=&amp;lt;id_do_canal&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Substitua no final pelo channel_id do canal que quer assinar. Um truque para descobrir o id que tem interesse: Selecione um vídeo, em seguida clique no ícone do canal e daí o channel_id vai aparecer na url. Por exemplo, o feed do canal da Jana Viscardi é o seguinte:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;www.youtube.com/feeds/videos.xml?channel_id=UC9h2vDtQXEiD0O4aVubsYYA&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Caso o truque não funcione, com o vídeo aberto, abra o código fonte da página (use o atalho control+u) e procure (control+f) por &lt;strong&gt;channelId&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Para acessar os feeds da melhor rede social 😛, o Reddit:&lt;/p&gt;
&lt;p&gt;Na &lt;a href=&#34;https://www.reddit.com/wiki/rss&#34;&gt;wiki tem uma seção sobre RSS&lt;/a&gt;, basta colocar um .rss no final. Por exemplo o feed do &lt;a href=&#34;https://old.reddit.com/r/dataisbeautiful/&#34;&gt;/r/dataisbeautiful&lt;/a&gt; é:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;old.reddit.com/r/dataisbeautiful/.rss&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Precisa acompanhar projetos do github? Por exemplo, utilizo aqui em casa um firmware livre no meu roteador, o &lt;a href=&#34;https://openwrt.org/&#34;&gt;OpenWRT&lt;/a&gt;, para acompanhar as releases o feed é:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;github.com/openwrt/openwrt/releases.atom&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;No mesmo padrão para acompanhar os commits, da branch master:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;github.com/openwrt/openwrt/commits/master.atom&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Obs.: Os feeds atom na prática são a mesma coisa que feeds RSS, alguns sites adotam isso.&lt;/p&gt;
&lt;p&gt;Gosta de Newsletters? O serviço &lt;a href=&#34;https://kill-the-newsletter.com/&#34;&gt;kill-the-newsletter.com&lt;/a&gt; cria um e-mail para você cadastrar na newsletter e um feed para assinar.&lt;/p&gt;
&lt;p&gt;Veja o &lt;a href=&#34;https://manualdousuario.net/newsletters-brasileiras/&#34;&gt;diretório de Newsletters brasileiras&lt;/a&gt; que o manual do usuário fez.&lt;/p&gt;
&lt;p&gt;Gosta do medium? o feed é assim: medium.com/feed/nome-do-usuario, por exemplo, o feed do computando arte 🤭 é:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;medium.com/feed/computando-arte&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;E o Twitter? Infelizmente o twitter descontinuou os seus feeds RSS 😞 Mas tem um software livre chamado &lt;a href=&#34;https://github.com/zedeus/nitter&#34;&gt;Nitter&lt;/a&gt; que permite navegar pelos posts do twitter com privacidade e gerar um feed rss.&lt;/p&gt;
&lt;p&gt;Tentei mostrar como chegar nos feeds de alguns serviços populares, mas e os outros? Então muitos sites e podcasts tem o ícone e/ou o link do seu feed, caso não encontre procure no código fonte da pagina por rss ou feed ou xml ou atom e você vai acabar encontrando. A maioria das tecnologias por trás dos sites como o super popular WordPress gera nativamente os feeds RSS.&lt;/p&gt;
&lt;p&gt;Por exemplo, até meu site pessoal simples uso o &lt;a href=&#34;https://gohugo.io/&#34;&gt;Hugo&lt;/a&gt; (gerador de sites estáticos, semelhante ao &lt;a href=&#34;https://jekyllrb.com/&#34;&gt;Jekyll&lt;/a&gt;) e coloquei o link pro meu feed, mas se for procurar no código fonte da página encontrará:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#0087ff&#34;&gt;link&lt;/span&gt; rel=&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;alternate&amp;#34;&lt;/span&gt; type=&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;application/rss+xml&amp;#34;&lt;/span&gt; href=&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#39;https://caioau.net/blog/index.xml&amp;#39;&lt;/span&gt; title=&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#34;Blogs on Pagina do caioau&amp;#34;&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pronto, aqui você encontra o meu feed RSS:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;caioau.net/blog/index.xml&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Por fim, não poderia fazer um texto sobre RSS sem falar do &lt;a href=&#34;https://github.com/RSS-Bridge/rss-bridge&#34;&gt;RSS-Bridge&lt;/a&gt;, software livre que gera feeds RSS apartir de páginas do facebook, instagram (dá até pra seguir hashtags ✨) , Wikipedia e várias outras integrações.&lt;/p&gt;
&lt;h2 id=&#34;considerações-finais&#34;&gt;Considerações finais&lt;/h2&gt;
&lt;p&gt;Com o RSS podemos &amp;ldquo;furar a bolha&amp;rdquo; e receber toda a informação sem filtros e algoritmos. Usando o RSS logo vai perceber uma das razões (além do lucro das big tech 💸) do porque desses filtros, é muita informação! Então use com moderação (para evitar o famoso FOMO, fear of missing out, a sensação de que não posso ficar minutos longe do meu celular pois estou perdendo algo) e tentar uma relação mais saudável com a tecnologia.&lt;/p&gt;
&lt;p&gt;Vale recomendar o episódio #41 do tecnocracia, é um podcast excelente sobre as consequências da tecnologia e vou indicar justamente o ep. #41: &lt;a href=&#34;https://manualdousuario.net/podcast/tecnocracia-41/&#34;&gt;Manual prático para retomar sua atenção do calabouço das redes sociais&lt;/a&gt; com várias dicas 🧘🔕 de como controlar o celular e as redes sociais e não o contrário.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/guia-rss/phone-addiction.jpg&#34; loading=&#34;lazy&#34;
         alt=&#34;Estamos usando a tecnologia? Ou sendo usados? (Fonte)&#34; width=&#34;300px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Estamos usando a tecnologia? Ou sendo usados? (&lt;a href=&#34;https://www.gizmodo.com.au/2014/09/a-vivid-reminder-from-banksy-that-technology-can-enslave-us-all/&#34;&gt;Fonte&lt;/a&gt;)&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Por fim, pra quem gosta do tema, vou indicar alguns conteúdos muito interessantes 🤯&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/guia-rss/meme-SocialDillema.jpeg&#34; loading=&#34;lazy&#34;
         alt=&#34;Crédito: Cryptorave no twitter&#34; width=&#34;500px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Crédito: Cryptorave no &lt;a href=&#34;https://twitter.com/cryptoravebr/status/1307305692185817094?s=19&#34;&gt;twitter&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;O documentário &lt;a href=&#34;https://www.imdb.com/title/tt11464826/&#34;&gt;Dilema nas Redes (2020)&lt;/a&gt;, disponível na Netflix, bombou! Adoro como ele é muito didático e expões as principais questões do tema, recomendo muito pra quem ainda não viu. Outro doc, é o &lt;a href=&#34;https://www.imdb.com/title/tt11394170/&#34;&gt;Coded Bias (2020)&lt;/a&gt; que foca mais nas tecnologias de reconhecimento facial e seus vieses e contou com a presença da Cathy O&amp;rsquo;Neil, autora do livro fenomenal Weapons of Math Destruction traduzido no Brasil como Algoritmos de Destruição em Massa.&lt;/p&gt;
&lt;p&gt;Uma talk recente, que eu adorei foi a &lt;a href=&#34;https://media.ccc.de/v/rc3-891673-rage_against_the_machine_learning&#34;&gt;Rage Against The Machine Learning&lt;/a&gt;, onde o Dr. Hendrik Heuer fala da sua pesquisa de auditoria dos algoritmos das redes sociais para o interesse público.&lt;/p&gt;
&lt;p&gt;Para podcast, vou indicar outros episódios do tecnocracia, é difícil indicar só alguns, todos são ótimos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;#18: &lt;a href=&#34;https://manualdousuario.net/podcast/tecnocracia-18/&#34;&gt;Em nome do lucro, o YouTube abriu os portões do inferno da desinformação&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;#40: &lt;a href=&#34;https://manualdousuario.net/podcast/tecnocracia-40/&#34;&gt;O filtro alucinógeno do Instagram colocou a humanidade no divã - e alguns no caixão&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;#42: &lt;a href=&#34;https://manualdousuario.net/podcast/tecnocracia-42/&#34;&gt;As empresas que nos colocaram nessa enrascada não nos tirarão dela&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Precisa transferir um arquivo? O magic-wormhole vai mudar sua vida!</title>
      <link>https://caioau.net/blog/magic-wormhole/</link><category>dicas</category>
		  <category>computando-arte</category>
		  <category>python</category>
		  <category>magic-wormhole</category>
		  <category>texto</category>
		  
      <pubDate>Mon, 19 Apr 2021 14:00:00 -0300</pubDate>
      
      <guid>https://caioau.net/blog/magic-wormhole/</guid><description>&lt;p&gt;Obs.: Originalmente publicado no &lt;a href=&#34;https://caioau.net/blog/computando-arte/&#34;&gt;computando-arte&lt;/a&gt; dia 19Abr2021&lt;/p&gt;
&lt;p&gt;Já precisou transferir um arquivo para alguém pela internet e não foi fácil chegar numa solução fácil? O magic-wormhole pode ser uma excelente alternativa!&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/magic-wormhole/xkcd-949.png&#34; loading=&#34;lazy&#34;
         alt=&#34;XKCD #949: File transfer&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;a href=&#34;https://xkcd.com/949/&#34;&gt;XKCD #949: File transfer&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Esse XKCD ilustra bem a motivação do magic-wormhole, a fim de copiar um arquivo para outra pessoa, algumas vezes sites como Dropbox não são a melhor opção, e como muitas vezes não se pode encontrar fisicamente para ser via um “pendrive” (principalmente com uma pandemia 😷) o magic-wormhole cria um “túnel mágico” para te salvar✨&lt;/p&gt;
&lt;h2 id=&#34;como-usar&#34;&gt;Como usar&lt;/h2&gt;
&lt;p&gt;O magic-wormhole é um programa em python para ser usado no terminal, então se você já tem o python instalado basta instalá-lo com o pip:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pip install magic-wormhole&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Uma vez instalado de ambos os lados (quem envia e quem recebe), basta rodar o comando &lt;strong&gt;wormhole send&lt;/strong&gt; seguido do nome do arquivo:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ wormhole send arquivo_a_ser_enviado
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Sending &lt;span style=&#34;color:#00afaf&#34;&gt;45&lt;/span&gt; Bytes file named &lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#39;arquivo_a_ser_enviado&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Wormhole code is: 6-wichita-reindeer
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;On the other computer, please run:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wormhole receive 6-wichita-reindeer&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Agora, quem vai receber deve digitar &lt;strong&gt;wormhole receive&lt;/strong&gt; seguindo do código gerado (6-wichita-reindeer).&lt;/p&gt;
&lt;p&gt;É isso! Como mágica o arquivo é enviado como mágica 🤩&lt;/p&gt;
&lt;h2 id=&#34;como-funciona-o-magic-wormhole&#34;&gt;Como funciona o magic-wormhole?&lt;/h2&gt;
&lt;p&gt;Sem entrar muito em detalhes, o magic-wormhole funciona em 2 partes: a descoberta e o envio em si.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A pessoa que vai enviar o arquivo roda o wormhole send.&lt;/li&gt;
&lt;li&gt;É gerado um código (ex.: 6-wichita-reindeer), pelo servidor mailbox do magic-wormhole.&lt;/li&gt;
&lt;li&gt;Quando o cliente entra com o código, a pessoa que envia e a recebe conseguem “se encontrar”.&lt;/li&gt;
&lt;li&gt;É tentado uma conexão direta, entre as duas pessoas, se estiverem na mesma rede local vai funcionar e ser muito rápido, caso contrário o magic-wormhole intermedia a conexão através do seu servidor de transito (a conexão sempre é criptografada).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Quem tiver interesse para aprender profundamente como funciona veja a &lt;a href=&#34;https://www.youtube.com/watch?v=oFrTqQw0_3c&#34;&gt;palestra do Brian Warner, o autor original do projeto na PyCon 2016&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Outro programa excelente que funciona de uma maneira similar, mas para outro proposito é o &lt;a href=&#34;https://syncthing.net/&#34;&gt;Syncthing&lt;/a&gt;, que permite sincronizar os arquivos entre seus dispositivos, criando sua “nuvem privada” somente com seus dispositivos.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>O que é um tarpit de rede e como colocar um no ar</title>
      <link>https://caioau.net/blog/endlessh/</link><category>dicas</category>
		  <category>computando-arte</category>
		  <category>texto</category>
		  <category>raspberry-pi</category>
		  <category>selfhost</category>
		  <category>devops</category>
		  <category>systemd</category>
		  <category>security</category>
		  <category>linux</category>
		  
      <pubDate>Mon, 18 Jan 2021 13:00:00 -0300</pubDate>
      
      <guid>https://caioau.net/blog/endlessh/</guid><description>&lt;p&gt;Obs.: Originalmente publicado no &lt;a href=&#34;https://caioau.net/blog/computando-arte/&#34;&gt;computando-arte&lt;/a&gt; dia 18Jan2021&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/endlessh/lock-picking.jpeg&#34; loading=&#34;lazy&#34;
         alt=&#34;Foto de Ariel Besagar, Unsplash&#34; width=&#34;600px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Foto de &lt;a href=&#34;https://unsplash.com/@arielbesagar&#34;&gt;Ariel Besagar&lt;/a&gt;, &lt;a href=&#34;https://unsplash.com/photos/Oal07Ai4oTk&#34;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Quando vemos as notícias de cyber ataques, como o WannaCry, é impressionante o impacto desses ataques, infectando milhares de computadores. No caso do WannaCry existia uma atualização de segurança que foi publicada 1 mês antes do ataque, quem não atualizou e estava exposto na internet provavelmente foi infectado. Moral da historia é deve se tomar todas precauções de segurança antes de expor algum computador na Internet. Se tiver interesse, leia as essas estatísticas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.zdnet.com/article/this-server-was-online-for-under-a-minute-before-cyber-criminals-started-to-hack-it/&#34;&gt;Em menos de 1 minuto online esse servidor começou a ser atacado&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://web.archive.org/web/20200923072723/https://associationsuccess.org/empower/how-long-until-were-hacked-a-lesson-in-server-vulnerability/&#34;&gt;“Quanto tempo até sermos atacados?” Uma lição sobre vulnerabilidade de servidores&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Assim que se coloca algum serviço na internet pública, em poucos minutos, já vemos que os logs de acesso do ssh (protocolo para acessar remotamente computadores) estão lotados de tentativas de combinações de usuário e senha, para conseguir acesso no servidor. Neste texto vamos mostrar como se proteger e como colocar um tarpit no lugar, uma especie de “armadilha” que deixa os atacantes “parados” perdendo tempo e recursos sem atacar ninguém, protegendo quem está vulnerável.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/endlessh/logs-ssh.jpg&#34; loading=&#34;lazy&#34;
         alt=&#34;Logs de acesso do ssh: Fonte&#34; width=&#34;700px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Logs de acesso do ssh: &lt;a href=&#34;https://dailydoseoftech.com/how-to-view-failed-ssh-login-attempts-on-linux/&#34;&gt;Fonte&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;começando-pelo-começo-protegendo-seu-servidor-ssh&#34;&gt;Começando pelo começo: protegendo seu servidor ssh&lt;/h2&gt;
&lt;p&gt;De todas as mitigações para proteger seu servidor ssh, a medida mais efetiva é desativar a autenticação por senha e utilizar apenas a autenticação por chaves privadas.
Se ainda não tem uma chave ssh, gere uma com o comando &lt;strong&gt;ssh-keygen&lt;/strong&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Copie sua chave pro seu servidor: &lt;code&gt;ssh-copy-id -i ~/.ssh/id_rsa usuario@servidor&lt;/code&gt;, se necessário ajuste o caminho da chave depois do -i .&lt;/li&gt;
&lt;li&gt;Teste se está funcionando: &lt;code&gt;ssh usuario@servidor&lt;/code&gt; , se o ssh conectar sem pedir senha então está tudo certo.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Desativando autenticação por senha: logue no servidor (&lt;code&gt;ssh usuario@servidor&lt;/code&gt;), e edite o arquivo /etc/ssh/sshd_config como root (sudo nano /etc/ssh/sshd_config), por fim encontre a linha PasswordAuthentication e coloque no, não se esqueça de não deixar a linha comentada (tire o # no começo da linha). Por fim, reinicie o ssh,  &lt;code&gt;sudo systemctl restart sshd&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Testando: Tente logar com um usuário que não existe: tipo &lt;code&gt;ssh usr123321@servidor&lt;/code&gt;, e deve aparecer Permission denied (publickey).&lt;/p&gt;
&lt;p&gt;É isso que vai acontecer com quem tentar acessar seu servidor, uma permissão negada sem nem pedir senha.&lt;/p&gt;
&lt;h2 id=&#34;endlessh-o-que-faz-um-tarpit&#34;&gt;endlessh: O que faz um tarpit?&lt;/h2&gt;
&lt;p&gt;A tradução de Tarpit é “poço de areia movediça”, no nosso contexto de redes é um serviço que intencionalmente insere um atraso, atrasando os clientes que estão conectando e os forçando esperar.&lt;/p&gt;
&lt;p&gt;O endlessh é um tarpit de ssh, ele explora um “brecha” na especificação do ssh (&lt;a href=&#34;https://datatracker.ietf.org/doc/html/rfc4253&#34;&gt;RFC 4253&lt;/a&gt;) que diz que quando um cliente está conectando o servidor pode mandar um “banner” (aqueles avisos legais avisando a politica de segurança), mas a especificação não coloca um limite do tamanho desse banner. É assim que o endlessh funciona, um cliente conectando fica esperando mandar o resto do banner, e o endlessh fica mandando o banner de pouco em pouco só pra manter a conexão ativa. Dessa forma o atacante fica gastando banda e recursos sem acontecer nada ao invés de atacar os clientes que de fato estão inseguros.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/endlessh/ssh-banner.png&#34; loading=&#34;lazy&#34;
         alt=&#34;Exemplo de banner ssh, Fonte: https://www.healthcareitnews.com/news/warning-banners-often-work-heres-how-hospitals-can-use-them-ward-hackers&#34; width=&#34;700px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Exemplo de banner ssh, Fonte: &lt;a href=&#34;https://www.healthcareitnews.com/news/warning-banners-often-work-heres-how-hospitals-can-use-them-ward-hackers&#34;&gt;https://www.healthcareitnews.com/news/warning-banners-often-work-heres-how-hospitals-can-use-them-ward-hackers&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;colocando-o-endlessh-no-ar&#34;&gt;Colocando o endlessh no ar&lt;/h2&gt;
&lt;p&gt;Primeiramente vamos instalar as dependências necessárias:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo apt install git build-essential&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;O apt , ou similarmente apt-get, é um gerenciador de pacotes de distribuições Debian. Pense no gerenciador de pacotes como a app store de seu celular, um programa que instala, remove e atualiza os softwares do seu sistema. É uma maravilha, pois imagine que precisa atualizar o VLC, ao invés de ir ao site e baixar o instalador mais recente basta fazer sudo apt update, para verificar se existem atualizações e finalmente sudo apt upgrade para baixar e instalar as atualizações.&lt;/p&gt;
&lt;p&gt;O comando acima então instala o git e o pacote build-essential.&lt;/p&gt;
&lt;p&gt;Para saber o que um pacote é, podemos utilizar o info do apt, com &lt;code&gt;apt into build-essential&lt;/code&gt; temos:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Package: build-essential
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Version: &lt;span style=&#34;color:#00afaf&#34;&gt;12.9&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Priority: optional
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Build-Essential: yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Section: devel
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Maintainer: Matthias Klose &amp;lt;doko@debian.org&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Installed-Size: &lt;span style=&#34;color:#00afaf&#34;&gt;20.5&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Depends: libc6-dev | libc-dev, gcc (&amp;gt;= &lt;span style=&#34;color:#00afaf&#34;&gt;4&lt;/span&gt;:&lt;span style=&#34;color:#00afaf&#34;&gt;10.2&lt;/span&gt;), g++ (&amp;gt;= &lt;span style=&#34;color:#00afaf&#34;&gt;4&lt;/span&gt;:&lt;span style=&#34;color:#00afaf&#34;&gt;10.2&lt;/span&gt;), make, dpkg-dev (&amp;gt;= &lt;span style=&#34;color:#00afaf&#34;&gt;1.17&lt;/span&gt;.&lt;span style=&#34;color:#00afaf&#34;&gt;11&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Tag: devel::packaging, interface::commandline, role::data, role::program,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; scope::utility, suite::debian
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Download-Size: &lt;span style=&#34;color:#00afaf&#34;&gt;7&lt;/span&gt;,&lt;span style=&#34;color:#00afaf&#34;&gt;704&lt;/span&gt; B
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;APT-Manual-Installed: yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;APT-Sources: &amp;lt;https://deb.debian.org/debian&amp;gt; bullseye/main amd64 Packages
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Description: Informational list of build-essential packages
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; This package contains an informational list of packages which are
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; considered essential &lt;span style=&#34;color:#5f8700&#34;&gt;for&lt;/span&gt; building Debian packages.  This package also
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; depends on the packages on that list, to make it easy to have the
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; build-essential packages installed.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Instalamos o build-essential pois ele instala o compilador gcc e o make que vamos utilizar (veja na linha Depends).&lt;/p&gt;
&lt;p&gt;Clonando o projeto:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git clone https://github.com/skeeto/endlessh.git&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Agora precisamos compilar o projeto. Felizmente o projeto tem um makefile, que é um arquivo com os comando de compilações configurados. Dessa forma basta fazer &lt;code&gt;make&lt;/code&gt; e &lt;code&gt;sudo make install&lt;/code&gt; para gerar o binário do endlessh e copiar para /usr/local/bin.&lt;/p&gt;
&lt;p&gt;Agora pasta rodar o endlessh:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/usr/local/bin/endlessh -v&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2021-01-14T01:22:10.091Z Port 2222
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2021-01-14T01:22:10.091Z Delay 10000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2021-01-14T01:22:10.091Z MaxLineLength 32
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2021-01-14T01:22:10.091Z MaxClients 4096
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2021-01-14T01:22:10.091Z BindFamily IPv4 Mapped IPv6
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;O endlessh está rodando na porta 2222, então abra outra aba no terminal e faça ssh usuario@servidor -p 2222 e veja o que acontece … ou seja nada 😆&lt;/p&gt;
&lt;p&gt;Mas como faço pro endlessh iniciar sozinho? Na próxima secção vamos mostrar como :)&lt;/p&gt;
&lt;h2 id=&#34;systemd-como-manejar-serviços&#34;&gt;systemd: Como manejar serviços&lt;/h2&gt;
&lt;p&gt;O systemd é um sistema init, que é o primeiro processo iniciado durante o boot do sistema e ele é responsável por iniciar e gerenciar todos os serviços do sistema. Por exemplo, se está rodando um servidor web com nginx, o systemd vai iniciar o nginx automaticamente e em caso dele travar vai ser iniciado novamente, certificando-se que está sempre no ar.&lt;/p&gt;
&lt;p&gt;Na maioria das distribuições Linux, o systemd é o sistema init padrão, que é controlado através do comando systemctl. Por exemplo: veja o status de todos os serviços: &lt;code&gt;sudo systemctl status --all&lt;/code&gt; . aqui podemos ver a que serviço cada processo está associado.&lt;/p&gt;
&lt;p&gt;Mão na massa: na pasta util do endlessh temos o arquivo para subir o endlessh como serviço, o endlessh.service (dentro da pasta util). Não vamos entrar no detalhe das diretivas definidas desse arquivo, aos interessados veja o artigo sobre &lt;a href=&#34;https://wiki.archlinux.org/title/systemd&#34;&gt;systemd na arch wiki&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Vamos apenas mudar apenas uma coisa no arquivo, na linha exec coloque o -v, para ele rodar mostrando mais detalhes, como os exibir os clientes conectando, ficando assim: ExecStart=/usr/local/bin/endlessh -v&lt;/p&gt;
&lt;p&gt;Vamos copiar o arquivo para ser identificado: &lt;code&gt;sudo cp endlessh.service /etc/systemd/system/&lt;/code&gt;, agora faça &lt;code&gt;sudo systemctl daemon-reload&lt;/code&gt; para que seja reconhecido, e então finalmente &lt;code&gt;sudo systemctl enable endlessh&lt;/code&gt;, agora o endlessh está habilitado e deve iniciar automaticamente, para iniciá-lo agora faça &lt;code&gt;sudo systemctl start endlessh&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Só para ter certeza, faça &lt;code&gt;sudo systemctl status endlessh&lt;/code&gt;. Podemos ver o status do serviço&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/endlessh/systemd-status.png&#34; loading=&#34;lazy&#34; width=&#34;700px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Como queríamos, o serviço está rodando.&lt;/p&gt;
&lt;p&gt;Também podemos reiniciar o serviço com restart (&lt;code&gt;sudo systemctl restart endlessh&lt;/code&gt;), e stop para parar. Para desativar temos o disable, porém caso o serviço seja dependência de outro serviço ele pode acabar sendo iniciado. Nesses casos utilize o mask que previne que o serviço seja iniciado. Por fim, temos o reload que faz que com o serviço carregue sua nova configuração sem derrubar o serviço.&lt;/p&gt;
&lt;h2 id=&#34;journalctl-acessando-os-logs&#34;&gt;journalctl: Acessando os logs&lt;/h2&gt;
&lt;p&gt;Agora que o endlessh está rodando e é iniciado automaticamente, como faço para acessar a saída dele para vem quem está conectando?&lt;/p&gt;
&lt;p&gt;No systemd os logs de todos serviços podem ser acessados através do comando &lt;strong&gt;journalctl&lt;/strong&gt;, faça &lt;code&gt;sudo journalctl&lt;/code&gt; e veja os logs de todos serviços, inclusive do kernel.&lt;/p&gt;
&lt;p&gt;Para vermos apenas do endlessh: &lt;code&gt;sudo journalctl -u endlessh&lt;/code&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/endlessh/systemd-logs.png&#34; loading=&#34;lazy&#34;
         alt=&#34;logs do endlessh&#34; width=&#34;700px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;logs do endlessh&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Bora analisar os dados? 🤓&lt;/p&gt;
&lt;p&gt;Podemos pegar a saída do journalctl e jogar num arquivo para ser lido e parseado para ser colocado num dataframe, por exemplo.&lt;/p&gt;
&lt;p&gt;para fazer isso, basta rodar o comando:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;journalctl -u endlessh.service &amp;gt; /tmp/endlessh.log&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Dessa forma os logs estarão em /tmp/endlessh.log. Depois disso basta fazer um programa que lê o arquivo, para fazer suas análises. Mas né, sem tempo irmão 😛. Vamos pela solução simples, usar comandos de processamento de texto, do Unix ✨:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo journalctl -u endlessh --since 2021-01-15 --until 2021-01-16 | grep CLOSE | wc -l
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1044
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Da mesma forma que o operador &amp;gt; joga a saída pra um arquivo o | (chamado de pipe) redireciona a saída para o outro comando, dessa forma o commando acima conta quantas linhas CLOSE tinha. Ou seja no período de 1 dia tivemos 1044 conexões.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo journalctl -u endlessh --since 2021-01-15 --until 2021-01-16 | grep CLOSE | awk &amp;#39;{print $8}&amp;#39; | sort | uniq -c | sort -hr
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    705 host=::ffff:218.92.0.210
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     32 host=::ffff:87.251.77.206
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     12 host=::ffff:81.161.63.103
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     10 host=::ffff:221.181.185.220
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      9 host=::ffff:81.161.63.100
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      9 host=::ffff:222.187.222.53
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      9 host=::ffff:221.181.185.148
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      8 host=::ffff:221.181.185.135
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      8 host=::ffff:122.194.229.122
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      7 host=::ffff:218.92.0.211
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      6 host=::ffff:81.161.63.252
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      6 host=::ffff:81.161.63.101
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[...]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;O comando acima mostra os IPs que fizeram mais conexões.&lt;/p&gt;
&lt;h2 id=&#34;conclusão&#34;&gt;Conclusão&lt;/h2&gt;
&lt;p&gt;Neste texto aprendemos como proteger seu servidor ssh, dessa forma ninguém não autorizado vai conseguir acessar seu servidor. E mostramos como colocar no ar um tarpit para ajudar a proteger quem ainda está vulnerável. Além disso aprendemos como manejar serviços e fazer processamento de texto de uma forma bem rápida, usando ferramentas Unix, que são tarefas muito importantes na administração de sistemas.&lt;/p&gt;
&lt;p&gt;Como continuação dessa jornada de implementar as boas praticas de segurança, sugiro o seguinte tutorial da DigitalOcean: &lt;a href=&#34;https://www.digitalocean.com/community/tutorials/7-medidas-de-seguranca-para-proteger-seus-servidores-pt&#34;&gt;7 Medidas de Segurança para Proteger Seus Servidores&lt;/a&gt;. Para segurança digital pessoal, o vídeo da Eva Galperin é excelente: &lt;a href=&#34;https://www.youtube.com/watch?v=cQI0O7xdNOU&#34;&gt;Especialista em Internet desmistifica cyber segurança&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Primeiros passos com o pandas</title>
      <link>https://caioau.net/blog/pandas/</link><category>computando-arte</category>
		  <category>texto</category>
		  <category>python</category>
		  <category>ciencia-de-dados</category>
		  
      <pubDate>Mon, 30 Nov 2020 13:00:00 -0300</pubDate>
      
      <guid>https://caioau.net/blog/pandas/</guid><description>&lt;p&gt;Obs.: Originalmente publicado no &lt;a href=&#34;https://caioau.net/blog/computando-arte/&#34;&gt;computando-arte&lt;/a&gt; dia 30Nov2020&lt;/p&gt;
&lt;h2 id=&#34;o-que-é-o-pandas&#34;&gt;O que é o pandas&lt;/h2&gt;
&lt;p&gt;Pandas é uma biblioteca Python para trabalhar com dados tabulares, que como o nome sugere são os dados estruturados na forma de uma tabela: ou seja os elementos são arranjados em colunas verticais e linhas (ou registros) horizontais, dessa forma cada elemento é formado pela intersecção de uma coluna e uma linha.&lt;/p&gt;
&lt;p&gt;É uma das biblioteca mais importantes para Ciência de Dados. As principais bibliotecas são:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Aprendizado de máquina: scikit-learn&lt;/li&gt;
&lt;li&gt;Vetores e matrizes: numpy&lt;/li&gt;
&lt;li&gt;Scipy: várias coisas científicas(computação científica) 😜&lt;/li&gt;
&lt;li&gt;Gráficos: matplotlib, seaborn, plotly&lt;/li&gt;
&lt;li&gt;Redes neurais: pytorch e tensorflow&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;sobre-a-linguagem-python&#34;&gt;Sobre a linguagem Python&lt;/h2&gt;
&lt;p&gt;Python é umas das principais linguagens de programação usada em Ciência de Dados, é uma linguagem fácil de aprender e existem muitas bibliotecas excelentes disponíveis. Além de Python, a linguagem R também é muito utilizada.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Quer aprender Python? Recomendo o livro do Luciano Ramalho: Python Fluente. Quer uma palinha? Ele fez uma live: &lt;a href=&#34;https://www.youtube.com/watch?v=2TLU3d3qgCw&#34;&gt;Luciano Ramalho &amp;ndash; A Beleza de Python&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Não curte livro? O Fernando Masanori fez uma série de vídeos: &lt;a href=&#34;https://www.youtube.com/c/PythonparaZumbis/playlists&#34;&gt;python para zumbis&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Canais do youtube: &lt;a href=&#34;https://www.youtube.com/c/Dunossauro&#34;&gt;Dunossauro (Eduardo Mendes)&lt;/a&gt; e o canal &lt;a href=&#34;https://www.youtube.com/c/Programa%C3%A7%C3%A3oDin%C3%A2mica&#34;&gt;Programação dinâmica&lt;/a&gt; tem vários vídeos excelentes.&lt;/li&gt;
&lt;li&gt;Já manja de programar e quer só aprender como faço determinada tarefa em Python: &lt;a href=&#34;https://www.pythoncheatsheet.org/&#34;&gt;pythoncheatsheet.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Praticar: tem um “jogo” que são dados alguns problemas para serem resolvidos em Python: &lt;a href=&#34;https://py.checkio.org/&#34;&gt;py.checkio.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Curte minecraft? Na Raspberry Pi é possível interagir em Python com o jogo: &lt;a href=&#34;https://projects.raspberrypi.org/en/projects/getting-started-with-minecraft-pi&#34;&gt;projects.raspberrypi.org/en/projects/getting-started-with-minecraft-pi&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;jupyter-notebooks-e-como-preparar-seu-ambiente&#34;&gt;Jupyter notebooks e como preparar seu ambiente&lt;/h2&gt;
&lt;p&gt;Quando estiver programando em Python ou outras linguagens interpretadas, uma opção popular é a utilização de Jupyter Notebooks. O Jupyter Notebook é uma espécie de “caderno com células” com código ou texto, que pode ser formatado com Markdown (inclusive com formulas LaTeX). Dessa forma, é possível escrever uma vez só o código que gera os gráficos, resultados, texto para um artigo, slides, e etc. Além de que as células são executadas de forma interativa, tornando-se mais fácil de programar dessa forma.&lt;/p&gt;
&lt;h2 id=&#34;dicas-para-os-jupyter-notebooks&#34;&gt;Dicas para os Jupyter notebooks:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Para usar o jupyter é simples, crie a célula e use shift+enter para executar aquela célula.&lt;/li&gt;
&lt;li&gt;Precisa instalar um pacote? coloque um ! antes do comando que quer instalar, por exemplo: &lt;code&gt;!pip install numpy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Coloque ? antes do que você quer procurar o manual, por exemplo a função split em strings: &lt;code&gt;?str.split&lt;/code&gt;. Então, será aberto um painel com o manual dessa função.&lt;/li&gt;
&lt;li&gt;Como instalar tudo? O jeito mais simples é usar o &lt;a href=&#34;https://www.anaconda.com/&#34;&gt;anaconda.com&lt;/a&gt; que instala todo ambiente Python em sua máquina de maneira simples.&lt;/li&gt;
&lt;li&gt;Outra opção é programar direto do navegador sem precisar instalar nada: o &lt;a href=&#34;https://colab.research.google.com/&#34;&gt;colab.research.google.com&lt;/a&gt; é uma opção popular, e ainda usufrui de GPUs para treinar redes neurais rapidamente e gratuito.&lt;/li&gt;
&lt;li&gt;Pra quem curte software livre e não quer usar a plataforma do google o &lt;a href=&#34;https://cocalc.com/&#34;&gt;cocalc.com&lt;/a&gt; é uma ótima opção.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;começando-pelo-começo-séries-de-valores-no-pandas&#34;&gt;Começando pelo começo: séries de valores no pandas&lt;/h2&gt;
&lt;p&gt;Antes de tudo, vamos importar o pandas:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d75f00&#34;&gt;import&lt;/span&gt; pandas &lt;span style=&#34;color:#5f8700&#34;&gt;as&lt;/span&gt; pd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Vamos escrever uma série de valores. Podemos definir os índices da serie de valores, tornando a mais completa e fácil de entender e acessar.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gasto_semana = pd.Series([&lt;span style=&#34;color:#00afaf&#34;&gt;20&lt;/span&gt;,&lt;span style=&#34;color:#00afaf&#34;&gt;40&lt;/span&gt;,&lt;span style=&#34;color:#00afaf&#34;&gt;50&lt;/span&gt;,&lt;span style=&#34;color:#00afaf&#34;&gt;30&lt;/span&gt;,&lt;span style=&#34;color:#00afaf&#34;&gt;40&lt;/span&gt;,&lt;span style=&#34;color:#00afaf&#34;&gt;80&lt;/span&gt;,&lt;span style=&#34;color:#00afaf&#34;&gt;15&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gasto_semana.index = [“domingo”, “segunda”, “terca”, “quarta”, “quinta”, “sexta”, “sabado”]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gasto_semana
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;domingo    &lt;span style=&#34;color:#00afaf&#34;&gt;20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;segunda    &lt;span style=&#34;color:#00afaf&#34;&gt;40&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;terca      &lt;span style=&#34;color:#00afaf&#34;&gt;50&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;quarta     &lt;span style=&#34;color:#00afaf&#34;&gt;30&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;quinta     &lt;span style=&#34;color:#00afaf&#34;&gt;40&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sexta      &lt;span style=&#34;color:#00afaf&#34;&gt;80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sabado     &lt;span style=&#34;color:#00afaf&#34;&gt;15&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dtype: int64&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Para acessar os valores procedemos da mesma forma que com listas: gasto_semana[“segunda”]. Dessa forma, o valor a ser retornado será o valor da segunda-feira.&lt;/p&gt;
&lt;p&gt;Também temos a flexibilidade de realizar cálculos, por exemplo elevar ao quadrado os gastos da semana ao quadrado:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gasto_semana**&lt;span style=&#34;color:#00afaf&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;domingo     &lt;span style=&#34;color:#00afaf&#34;&gt;400&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;segunda    &lt;span style=&#34;color:#00afaf&#34;&gt;1600&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;terca      &lt;span style=&#34;color:#00afaf&#34;&gt;2500&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;quarta      &lt;span style=&#34;color:#00afaf&#34;&gt;900&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;quinta     &lt;span style=&#34;color:#00afaf&#34;&gt;1600&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sexta      &lt;span style=&#34;color:#00afaf&#34;&gt;6400&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sabado      &lt;span style=&#34;color:#00afaf&#34;&gt;225&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dtype: int64&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Uma vez que a série foi criada, podemos, por exemplo, calcular a mediana, as estatísticas descritivas (média, desvio padrão, quartis, e etc.) e contar os valores únicos da série:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gasto_semana.median()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;40.0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gasto_semana.describe(percentiles = [&lt;span style=&#34;color:#00afaf&#34;&gt;.25&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;.5&lt;/span&gt;, &lt;span style=&#34;color:#00afaf&#34;&gt;.75&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;count     &lt;span style=&#34;color:#00afaf&#34;&gt;7.000000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mean     &lt;span style=&#34;color:#00afaf&#34;&gt;39.285714&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std      &lt;span style=&#34;color:#00afaf&#34;&gt;21.684974&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;min&lt;/span&gt;      &lt;span style=&#34;color:#00afaf&#34;&gt;15.000000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;25&lt;/span&gt;%      &lt;span style=&#34;color:#00afaf&#34;&gt;25.000000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;50&lt;/span&gt;%      &lt;span style=&#34;color:#00afaf&#34;&gt;40.000000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;75&lt;/span&gt;%      &lt;span style=&#34;color:#00afaf&#34;&gt;45.000000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0087ff&#34;&gt;max&lt;/span&gt;      &lt;span style=&#34;color:#00afaf&#34;&gt;80.000000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dtype: float64&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gasto_semana.value_counts(normalize=&lt;span style=&#34;color:#d75f00&#34;&gt;False&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;40&lt;/span&gt;    &lt;span style=&#34;color:#00afaf&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;15&lt;/span&gt;    &lt;span style=&#34;color:#00afaf&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;30&lt;/span&gt;    &lt;span style=&#34;color:#00afaf&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;20&lt;/span&gt;    &lt;span style=&#34;color:#00afaf&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;80&lt;/span&gt;    &lt;span style=&#34;color:#00afaf&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00afaf&#34;&gt;50&lt;/span&gt;    &lt;span style=&#34;color:#00afaf&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dtype: int64&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Podemos procurar por valores que satisfazem uma determinada condição:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gasto_semana &amp;gt; &lt;span style=&#34;color:#00afaf&#34;&gt;30&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;domingo    &lt;span style=&#34;color:#d75f00&#34;&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;segunda     &lt;span style=&#34;color:#d75f00&#34;&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;terca       &lt;span style=&#34;color:#d75f00&#34;&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;quarta     &lt;span style=&#34;color:#d75f00&#34;&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;quinta      &lt;span style=&#34;color:#d75f00&#34;&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sexta       &lt;span style=&#34;color:#d75f00&#34;&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sabado     &lt;span style=&#34;color:#d75f00&#34;&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dtype: &lt;span style=&#34;color:#0087ff&#34;&gt;bool&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Repare que a saída é uma série com os mesmos índices da serie original e com valores True ou False para os valores que satisfazem ou não a condição.&lt;/p&gt;
&lt;p&gt;Um detalhe é que se quisermos procurar por valores que satisfazem diversas condições, temos que os usar operadores bitwise, por exemplo E (and) é representado por &amp;amp;, OU (or) por | e negação (NOT) por ~&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(gasto_semana &amp;gt; &lt;span style=&#34;color:#00afaf&#34;&gt;30&lt;/span&gt;) &amp;amp; (gasto_semana &amp;lt; &lt;span style=&#34;color:#00afaf&#34;&gt;80&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;domingo    &lt;span style=&#34;color:#d75f00&#34;&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;segunda     &lt;span style=&#34;color:#d75f00&#34;&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;terca       &lt;span style=&#34;color:#d75f00&#34;&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;quarta     &lt;span style=&#34;color:#d75f00&#34;&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;quinta      &lt;span style=&#34;color:#d75f00&#34;&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sexta      &lt;span style=&#34;color:#d75f00&#34;&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sabado     &lt;span style=&#34;color:#d75f00&#34;&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dtype: &lt;span style=&#34;color:#0087ff&#34;&gt;bool&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Por fim, se usarmos isso dentro da série original, vamos gerar uma serie com os valores que satisfazem as condições:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gasto_semana[(gasto_semana &amp;gt; &lt;span style=&#34;color:#00afaf&#34;&gt;30&lt;/span&gt;) &amp;amp; (gasto_semana &amp;lt; &lt;span style=&#34;color:#00afaf&#34;&gt;80&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;segunda    &lt;span style=&#34;color:#00afaf&#34;&gt;40&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;terca      &lt;span style=&#34;color:#00afaf&#34;&gt;50&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;quinta     &lt;span style=&#34;color:#00afaf&#34;&gt;40&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dtype: int64&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;dataframes&#34;&gt;Dataframes&lt;/h2&gt;
&lt;p&gt;Dataframe é um estrutura bidimensional de dados. Pense em dataframe como uma tabela ou matriz. No fundo, o dataframe tem algumas colunas onde cada coluna é uma série de dados e as colunas são “amarradas” pelos índices.&lt;/p&gt;
&lt;p&gt;Vamos importar um dataframe de gorjetas, onde foram anotadas diversas informações de gorjetas como sexo, se é fumante ou não, dia da semana, quantas pessoas na mesa, e etc.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d75f00&#34;&gt;import&lt;/span&gt; seaborn &lt;span style=&#34;color:#5f8700&#34;&gt;as&lt;/span&gt; sns
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tips_df = sns.load_dataset(“tips”)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tips_df.head(&lt;span style=&#34;color:#00afaf&#34;&gt;6&lt;/span&gt;) &lt;span style=&#34;color:#4e4e4e&#34;&gt;# exibe os 6 primeiros registros (use tail para ultimos)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/pandas/df1.png&#34; loading=&#34;lazy&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Uma das primeiras coisas que eu gosto de fazer assim que importo os dados é utilizar a função info para vermos se o type de cada coluna foi identificado corretamente.&lt;/p&gt;
&lt;p&gt;E também podemos ver quanto de memória é utilizada. Caso o conjunto de dados seja grande, é interessante tentar alguns “truques” como transformar alguma coluna como categórico para poupar memória 😜&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tips_df.info()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#5f8700&#34;&gt;class&lt;/span&gt; &amp;#39;&lt;span style=&#34;color:#0087ff&#34;&gt;pandas&lt;/span&gt;.core.frame.DataFrame&lt;span style=&#34;color:#00afaf&#34;&gt;&amp;#39;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RangeIndex: &lt;span style=&#34;color:#00afaf&#34;&gt;244&lt;/span&gt; entries, &lt;span style=&#34;color:#00afaf&#34;&gt;0&lt;/span&gt; to &lt;span style=&#34;color:#00afaf&#34;&gt;243&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Data columns (total &lt;span style=&#34;color:#00afaf&#34;&gt;7&lt;/span&gt; columns):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#4e4e4e&#34;&gt;#   Column      Non-Null Count  Dtype   &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---  ------      --------------  -----   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00afaf&#34;&gt;0&lt;/span&gt;   total_bill  &lt;span style=&#34;color:#00afaf&#34;&gt;244&lt;/span&gt; non-null    float64 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00afaf&#34;&gt;1&lt;/span&gt;   tip         &lt;span style=&#34;color:#00afaf&#34;&gt;244&lt;/span&gt; non-null    float64 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00afaf&#34;&gt;2&lt;/span&gt;   sex         &lt;span style=&#34;color:#00afaf&#34;&gt;244&lt;/span&gt; non-null    category
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00afaf&#34;&gt;3&lt;/span&gt;   smoker      &lt;span style=&#34;color:#00afaf&#34;&gt;244&lt;/span&gt; non-null    category
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00afaf&#34;&gt;4&lt;/span&gt;   day         &lt;span style=&#34;color:#00afaf&#34;&gt;244&lt;/span&gt; non-null    category
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00afaf&#34;&gt;5&lt;/span&gt;   time        &lt;span style=&#34;color:#00afaf&#34;&gt;244&lt;/span&gt; non-null    category
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00afaf&#34;&gt;6&lt;/span&gt;   size        &lt;span style=&#34;color:#00afaf&#34;&gt;244&lt;/span&gt; non-null    int64   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dtypes: category(&lt;span style=&#34;color:#00afaf&#34;&gt;4&lt;/span&gt;), float64(&lt;span style=&#34;color:#00afaf&#34;&gt;2&lt;/span&gt;), int64(&lt;span style=&#34;color:#00afaf&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;memory usage: &lt;span style=&#34;color:#00afaf&#34;&gt;7.3&lt;/span&gt; KB&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Se quisermos saber qual o percentual de quem paga a gorjeta e é fumante, podemos utilizar o values_count conforme descrito na célula de código abaixo. Assim, saberemos que aproximadamente 60% dos pagantes de gorjeta fumam.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tips_df[‘smoker’].value_counts(normalize=&lt;span style=&#34;color:#d75f00&#34;&gt;True&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;No     &lt;span style=&#34;color:#00afaf&#34;&gt;0.618852&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Yes    &lt;span style=&#34;color:#00afaf&#34;&gt;0.381148&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Name: smoker, dtype: float64&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Podemos criar também colunas novas. Vamos calcular o total pago (total = valor_conta + valor_tip) e a porcentagem do valor da gorjeta com o total:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tips_df[‘total_payed’] = tips_df[“total_bill”] + tips_df[“tip”]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tips_df[‘tip_percentage’] = &lt;span style=&#34;color:#00afaf&#34;&gt;100.0&lt;/span&gt;*tips_df[“tip”]/tips_df[“total_bill”]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tips_df.head()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/pandas/df2.png&#34; loading=&#34;lazy&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Qual é a distribuição de percentagem da gorjeta? E do valor total?&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/pandas/df3.png&#34; loading=&#34;lazy&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Como podemos ver, em média as gorjetas representam 15% do valor da conta, o que corresponde a ao valor médio da gorjeta de 2.9 dólares.&lt;/p&gt;
&lt;p&gt;Referente ao valor total, a média é de 20.6 dólares e mediana de 22.8 dólares.&lt;/p&gt;
&lt;p&gt;Fumantes tendem a pagar mais gorjeta? Podemos agrupar os valores pela coluna smoker e fazer um describe&lt;/p&gt;
&lt;p&gt;&lt;code&gt;tips_df.groupby([‘smoker’]).tip_percentage.describe()&lt;/code&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/pandas/df4.png&#34; loading=&#34;lazy&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Aparentemente não faz muita diferença se o cliente é fumante ou não para pagar um percentual maior de gorjeta (mediana ficou 15.4% para fumantes e 15.6% para não fumantes).&lt;/p&gt;
&lt;p&gt;E o dia da semana junto com o dia? Faz diferença? Podemos agrupar com mais de uma coluna&lt;/p&gt;
&lt;p&gt;&lt;code&gt;tips_df.groupby([‘day’, ‘time’]).tip_percentage.describe()&lt;/code&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/pandas/df5.png&#34; loading=&#34;lazy&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;E gráficos? Fazer gráficos com o pandas é muito simples:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;tips_df.plot.scatter(x=’total_bill’,y=’tip_percentage’)&lt;/code&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/pandas/sns1.png&#34; loading=&#34;lazy&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Neste gráfico queremos ver se existe uma correlação entre o valor conta e o percentual de gorjeta concedido. Vemos que pelo contrario, uma leve correlação negativa: quanto maior o valor da conta menos será pago de gorjeta, percentualmente.&lt;/p&gt;
&lt;p&gt;Outra opção é usar a biblioteca de gráficos seaborn, que além de ser fácil de usar, os gráficos ficam bem bonitos&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d75f00&#34;&gt;import&lt;/span&gt; seaborn &lt;span style=&#34;color:#5f8700&#34;&gt;as&lt;/span&gt; sns
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sns.scatterplot(data=tips_df, x=’total_bill’,y=’tip_percentage’, hue=’smoker’)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/pandas/sns2.png&#34; loading=&#34;lazy&#34;/&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;ler-e-gravar-os-dados&#34;&gt;Ler e gravar os dados&lt;/h2&gt;
&lt;p&gt;Para ler dados com pandas é super simples. Por exemplo, para ler um csv basta fazer (inclusive funciona se passar o link do csv):&lt;/p&gt;
&lt;p&gt;&lt;code&gt;df = pd.read_csv(&#39;arquivo.csv&#39;)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;É possível ler de arquivos excel com pd.read_excel, HDF5, SQL, inclusive Parquet — um formato muito usado em Big Data.
Para salvar o arquivo basta fazer df.to_csv(‘arquivo.csc’), e etc.&lt;/p&gt;
&lt;h2 id=&#34;dicas-legais&#34;&gt;Dicas legais&lt;/h2&gt;
&lt;p&gt;Raspagem web: o pandas consegue extrair tabelas de páginas web. Para isso, basta usar a função &lt;code&gt;pd.read_html(&amp;lt;link_da_pagina&amp;gt;)&lt;/code&gt;, assim como mágica o pandas lê a tabela como um dataframe.&lt;/p&gt;
&lt;p&gt;Pivot tables: se você está acostumado a fazer pivot tables como no excel, o pandas faz facilmente através da função &lt;code&gt;pd.pivot_table&lt;/code&gt;, conforme o exemplo abaixo:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pd.pivot_table(tips_df, index=’size’, columns=’smoker’, values=’tip_percentage’, aggfunc=’median’)&lt;/code&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/pandas/df6.png&#34; loading=&#34;lazy&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Fizemos uma pivot table onde as linhas são quantas pessoas tem à mesa, as colunas significam se o cliente é fumante ou não, e os valores são a porcentagem da gorjeta agregada com mediana.&lt;/p&gt;
&lt;h2 id=&#34;conclusão&#34;&gt;Conclusão&lt;/h2&gt;
&lt;p&gt;Como vimos, o pandas é uma biblioteca muito fácil de usar e que faz mágica. Para aprender mais, existe o &lt;a href=&#34;https://pandas.pydata.org/pandas-docs/stable/user_guide/index.html&#34;&gt;guia de usuário&lt;/a&gt; com o passo-a-passo e a &lt;a href=&#34;https://pandas.pydata.org/pandas-docs/stable/reference/index.html&#34;&gt;documentação oficial&lt;/a&gt;. Outra referência legal e rapidinha são as dicas do Kevin Markham, ele montou uma lista com 100 dicas ótimas para usar pandas: &lt;a href=&#34;https://www.dataschool.io/python-pandas-tips-and-tricks/&#34;&gt;dataschool.io/python-pandas-tips-and-tricks/&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Projeto novo: Divulgação cientifica no medium</title>
      <link>https://caioau.net/blog/computando-arte/</link><category>divulgacao-cientifica</category>
		  <category>medium</category>
		  <category>estatistica</category>
		  <category>computacao</category>
		  <category>matematica</category>
		  <category>ciencia-de-dados</category>
		  <category>computando-arte</category>
		  <category>rss</category>
		  
      <pubDate>Mon, 23 Nov 2020 14:00:00 -0300</pubDate>
      
      <guid>https://caioau.net/blog/computando-arte/</guid><description>&lt;h2 id=&#34;edits&#34;&gt;Edits&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;21Abr2021: Agora também estamos no &lt;a href=&#34;https://dev.to/&#34;&gt;dev.to&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;Juntei com uns amigos e formamos um grupo de divulgação cientifica de estatística, matemática, ciência de dados e computação no medium.&lt;/p&gt;
&lt;p&gt;A ideia é publicar um texto por semana.&lt;/p&gt;
&lt;p&gt;Confira aqui: &lt;a href=&#34;https://medium.com/computando-arte&#34;&gt;medium.com/computando-arte&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;e no dev.to: &lt;a href=&#34;https://dev.to/computandoarte&#34;&gt;dev.to/computandoarte&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Assine o feed RSS: &lt;a href=&#34;https://medium.com/feed/computando-arte&#34;&gt;medium.com/feed/computando-arte&lt;/a&gt; e &lt;a href=&#34;https://dev.to/feed/computandoarte&#34;&gt;dev.to/feed/computandoarte&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Mandem sugestões, dicas e feedback :)&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
