<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Devops on Crimideias do caioau</title>
    <link>https://caioau.net/tags/devops/</link>
    <description>Recent content in Devops 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>Sat, 16 May 2026 01:00:00 +1100</lastBuildDate><atom:link href="https://caioau.net/tags/devops/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Slides: Dockerfile: Hardening e boas práticas (Sorocoded 2a edição)</title>
      <link>https://caioau.net/blog/dockerfile-hardening-sorocoded2026/</link><category>sorocode</category>
		  <category>slides</category>
		  <category>devops</category>
		  <category>docker</category>
		  <category>security</category>
		  <category>sbom</category>
		  <category>chainguard</category>
		  
      <pubDate>Sat, 16 May 2026 01:00:00 +1100</pubDate>
      
      <guid>https://caioau.net/blog/dockerfile-hardening-sorocoded2026/</guid><description>&lt;p&gt;Atividade realizada dia 16 maio 2026, na segunda edição do &lt;a href=&#34;https://www.linkedin.com/company/sorocode/&#34;&gt;sorocoded&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;slides-dockerfile-hardening-sorocoded_16may26_beamer.pdf&#34;&gt;slides&lt;/a&gt; (&lt;a href=&#34;https://gitlab.com/caioau/caioau.gitlab.io/-/tree/master/static/blog/dockerfile-hardening-sorocoded2026&#34;&gt;arquivo markdown editável e outros artefatos usados&lt;/a&gt; feito com pandoc com beamer (latex), excelente template: &lt;a href=&#34;https://codeberg.org/alexeygumirov/pandoc-beamer-how-to&#34;&gt;alexeygumirov/pandoc-beamer-how-to&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Slides: Dockerfile: Hardening e boas práticas (CoffeOps)</title>
      <link>https://caioau.net/blog/dockerfile-hardening-coffeops2026/</link><category>lhc</category>
		  <category>slides</category>
		  <category>devops</category>
		  <category>docker</category>
		  <category>security</category>
		  <category>sbom</category>
		  <category>chainguard</category>
		  
      <pubDate>Sat, 18 Apr 2026 01:00:00 +1100</pubDate>
      
      <guid>https://caioau.net/blog/dockerfile-hardening-coffeops2026/</guid><description>&lt;p&gt;Atividade realizada dia 18 abril 2026, no &lt;a href=&#34;https://coffeeopscampinassp.github.io/&#34;&gt;CoffeeOps Campinas SP&lt;/a&gt; no &lt;a href=&#34;https://lhc.net.br/&#34;&gt;Laboratório Hacker de Campinas – LHC&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;slides-dockerfile-hardening-coffeops_18abr26.pdf&#34;&gt;slides&lt;/a&gt; (&lt;a href=&#34;https://gitlab.com/caioau/caioau.gitlab.io/-/tree/master/static/blog/dockerfile-hardening-coffeops2026&#34;&gt;arquivo markdown editável e outros artefatos usados&lt;/a&gt; feito com &lt;a href=&#34;https://marp.app/&#34;&gt;Marp&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <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>Slides: Navegando logs usando lnav (CoffeOps)</title>
      <link>https://caioau.net/blog/lnav-coffeops2025/</link><category>lhc</category>
		  <category>slides</category>
		  <category>devops</category>
		  <category>monitoramento</category>
		  <category>lnav</category>
		  
      <pubDate>Sat, 20 Dec 2025 01:00:00 +1100</pubDate>
      
      <guid>https://caioau.net/blog/lnav-coffeops2025/</guid><description>&lt;p&gt;Atividade realizada dia 20 dezembro 2025, no &lt;a href=&#34;https://coffeeopscampinassp.github.io/&#34;&gt;CoffeeOps Campinas SP&lt;/a&gt; no &lt;a href=&#34;https://lhc.net.br/&#34;&gt;Laboratório Hacker de Campinas – LHC&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;slides-lav-coffeops_20dec2025.pdf&#34;&gt;slides&lt;/a&gt; (&lt;a href=&#34;https://gitlab.com/caioau/caioau.gitlab.io/-/tree/master/static/blog/lnav-coffeops2025&#34;&gt;arquivo markdown editável e outros artefatos usados&lt;/a&gt; feito com &lt;a href=&#34;https://marp.app/&#34;&gt;Marp&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Slides: Primeiros passos com self-hosting (cryptorave 2024)</title>
      <link>https://caioau.net/blog/cr2024-intro-selfhosting/</link><category>cryptorave</category>
		  <category>slides</category>
		  <category>devops</category>
		  <category>raspberry-pi</category>
		  <category>selfhost</category>
		  <category>linux</category>
		  <category>docker</category>
		  <category>ansible</category>
		  <category>security</category>
		  <category>monitoramento</category>
		  
      <pubDate>Tue, 07 May 2024 08:00:00 -0300</pubDate>
      
      <guid>https://caioau.net/blog/cr2024-intro-selfhosting/</guid><description>&lt;p&gt;Atividade realizada dia 11 maio 2024, na &lt;a href=&#34;https://2024.cryptorave.org/&#34;&gt;cryptorave&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Palestra baseada no texto &lt;a href=&#34;https://caioau.net/blog/selfhosting/&#34;&gt;Primeiros passos com self-hosting&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;slides-intro-selfhosting_11maio2024.pdf&#34;&gt;slides&lt;/a&gt; (&lt;a href=&#34;https://gitlab.com/caioau/caioau.gitlab.io/-/tree/master/static/blog/cr2024-intro-selfhosting&#34;&gt;arquivo markdown editável&lt;/a&gt; feito com &lt;a href=&#34;https://marp.app/&#34;&gt;Marp&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Slides: Primeiros passos com self-hosting (cryptorave 2023)</title>
      <link>https://caioau.net/blog/cr2023-intro-selfhosting/</link><category>cryptorave</category>
		  <category>slides</category>
		  <category>devops</category>
		  <category>raspberry-pi</category>
		  <category>selfhost</category>
		  <category>linux</category>
		  <category>docker</category>
		  <category>ansible</category>
		  <category>security</category>
		  <category>monitoramento</category>
		  
      <pubDate>Thu, 04 May 2023 08:00:00 -0300</pubDate>
      
      <guid>https://caioau.net/blog/cr2023-intro-selfhosting/</guid><description>&lt;p&gt;Atividade realizada dia 5 maio 2023, na &lt;a href=&#34;https://2023.cryptorave.org/&#34;&gt;cryptorave&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Palestra baseada no texto &lt;a href=&#34;https://caioau.net/blog/selfhosting/&#34;&gt;Primeiros passos com self-hosting&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;slides-intro-selfhosting_05maio2023.pdf&#34;&gt;slides&lt;/a&gt; (&lt;a href=&#34;https://gitlab.com/caioau/caioau.gitlab.io/-/tree/master/static/blog/cr2023-intro-selfhosting&#34;&gt;arquivo markdown editável&lt;/a&gt; feito com &lt;a href=&#34;https://marp.app/&#34;&gt;Marp&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Slides: Primeiros passos com self-hosting (TOSCONF[3])</title>
      <link>https://caioau.net/blog/tosconf2023-intro-selfhosting/</link><category>lhc</category>
		  <category>slides</category>
		  <category>devops</category>
		  <category>raspberry-pi</category>
		  <category>selfhost</category>
		  <category>linux</category>
		  <category>docker</category>
		  <category>ansible</category>
		  <category>security</category>
		  <category>monitoramento</category>
		  
      <pubDate>Fri, 17 Mar 2023 08:00:00 -0300</pubDate>
      
      <guid>https://caioau.net/blog/tosconf2023-intro-selfhosting/</guid><description>&lt;p&gt;Atividade realizada dia 18 março 2023, na &lt;a href=&#34;https://tosconf.lhc.net.br/&#34;&gt;TOSCONF[3]&lt;/a&gt; no &lt;a href=&#34;https://lhc.net.br/&#34;&gt;Laboratório Hacker de Campinas – LHC&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Palestra baseada no texto &lt;a href=&#34;https://caioau.net/blog/selfhosting/&#34;&gt;Primeiros passos com self-hosting&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;slides-intro-selfhosting_18mar2023.pdf&#34;&gt;slides&lt;/a&gt; (&lt;a href=&#34;https://gitlab.com/caioau/caioau.gitlab.io/-/tree/master/static/blog/tosconf2023-intro-selfhosting&#34;&gt;arquivo markdown editável&lt;/a&gt; feito com &lt;a href=&#34;https://marp.app/&#34;&gt;Marp&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Slides: Testando playbooks com molecule</title>
      <link>https://caioau.net/blog/eldorado-ansible-molecule/</link><category>eldorado</category>
		  <category>slides</category>
		  <category>devops</category>
		  <category>linux</category>
		  <category>ansible</category>
		  
      <pubDate>Mon, 03 Oct 2022 16:00:00 -0300</pubDate>
      
      <guid>https://caioau.net/blog/eldorado-ansible-molecule/</guid><description>&lt;p&gt;Atividade realizada dia 28 setembro 2022, no &lt;a href=&#34;https://www.eldorado.org.br/&#34;&gt;Eldorado&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;slides-ansible-parte2.pdf&#34;&gt;slides&lt;/a&gt; (&lt;a href=&#34;https://gitlab.com/caioau/caioau.gitlab.io/-/tree/master/static/blog/eldorado-ansible-molecule&#34;&gt;arquivo markdown editável&lt;/a&gt; feito com &lt;a href=&#34;https://marp.app/&#34;&gt;Marp&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Slides: Primeiros passos com o Ansible</title>
      <link>https://caioau.net/blog/eldorado-intro-ansible/</link><category>eldorado</category>
		  <category>slides</category>
		  <category>devops</category>
		  <category>linux</category>
		  <category>ansible</category>
		  
      <pubDate>Thu, 04 Aug 2022 16:00:00 -0300</pubDate>
      
      <guid>https://caioau.net/blog/eldorado-intro-ansible/</guid><description>&lt;p&gt;Atividade realizada dia 3 agosto 2022, no &lt;a href=&#34;https://www.eldorado.org.br/&#34;&gt;Eldorado&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;slides-ansible-eldorado.pdf&#34;&gt;slides&lt;/a&gt; (&lt;a href=&#34;https://gitlab.com/caioau/caioau.gitlab.io/-/tree/master/static/blog/eldorado-intro-ansible&#34;&gt;arquivo markdown editável&lt;/a&gt; feito com &lt;a href=&#34;https://marp.app/&#34;&gt;Marp&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&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 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>Slides: Como contêineres funcionam? parte 1</title>
      <link>https://caioau.net/blog/eldorado-intro-containers/</link><category>eldorado</category>
		  <category>slides</category>
		  <category>devops</category>
		  <category>linux</category>
		  <category>docker</category>
		  <category>security</category>
		  
      <pubDate>Wed, 05 Jan 2022 16:00:00 -0300</pubDate>
      
      <guid>https://caioau.net/blog/eldorado-intro-containers/</guid><description>&lt;p&gt;Atividade realizada dia 5 janeiro 2022, no &lt;a href=&#34;https://www.eldorado.org.br/&#34;&gt;Eldorado&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;slides-containers_caioau_05jan2022.pdf&#34;&gt;slides&lt;/a&gt; (&lt;a href=&#34;https://gitlab.com/caioau/caioau.gitlab.io/-/tree/master/static/blog/eldorado-intro-containers&#34;&gt;arquivo markdown editável&lt;/a&gt; feito com &lt;a href=&#34;https://marp.app/&#34;&gt;Marp&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Slides: Como operar uma infra on premisses</title>
      <link>https://caioau.net/blog/eldorado-intro-infra/</link><category>eldorado</category>
		  <category>slides</category>
		  <category>devops</category>
		  <category>raspberry-pi</category>
		  <category>selfhost</category>
		  <category>linux</category>
		  <category>docker</category>
		  <category>ansible</category>
		  <category>security</category>
		  <category>monitoramento</category>
		  
      <pubDate>Wed, 15 Dec 2021 08:00:00 -0300</pubDate>
      
      <guid>https://caioau.net/blog/eldorado-intro-infra/</guid><description>&lt;p&gt;Atividade realizada dia 15 dezembro 2021, no &lt;a href=&#34;https://www.eldorado.org.br/&#34;&gt;Eldorado&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Palestra baseada no texto &lt;a href=&#34;https://caioau.net/blog/selfhosting/&#34;&gt;Primeiros passos com self-hosting&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;slides-intro-infra_caioau_15dez2021.pdf&#34;&gt;slides&lt;/a&gt; (&lt;a href=&#34;https://gitlab.com/caioau/caioau.gitlab.io/-/tree/master/static/blog/eldorado-intro-infra&#34;&gt;arquivo markdown editável&lt;/a&gt; feito com &lt;a href=&#34;https://marp.app/&#34;&gt;Marp&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Termux: Um terminal linux no seu Android</title>
      <link>https://caioau.net/blog/termux/</link><category>devops</category>
		  <category>portal-embarcados</category>
		  <category>texto</category>
		  <category>android</category>
		  <category>fdroid</category>
		  <category>linux</category>
		  <category>python</category>
		  
      <pubDate>Fri, 10 Sep 2021 14:00:00 -0300</pubDate>
      
      <guid>https://caioau.net/blog/termux/</guid><description>&lt;p&gt;Originalmente publicado no &lt;a href=&#34;https://www.embarcados.com.br/termux-um-terminal-linux-no-seu-android/&#34;&gt;portal embarcados&lt;/a&gt; dia 8 setembro de 2021, com apoio dos colegas do instituto Eldorado.&lt;/p&gt;
&lt;p&gt;Hoje vamos falar do &lt;strong&gt;termux&lt;/strong&gt;: um app open source para android que traz um terminal completo Linux com diversas possibilidades e facilidades, como fazer backups dos arquivos do Android e programar com python 🤓&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/termux/termux.png&#34; loading=&#34;lazy&#34; width=&#34;400px&#34;/&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;instalando-o-app-o-que-é-a-fdroid&#34;&gt;Instalando o app: O que é a Fdroid?&lt;/h2&gt;
&lt;p&gt;O &lt;strong&gt;termux&lt;/strong&gt; atualmente está apenas disponível na Fdroid, não é possível instalar a versão mais recente na play store. Mas afinal o que é a Fdroid?&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/termux/fdroid.png&#34; loading=&#34;lazy&#34;
         alt=&#34;Logo da Fdroid&#34; width=&#34;200px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Logo da Fdroid&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;A Fdroid é uma loja de apps para Android, tipo a Play Store, mas apenas com apps software livre/open source. Atualmente existem mais de 3 mil apps oferecidos lá, dê uma olhada se tem algum que te interesse.&lt;/p&gt;
&lt;p&gt;Para usar a Fdroid basta ir no site &lt;a href=&#34;http://fdroid.org/&#34;&gt;fdroid.org&lt;/a&gt; clique em download e instale o apk.&lt;/p&gt;
&lt;p&gt;Com a Fdroid instalada, busque pelo &lt;strong&gt;termux&lt;/strong&gt; e instale-o de lá, a Fdroid periodicamente vai procurar por atualizações dos seus apps.&lt;/p&gt;
&lt;h2 id=&#34;instalei-o-termux-e-agora&#34;&gt;Instalei o Termux, e agora?&lt;/h2&gt;
&lt;p&gt;Com o &lt;strong&gt;termux&lt;/strong&gt; instalado, podemos instalar alguns pacotes. Para fazer isso basta usar o comando pkg igual faria com apt ou apt-get (não precisa de sudo).&lt;/p&gt;
&lt;p&gt;Então antes de tudo vamos atualizar os repos, para isto execute a  seguinte linha de comando: &lt;code&gt;pkg update&lt;/code&gt; .&lt;/p&gt;
&lt;p&gt;Espere terminar e aceite atualizar os pacotes.&lt;/p&gt;
&lt;p&gt;Agora vamos instalar o neofetch usando a linha de comando: &lt;code&gt;pkg install neofetch&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Por fim rode o &lt;strong&gt;neofetch&lt;/strong&gt;, ele exibirá o logo do Android (que no caso é a nossa “distro” Linux) e diversas informações como número de pacotes instalados, qual kernel, etc.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/termux/meme.png&#34; loading=&#34;lazy&#34;
         alt=&#34;Créditos: @anubhavitis&#34; width=&#34;500px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Créditos: &lt;a href=&#34;https://twitter.com/anubhavitis/status/1411935066406625287/photo/1&#34;&gt;@anubhavitis&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;acessando-remotamente-o-celular-com-ssh&#34;&gt;Acessando remotamente o celular com ssh&lt;/h2&gt;
&lt;p&gt;Como o teclado e a tela do celular são pequenos, uma possibilidade seria usar um teclado externo bluetooth ou conectado no cabo OTG. Outra abordagem possível é acessar remotamente o &lt;strong&gt;termux&lt;/strong&gt; via ssh com um computador na mesma rede. Para isto:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Instale o &lt;strong&gt;openssh&lt;/strong&gt;: &lt;code&gt;pkg install openssh&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Crie uma senha para logar com o comando: &lt;code&gt;passwd&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;Digite a senha 2 vezes (é normal não aparecer nada enquanto digita a senha).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Inicie o servidor ssh com o comando: &lt;code&gt;sshd&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Descubra o IP do android: na cortina de notificações pressione e segure o ícone do WiFi, clique na rede conectada, avançado, e o seu endereço IP será apresentado no formato 999.999.9.9999&lt;/li&gt;
&lt;li&gt;Agora no computador dispare o ssh no IP, porém na porta 8022 usando o comando: &lt;code&gt;ssh &amp;lt;user&amp;gt;@&amp;lt;endereco_IP&amp;gt; -p 8022&lt;/code&gt; . E digite a senha que configurou antes, para quem está no Windows uma possibilidade é instalar o &lt;strong&gt;&lt;a href=&#34;https://docs.microsoft.com/pt-br/windows/wsl/install-win10&#34;&gt;WSL&lt;/a&gt;&lt;/strong&gt; e ter um linux dentro do Windows ou usar o &lt;strong&gt;&lt;a href=&#34;https://mobaxterm.mobatek.net/&#34;&gt;MobaXterm&lt;/a&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Prontinho! Agora é possível acessar remotamente o &lt;strong&gt;termux&lt;/strong&gt; no computador via ssh. Porém logo vai perceber que o terminal começa a ficar lento, ou congela e as vezes volta. Isso acontece porque o Android está com a tela apagada e entrando num modo de “economia de energia”, nesses casos temos a opção do &lt;strong&gt;termux&lt;/strong&gt; usar wakelocks para prevenir que o Android suspenda, isso vai consumir mais bateria mas se tudo bem basta abaixar a cortina de notificação e clicar em acquire wakelock.&lt;/p&gt;
&lt;p&gt;Dica 1: O seu roteador WiFi provavelmente atribui os endereços dos dispositivos de forma sequencial, ou seja, pode ser que o IP do Android amanhã não seja mais aquele que vimos anteriormente. Vá na configuração do seu roteador e reserve um IP fixo para o Android. Segue abaixo a opção em um roteador D-Link:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/termux/router.png&#34; loading=&#34;lazy&#34; width=&#34;300px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Dica 2: Criando um alias no ssh: toda vez que vamos acessar o android temos que digitar tudo isso: &lt;code&gt;ssh &amp;lt;user&amp;gt;@&amp;lt;endereco_IP&amp;gt; -p 8022&lt;/code&gt;, vamos criar um apelido que simplifica o comando para: &lt;code&gt;ssh android&lt;/code&gt; . No computador edite o arquivo &lt;code&gt;~/.ssh/config&lt;/code&gt; colocando 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;Host android
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  HostName &amp;lt;endereco_IP&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  User user
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Compression yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Port &lt;span style=&#34;color:#00afaf&#34;&gt;8022&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;instalando-o-python-e-jupyter-notebook-&#34;&gt;Instalando o python e jupyter notebook 🤯&lt;/h2&gt;
&lt;p&gt;Podemos instalar no nosso android um ambiente de computação científica python para fazer análises, testar coisas e levar pra onde quisermos. Para isto, basta executar as seguintes linhas de comando no &lt;strong&gt;termux&lt;/strong&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;span style=&#34;white-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;/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;pkg install python build-essential libzmq freetype libjpeg-turbo libpng
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;python3 -m venv venv
&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;source&lt;/span&gt; venv/bin/activate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pip3 install -U pip wheel setuptools
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pip3 install jupyter&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;Estas linhas de comando instalam o python e algumas dependências necessárias para instalar as bibliotecas do python. Em seguida, foi criado um “ambiente virtual” (&lt;strong&gt;venv&lt;/strong&gt;) que permite instalar nossas bibliotecas de forma separada, para ter um ambiente python separado para cada projeto. Toda vez que quisermos usar o &lt;strong&gt;venv&lt;/strong&gt; é necessário executar &lt;code&gt;source venv/bin/activate&lt;/code&gt;, responsável por ativar o &lt;strong&gt;venv&lt;/strong&gt; no shell atual do &lt;strong&gt;termux&lt;/strong&gt;(linha 3). Nas linhas seguintes, 4 e 5, atualizamos nossas ferramentas do python (pip, wheel e setuptools) e por fim, instalamos o jupyter notebook.&lt;/p&gt;
&lt;p&gt;jupyter notebook é iniciado com:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;jupyter notebook --ip=0.0.0.0&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Coloque o link no navegador e substitua pelo IP do android e pronto, tudo funcionando:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/termux/jupyter_notebook.png&#34; loading=&#34;lazy&#34; width=&#34;600px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Sucesso! O jupyter notebook já está funcionando perfeitamente. É esperado que a instalação de pacotes python, como o numpy (usando o comando &lt;code&gt;pip install&lt;/code&gt;) demore mais do que em uma máquina Linux convencional. Por que? O python distribui suas bibliotecas com os wheels que são pacotes pré-compilados mais rápidos de serem instalados, porém os wheels foram gerados para a arquitetura de processadores x86_64 e estamos usando um processador arm no nosso android então temos que compilar tudo. Outra coisa é que além da arquitetura os wheels são gerados para uma determinada biblioteca padrão a &lt;strong&gt;glibc&lt;/strong&gt; mas o android usa outra libc, a &lt;strong&gt;bionic&lt;/strong&gt;. Na wiki do &lt;strong&gt;termux&lt;/strong&gt; tem uma pagina com todas as diferenças de uma maquina linux convencional: &lt;a href=&#34;https://wiki.termux.com/wiki/Differences_from_Linux&#34;&gt;https://wiki.termux.com/wiki/Differences_from_Linux&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;acessando-os-arquivos-do-celular&#34;&gt;Acessando os arquivos do celular&lt;/h2&gt;
&lt;p&gt;Podemos acessar as fotos e outros arquivos do celular pelo &lt;strong&gt;termux&lt;/strong&gt; executando o comando: &lt;code&gt;termux-setup-storage.&lt;/code&gt; É necessário  permitir o acesso de arquivos pelo app. Podemos ver quais pastas estão consumindo mais espaç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-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /sdcard
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;du -shxc * | sort -rh
&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.0&lt;/span&gt;G	total
&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.0&lt;/span&gt;G	DCIM
&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;828&lt;/span&gt;M	Android
&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;704&lt;/span&gt;M	Pictures
&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;231&lt;/span&gt;M	Telegram
&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;213&lt;/span&gt;M	syncthing
&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;103&lt;/span&gt;M	Download
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;O comando acima (&lt;code&gt;du&lt;/code&gt;) lista o espaço utilizado por cada pasta e em seguida pegamos sua saída para o comando &lt;code&gt;sort&lt;/code&gt; através do&lt;code&gt; |&lt;/code&gt; (chamado de pipe), para ordenar de forma decrescente. Outro comando interessante é o &lt;code&gt;df&lt;/code&gt; que exibe o uso de disco de cada “partição” e quanto está livre.&lt;/p&gt;
&lt;p&gt;Outra coisa legal de fazer agora que estamos acessando os arquivos do celular é deletar fotos (ou arquivos) de forma segura. Quando deletamos um arquivo, este não é removido de fato, simplesmente o espaço daquele arquivo é marcado como livre, dessa forma é possível recuperar arquivos deletados. Então para deletar um arquivo de forma segura temos que sobrescrever o conteúdo do arquivo com “lixo” para que o conteúdo original não seja recuperado, para fazer isso temos o comando &lt;code&gt;shred&lt;/code&gt;, basta executar: &lt;code&gt;shred -u &amp;lt;nome_arquivo&amp;gt;&lt;/code&gt;, como por exemplo:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;shred -uv IMG_20210416_103105401.jpg&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Outro comando, mais completo que o &lt;code&gt;shred&lt;/code&gt; é o &lt;code&gt;srm&lt;/code&gt;. Para instalar execute &lt;code&gt;pkg install secure-delete.&lt;/code&gt; Ele permite deletar diretórios de forma recursiva e outras opções não presentes no &lt;code&gt;shred&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;sincronizando-arquivos-com-o-pc&#34;&gt;Sincronizando arquivos com o PC&lt;/h2&gt;
&lt;p&gt;O protocolo ssh além de permitir acessar remotamente o Android, permite transferir arquivos. O comando que faz essa cópia é o scp, para copiar um arquivo basta executar no terminal do PC: &lt;code&gt;scp arquivo.jpg user@&amp;lt;endereco_IP&amp;gt;:/sdcard/DCIM/&lt;/code&gt;, com o usuário, IP e caminho de destino.&lt;/p&gt;
&lt;p&gt;Outro comando muito usado para essa tarefa é o &lt;code&gt;rsync&lt;/code&gt;, ele permite sincronizar pastas entre o Android e o PC. Enquanto o comando scp vai “re copiar” todas as fotos para o PC, o rsync vai copiar apenas as novas e o que mudou, sendo na maioria das vezes mais eficiente. Primeiro vamos instalar o rsync no termux (o rsync precisa estar instalado tanto no PC quanto no android):&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pkg install rsync&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;O &lt;strong&gt;rsync&lt;/strong&gt; oferece várias opções, mas nesse caso o importante é: &lt;code&gt;rsync -avh -P user@&amp;lt;endereco_IP&amp;gt;:/sdcard/DCIM/ fotos_celular/.&lt;/code&gt; Na primeira vez que for executado, esse comando vai copiar todas e fotos para o PC, e das próximas vezes copiará somente o que mudou.&lt;/p&gt;
&lt;p&gt;Por fim vou indicar um app ótimo para sincronizar os arquivos entre o celular e pc: o &lt;a href=&#34;https://syncthing.net/&#34;&gt;syncthing.net&lt;/a&gt;, tem na Fdroid e com ele é possível fazer backup de todos meus arquivos do Android no PC.&lt;/p&gt;
&lt;h2 id=&#34;alguns-apps-para-terminal&#34;&gt;Alguns apps para terminal&lt;/h2&gt;
&lt;p&gt;Para quem vive no terminal tem alguns apps que ajudam a realizar algumas tarefas e para quem não usa muito a interface gráfica.&lt;/p&gt;
&lt;p&gt;Analisador de espaço: o &lt;strong&gt;ncdu.&lt;/strong&gt; Da mesma forma que usamos o &lt;strong&gt;du&lt;/strong&gt; para ver quais pastas estão usando mais espaço, o &lt;strong&gt;ncdu&lt;/strong&gt; faz a mesma coisa, mas permite navegar de forma rápida e deletar os arquivos/pastas para liberar espaço.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/termux/ncdu.png&#34; loading=&#34;lazy&#34; width=&#34;600px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Para navegar nas pastas temos o &lt;strong&gt;ranger&lt;/strong&gt;: um gerenciador de arquivos como o explorer do Windows ou &lt;strong&gt;nautilus&lt;/strong&gt; no Linux (gnome).&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/termux/ranger.png&#34; loading=&#34;lazy&#34; width=&#34;600px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Por fim, um agregador de feeds RSS: o &lt;strong&gt;newsboat&lt;/strong&gt;, o qual permite acompanhar os feeds RSS:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://caioau.net/blog/termux/newsboat.png&#34; loading=&#34;lazy&#34; width=&#34;700px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Feed do &lt;a href=&#34;https://medium.com/computando-arte&#34;&gt;Computando Arte – Medium&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;considerações-finais&#34;&gt;Considerações finais&lt;/h2&gt;
&lt;p&gt;Neste texto tentei mostrar para nosso leitor sobre o que dá para fazer com &lt;strong&gt;termux&lt;/strong&gt; e um terminal linux, ilustrando sobre como realizar as tarefas apenas no terminal. Para quem gostou do conceito de acessar remotamente os apps e arquivos, mas achou android um pouco lento, confira esse blogspot da linuxserver.io sobre a imagem webtop que fizeram: &lt;a href=&#34;https://www.linuxserver.io/blog/2021-05-05-meet-webtops-a-linux-desktop-environment-in-your-browser&#34;&gt;linuxserver.io/blog/2021-05-05-meet-webtops-a-linux-desktop-environment-in-your-browser&lt;/a&gt; fornecendo uma alternativa mais rápida.&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>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>Slides: Treinamento de DevOps</title>
      <link>https://caioau.net/blog/eldorado-devops-training/</link><category>eldorado</category>
		  <category>slides</category>
		  <category>linux</category>
		  <category>devops</category>
		  <category>systemd</category>
		  <category>security</category>
		  <category>monitoramento</category>
		  <category>docker</category>
		  <category>ansible</category>
		  <category>english</category>
		  
      <pubDate>Sun, 25 Oct 2020 16:00:00 -0300</pubDate>
      
      <guid>https://caioau.net/blog/eldorado-devops-training/</guid><description>&lt;p&gt;Atividade realizada nos dias 5 até 9 outubro 2020, no &lt;a href=&#34;https://www.eldorado.org.br/&#34;&gt;Eldorado&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nesse treinamento de 5h, apresentei diversos conceitos e ferramentas de DevOps: como manejar serviços systemd, rede e firewall, como criar seu pacote Debian para deploy mais eficiente, security, monitoramento, backups, docker e ansible.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;devops_eldorado_5oct2020.pdf&#34;&gt;slides&lt;/a&gt; (&lt;a href=&#34;devops_eldorado_5oct2020.odp&#34;&gt;arquivo odp editável&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;devops_eldorado_5oct2020.zip&#34;&gt;arquivos extras usados na talk&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Slides: An intro to setting up Linux servers and maintaining it</title>
      <link>https://caioau.net/blog/eldorado-linux/</link><category>eldorado</category>
		  <category>slides</category>
		  <category>linux</category>
		  <category>devops</category>
		  <category>english</category>
		  
      <pubDate>Thu, 11 Jun 2020 14:00:00 -0300</pubDate>
      
      <guid>https://caioau.net/blog/eldorado-linux/</guid><description>&lt;p&gt;Atividade realizada dia 11 junho 2020, no &lt;a href=&#34;https://www.eldorado.org.br/&#34;&gt;Eldorado&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nessa apresentação interna, mostrei o que considero mais importante saber para fazer o trabalho que venho fazendo de DevOps.&lt;/p&gt;
&lt;p&gt;(Obs: Em alguns slides tinham alguns detalhes sensíveis da infra da empresa, nessa versão publicada essas partes foram censuradas, mas isso não prejudica o entendimento do conteúdo)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;linux_eldorado_11jun2020.pdf&#34;&gt;slides&lt;/a&gt; (&lt;a href=&#34;linux_eldorado_11jun2020.odp&#34;&gt;arquivo odp editável&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
  </channel>
</rss>
