<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Infrastructure on kenji.blog</title><link>http://kenji.blog/pt/categories/infrastructure/</link><description>Recent content in Infrastructure on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>pt</language><copyright>kenjinote</copyright><lastBuildDate>Sun, 13 Sep 2026 07:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/pt/categories/infrastructure/index.xml" rel="self" type="application/rss+xml"/><item><title>Hyper-V vs WSL2: Comparação de tecnologias de virtualização no Windows</title><link>http://kenji.blog/pt/p/hyper-v-vs-wsl2-windows-virtualization/</link><pubDate>Sun, 13 Sep 2026 07:00:00 +0900</pubDate><guid>http://kenji.blog/pt/p/hyper-v-vs-wsl2-windows-virtualization/</guid><description>&lt;img src="http://kenji.blog/p/hyper-v-vs-wsl2-windows-virtualization/img/eyecatch.jpg" alt="Featured image of post Hyper-V vs WSL2: Comparação de tecnologias de virtualização no Windows" />&lt;h2 id="1-introdução-a-evolução-da-virtualização-no-windows">1. Introdução: A evolução da virtualização no Windows
&lt;/h2>&lt;p>A tecnologia de virtualização na plataforma Windows passou por uma evolução dramática nas últimas décadas. No passado, hipervisores Type 2 de terceiros (como VMware Workstation e VirtualBox) eram a norma, mas desde que a Microsoft introduziu o &amp;ldquo;Hyper-V&amp;rdquo; no Windows Server 2008, hipervisores Type 1 também foram incorporados em SOs desktop como o Windows 10/11.&lt;/p>
&lt;p>E nos últimos anos, o que mais tem chamado a atenção dos desenvolvedores é o &amp;ldquo;WSL2 (Windows Subsystem for Linux 2)&amp;rdquo;. Enquanto o WSL1 dependia da conversão de chamadas de sistema (tradução), o WSL2 adota uma &amp;ldquo;Lightweight Utility VM&amp;rdquo; (Máquina Virtual Utilitária Leve) que aplica a tecnologia do Hyper-V, alcançando total compatibilidade com o Linux e uma melhoria dramática de desempenho.&lt;/p>
&lt;p>Neste artigo, vamos comparar e explicar minuciosamente essas duas poderosas tecnologias de virtualização — o &amp;ldquo;Hyper-V&amp;rdquo; completo e o &amp;ldquo;WSL2&amp;rdquo; focado na experiência do desenvolvedor — abordando suas arquiteturas, desempenho (CPU, memória, E/S de disco), configuração de rede e os melhores casos de uso, juntamente com profundos detalhes técnicos.&lt;/p>
&lt;hr>
&lt;h2 id="2-teoria-básica-dos-hipervisores-e-comparação-de-arquiteturas">2. Teoria básica dos hipervisores e comparação de arquiteturas
&lt;/h2>&lt;p>Ao entender a tecnologia de virtualização, classificar os tipos de hipervisores (Monitores de Máquina Virtual: VMM) é essencial.&lt;/p>
&lt;h3 id="21-diferenças-entre-hipervisores-type-1-e-type-2">2.1. Diferenças entre hipervisores Type 1 e Type 2
&lt;/h3>&lt;p>Um hipervisor é uma camada de software que abstrai o acesso ao hardware e permite que vários sistemas operacionais (SOs convidados) sejam executados simultaneamente em uma única máquina física.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Type 1 (Bare-metal)&lt;/strong>: Executado diretamente no hardware. Não existe o conceito de um SO host (embora, estritamente falando, possa existir um SO de gerenciamento com privilégios). Tem sobrecarga extremamente baixa e oferece alto desempenho e segurança. Exemplos: Hyper-V, VMware ESXi, Xen.&lt;/li>
&lt;li>&lt;strong>Type 2 (Hospedado)&lt;/strong>: Executado como um aplicativo no SO host (como Windows ou macOS). Como todo o acesso ao hardware passa pelo SO host, a sobrecarga é maior. Exemplos: VMware Workstation, Oracle VirtualBox.&lt;/li>
&lt;/ul>
&lt;p>O Hyper-V do Windows é um puro &lt;strong>hipervisor Type 1&lt;/strong>. Quando o Hyper-V é ativado, na verdade, o próprio SO Windows que o usuário opera normalmente passa a ser executado dentro de uma máquina virtual especial chamada &amp;ldquo;Partição Raiz (Root Partition)&amp;rdquo;.&lt;/p>
&lt;h3 id="22-detalhes-da-arquitetura-do-hyper-v">2.2. Detalhes da arquitetura do Hyper-V
&lt;/h3>&lt;p>A arquitetura do Hyper-V adota um design de microkernel e baseia-se em unidades de separação lógicas chamadas Partiçõoes (Partitions).&lt;/p>
&lt;pre class="mermaid">
graph TD
A[&amp;#34;Hardware (CPU, RAM, Disco, NIC)&amp;#34;] --&amp;gt; B[&amp;#34;Hipervisor do Windows (Ring -1)&amp;#34;]
B --&amp;gt; C[&amp;#34;Partição Raiz (SO Windows)&amp;#34;]
B --&amp;gt; D[&amp;#34;Partição Filha 1 (VM Windows)&amp;#34;]
B --&amp;gt; E[&amp;#34;Partição Filha 2 (VM Linux)&amp;#34;]
C --&amp;gt; F[&amp;#34;VMBus (Barramento de Máquina Virtual)&amp;#34;]
D --&amp;gt; F
E --&amp;gt; F
C --&amp;gt; G[&amp;#34;VID (Driver de Infraestrutura de Virtualização)&amp;#34;]
C --&amp;gt; H[&amp;#34;VMWP.exe (Processo de Trabalho)&amp;#34;]
&lt;/pre>
&lt;ul>
&lt;li>&lt;strong>Hipervisor do Windows (Windows Hypervisor)&lt;/strong>: Opera no estado de nível de privilégio mais alto da CPU (Ring -1 ou VMX Root Mode) e é responsável apenas pela alocação de memória e escalonamento da CPU. Não inclui drivers de dispositivo.&lt;/li>
&lt;li>&lt;strong>Partição Raiz (Root Partition)&lt;/strong>: A partição onde o SO Windows host é executado. Ela possui todos os drivers de dispositivo e controla o hardware diretamente. Também fornece funções de gerenciamento para as partições filhas (como provedores WMI e VMWP.exe).&lt;/li>
&lt;li>&lt;strong>Partição Filha (Child Partition)&lt;/strong>: A partição onde o SO convidado é executado. O acesso direto ao hardware não é permitido e as solicitações de E/S são enviadas à partição raiz (I/O Sintético) por meio de um barramento de compartilhamento de memória lógico chamado &amp;ldquo;VMBus&amp;rdquo;.&lt;/li>
&lt;/ul>
&lt;h3 id="23-o-mecanismo-do-wsl2-e-da-lightweight-utility-vm">2.3. O mecanismo do WSL2 e da Lightweight Utility VM
&lt;/h3>&lt;p>O WSL2 utiliza a mesma tecnologia base de hipervisor Type 1 que o Hyper-V, mas utiliza um subconjunto de recursos chamado &amp;ldquo;Plataforma de Máquina Virtual (Virtual Machine Platform: VMP)&amp;rdquo;, que é diferente de uma máquina virtual Hyper-V completa.&lt;/p>
&lt;p>A &amp;ldquo;Lightweight Utility VM&amp;rdquo; (Máquina Virtual Utilitária Leve) adotada no WSL2 elimina completamente a emulação de hardware legado (como BIOS virtual ou placa-mãe virtual) encontrada em VMs tradicionais.&lt;/p>
&lt;pre class="mermaid">
graph TD
A[&amp;#34;SO Host Windows (Espaço do Usuário)&amp;#34;]
B[&amp;#34;Sistema de Arquivos NTFS&amp;#34;]
C[&amp;#34;Servidor de Protocolo 9P (Plan 9)&amp;#34;]
D[&amp;#34;Lightweight Utility VM (Kernel Linux)&amp;#34;]
E[&amp;#34;ext4.vhdx (Disco Virtual)&amp;#34;]
F[&amp;#34;Espaço do Usuário Linux (Distribuições WSL2)&amp;#34;]
A --&amp;gt; C
C --&amp;gt;| Compartilhamento de Arquivos Cross-OS | D
D --&amp;gt; E
D --&amp;gt; F
&lt;/pre>
&lt;p>A maior característica do WSL2 é a &lt;strong>velocidade de inicialização&lt;/strong> e a &lt;strong>integração perfeita com o SO host&lt;/strong>. O kernel do Linux é inicializado em menos de alguns segundos e o sistema de arquivos do lado do Windows (NTFS) é acessado por meio do protocolo de sistema de arquivos de rede &lt;code>9P&lt;/code> do Plan 9.&lt;/p>
&lt;hr>
&lt;h2 id="3-análise-detalhada-de-desempenho-recursos-computacionais-e-es">3. Análise detalhada de desempenho: Recursos computacionais e E/S
&lt;/h2>&lt;p>O desempenho da máquina virtual é expresso como a soma das sobrecargas em cada componente de CPU, memória e E/S de disco.&lt;/p>
&lt;h3 id="31-sobrecarga-de-cpu-e-troca-de-contexto">3.1. Sobrecarga de CPU e troca de contexto
&lt;/h3>&lt;p>Tanto o Hyper-V quanto o WSL2 usam virtualização assistida por hardware (Intel VT-x / AMD-V). As instruções da CPU são executadas basicamente na velocidade nativa, mas ao executar instruções privilegiadas ou processar E/S, ocorre uma interrupção chamada &amp;ldquo;VM Exit&amp;rdquo;, realizando uma troca de contexto para o hipervisor.&lt;/p>
&lt;p>A sobrecarga de CPU neste momento, $T_{overhead}$, pode ser expressa pelo seguinte modelo matemático:&lt;/p>
$$ T_{overhead} = \sum_{i=1}^{N} (t_{vm\_exit} + t_{hypercall\_process} + t_{vm\_entry}) $$&lt;p>Onde:&lt;/p>
&lt;ul>
&lt;li>$N$: Número de ocorrências de VM Exit por unidade de tempo&lt;/li>
&lt;li>$t_{vm\_exit}$: Tempo de transição do convidado para o hipervisor&lt;/li>
&lt;li>$t_{hypercall\_process}$: Tempo de processamento de E/S ou interrupções via VMBus&lt;/li>
&lt;li>$t_{vm\_entry}$: Tempo de retorno do hipervisor para o convidado&lt;/li>
&lt;/ul>
&lt;p>Como o WSL2 não possui emulação de legado, $t_{hypercall\_process}$ é otimizado para ser extremamente pequeno. Portanto, em operações de CPU puras (como compilação de kernel ou inferência de modelos de aprendizado de máquina), a degradação de desempenho fica dentro de alguns por cento em comparação com um ambiente bare-metal.&lt;/p>
&lt;h3 id="32-mecanismos-de-alocação-de-memória">3.2. Mecanismos de alocação de memória
&lt;/h3>&lt;p>Existem diferenças claras nas filosofias de design entre os dois na abordagem de gerenciamento de memória.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Hyper-V (Memória Dinâmica)&lt;/strong>: A partição raiz aloca e recupera dinamicamente a memória de acordo com a demanda de memória da VM convidada. No entanto, a memória reservada como cache de página dentro do SO convidado tende a não ser liberada a menos que o sistema esteja sob pressão.&lt;/li>
&lt;li>&lt;strong>WSL2 (Recuperação dinâmica de memória)&lt;/strong>: O WSL2 tem seu próprio mecanismo e retorna periodicamente (Reclaim) a memória que não é mais necessária na VM Linux (incluindo o cache) para o host Windows. Nos primórdios do WSL2, havia o problema do cache de páginas do Linux consumir a memória do Windows (inchaço do processo Vmmem), mas isso foi melhorado agora com patches de kernel.&lt;/li>
&lt;/ul>
&lt;h3 id="33-características-de-es-de-disco-vhdx-vs-ext4vhdx">3.3. Características de E/S de disco (VHDX vs ext4.vhdx)
&lt;/h3>&lt;p>A E/S de disco é o gargalo mais provável no desempenho de uma máquina virtual.&lt;/p>
&lt;p>A latência de E/S, $L_{total}$, é calculada da seguinte forma:&lt;/p>
$$ L_{total} = L_{guest\_fs} + L_{vmbus} + L_{host\_fs} + L_{physical\_disk} $$&lt;p>&lt;strong>No caso do Hyper-V&lt;/strong>:
Convidados gerais do Hyper-V usam discos virtuais no formato &lt;code>VHDX&lt;/code>. As solicitações de E/S emitidas pelo sistema de arquivos (ext4 ou NTFS) dentro do SO convidado passam pelo driver de armazenamento de dispositivo de bloco (storvsc) do VMBus e são processadas como acessos ao arquivo VHDX no NTFS do lado do Windows.&lt;/p>
&lt;p>&lt;strong>No caso do WSL2&lt;/strong>:
As distribuições Linux no WSL2 operam em um sistema de arquivos ext4 nativo construído dentro de um arquivo &lt;code>ext4.vhdx&lt;/code> dedicado. Operações de arquivo dentro do Linux (como dentro do diretório &lt;code>~&lt;/code>) apresentam desempenho nativo equivalente ao do Hyper-V acima.
No entanto, o processo é muito diferente &lt;strong>quando o Linux no WSL2 acessa arquivos no lado do Windows (como &lt;code>/mnt/c/&lt;/code>)&lt;/strong>, ou vice-versa. Para esse acesso cross-OS, o &lt;code>9P (Plan 9 File System Protocol)&lt;/code> é usado.&lt;/p>
$$ L_{cross\_os} = L_{9p\_client} + L_{socket\_transfer} + L_{9p\_server} + L_{ntfs} $$&lt;p>O acesso através deste protocolo 9P possui uma grande sobrecarga de processamento de serialização e, para o propósito de ler e escrever um grande número de arquivos pequenos (por exemplo: um &lt;code>npm install&lt;/code> ou operações do Git em um projeto Node.js localizado em um diretório no lado do Windows), o desempenho diminui significativamente (às vezes mais de 10 vezes mais lento).
Portanto, &lt;strong>ao usar o WSL2, é uma regra de ouro sempre colocar os arquivos de projeto no sistema de arquivos nativo do Linux (sob &lt;code>~/&lt;/code>)&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h2 id="4-estrutura-de-rede-nat-default-switch-e-bridged">4. Estrutura de rede: NAT, Default Switch e Bridged
&lt;/h2>&lt;p>A flexibilidade de rede é uma das maiores diferenças entre o Hyper-V e o WSL2.&lt;/p>
&lt;h3 id="41-rede-do-wsl2-baseada-em-nat">4.1. Rede do WSL2 (Baseada em NAT)
&lt;/h3>&lt;p>Por padrão, a rede do WSL2 usa uma configuração &amp;ldquo;NAT (Network Address Translation)&amp;rdquo; usando a tecnologia de comutador virtual (Virtual Switch) do Hyper-V.
A VM Linux recebe automaticamente um endereço IP privado diferente do host Windows (por exemplo: &lt;code>172.20.x.x&lt;/code>). Está integrado um mecanismo onde o host Windows usa &lt;code>localhost&lt;/code> para encaminhar para serviços (portas) iniciados no WSL2, permitindo que os desenvolvedores testem servidores web e outros sem precisar estar cientes da rede.&lt;/p>
&lt;p>Recentemente, um novo modo de rede chamado &amp;ldquo;Mirrored mode&amp;rdquo; (Modo espelhado) foi introduzido em versões de visualização do WSL2. Isso visa melhorar o suporte IPv6 e a compatibilidade com conexões VPN (pode ser configurado em &lt;code>.wslconfig&lt;/code>).&lt;/p>
&lt;h3 id="42-comutador-virtual-do-hyper-v-virtual-switch">4.2. Comutador Virtual do Hyper-V (Virtual Switch)
&lt;/h3>&lt;p>O Hyper-V permite a construção de redes avançadas de nível corporativo. Através do &amp;ldquo;Gerenciador de Comutador Virtual&amp;rdquo;, ele fornece principalmente 3 modos.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Externo (External)&lt;/strong>: Vincula a NIC física da máquina host ao comutador virtual e permite que as VMs convidadas participem diretamente da rede física (conexão em ponte). A VM obtém um IP da mesma sub-rede da rede física através de um servidor DHCP.&lt;/li>
&lt;li>&lt;strong>Interno (Internal)&lt;/strong>: Permite a comunicação apenas entre o SO host e a VM, e entre as VMs. Não pode acessar diretamente redes externas.&lt;/li>
&lt;li>&lt;strong>Privado (Private)&lt;/strong>: Permite a comunicação apenas entre as VMs e bloqueia a comunicação com o SO host. Usado para construir ambientes de teste isolados.&lt;/li>
&lt;/ol>
&lt;h3 id="43-construção-avançada-de-rede-hyper-v-com-powershell">4.3. Construção avançada de rede Hyper-V com PowerShell
&lt;/h3>&lt;p>Em ambientes de desenvolvimento ou teste, quando você deseja construir uma rede NAT personalizada para VMs, o PowerShell permite um controle detalhado. Abaixo está um exemplo de script que cria um comutador virtual interno, configura NAT nele e fornece acesso à internet para as VMs.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 1. Criação do comutador virtual interno&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$SwitchName&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;HyperV-NatSwitch&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">New-VMSwitch&lt;/span> &lt;span class="n">-SwitchName&lt;/span> &lt;span class="nv">$SwitchName&lt;/span> &lt;span class="n">-SwitchType&lt;/span> &lt;span class="n">Internal&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 2. Definir endereço IP na NIC virtual do host (IP que servirá como gateway)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$GatewayIP&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;192.168.100.1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$NetPrefix&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="mf">24&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$InterfaceAlias&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;vEthernet (&lt;/span>&lt;span class="nv">$SwitchName&lt;/span>&lt;span class="s2">)&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">New-NetIPAddress&lt;/span> &lt;span class="n">-IPAddress&lt;/span> &lt;span class="nv">$GatewayIP&lt;/span> &lt;span class="n">-PrefixLength&lt;/span> &lt;span class="nv">$NetPrefix&lt;/span> &lt;span class="n">-InterfaceAlias&lt;/span> &lt;span class="nv">$InterfaceAlias&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 3. Configuração da rede NAT&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$NatName&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;HyperV-NatNetwork&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$NatSubnet&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;192.168.100.0/24&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">New-NetNat&lt;/span> &lt;span class="n">-Name&lt;/span> &lt;span class="nv">$NatName&lt;/span> &lt;span class="n">-InternalIPInterfaceAddressPrefix&lt;/span> &lt;span class="nv">$NatSubnet&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Comando para verificação&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Get-NetNat&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Com esta configuração, ao definir manualmente um IP de &lt;code>192.168.100.x&lt;/code> e o gateway &lt;code>192.168.100.1&lt;/code> no convidado Hyper-V especificado, você pode construir um segmento NAT próprio capaz de se comunicar externamente através do host.&lt;/p>
&lt;hr>
&lt;h2 id="5-casos-de-uso-e-guia-prático-de-seleção">5. Casos de uso e guia prático de seleção
&lt;/h2>&lt;p>Com base nas diferenças em arquitetura e desempenho discutidas até o momento, vamos definir em quais situações qual tecnologia deve ser adotada.&lt;/p>
&lt;h3 id="51-cenários-onde-o-wsl2-deve-ser-selecionado">5.1. Cenários onde o WSL2 deve ser selecionado
&lt;/h3>&lt;p>O WSL2 foi projetado especificamente para &amp;ldquo;melhorar a produtividade do desenvolvedor&amp;rdquo;. É ideal para os seguintes usos:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Desenvolvimento Web e nativo de nuvem&lt;/strong>: Desenvolvimento de contêineres usando Docker Desktop (backend WSL2) ou Podman.&lt;/li>
&lt;li>&lt;strong>Uso de ferramentas exclusivas do Linux&lt;/strong>: Ao usar diariamente bash, grep, awk, sed ou compiladores GCC ou Clang para Linux.&lt;/li>
&lt;li>&lt;strong>Aplicativos com GUI (WSLg)&lt;/strong>: Quando se deseja executar aplicativos Linux X11/Wayland nativamente na área de trabalho do Windows sem problemas.&lt;/li>
&lt;li>&lt;strong>Aprendizado de Máquina e Desenvolvimento de IA&lt;/strong>: Treinamento rápido de TensorFlow ou PyTorch usando a função de repasse de GPU (NVIDIA CUDA on WSL).&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Nota&lt;/strong>: Você pode encontrar limitações se quiser personalizar o kernel em detalhes ou construir serviços complexos que dependem fortemente do systemd (o systemd agora é suportado, mas desabilitado ou restrito por padrão).&lt;/p>
&lt;h3 id="52-cenários-onde-o-hyper-v-deve-ser-selecionado">5.2. Cenários onde o Hyper-V deve ser selecionado
&lt;/h3>&lt;p>O Hyper-V visa &amp;ldquo;virtualização e isolamento completo da infraestrutura&amp;rdquo;. Ele se torna indispensável para os seguintes casos de uso:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Execução de VMs Windows&lt;/strong>: Para executar diferentes versões do Windows (Windows Server, Windows 10 mais antigo, etc.) como um ambiente de teste.&lt;/li>
&lt;li>&lt;strong>Virtualização aninhada (Nested Virtualization)&lt;/strong>: Quando se deseja executar ainda mais máquinas virtuais (Hyper-V ou KVM) dentro de uma máquina virtual. É essencial para ambientes de verificação de engenheiros de infraestrutura.&lt;/li>
&lt;li>&lt;strong>Requisitos avançados de rede&lt;/strong>: Quando se precisa controlar rigorosamente as configurações de rede, como conexões de ponte externa (participação na mesma LAN), marcação de VLAN ou alocação de várias NICs.&lt;/li>
&lt;li>&lt;strong>Instantâneos (Snapshots/Checkpoints)&lt;/strong>: A capacidade de salvar o estado de uma VM em um momento específico e reverter instantaneamente a qualquer momento. Extremamente útil para testes destrutivos de software ou análise de malware.&lt;/li>
&lt;li>&lt;strong>Alocação de recursos fixos&lt;/strong>: Quando se deseja fixar rigorosamente o número de núcleos de CPU e a quantidade de memória para minimizar o impacto no SO host.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="6-considerações-sobre-a-taxa-de-transferência-throughput-de-es-por-meio-de-modelos-matemáticos-apêndice">6. Considerações sobre a taxa de transferência (throughput) de E/S por meio de modelos matemáticos (Apêndice)
&lt;/h2>&lt;p>Como um engenheiro de sistemas, ao avaliar os limites de desempenho de E/S de ambos, é importante entender teoricamente a relação entre a taxa de transferência $S$ e o tamanho do bloco $B$.&lt;/p>
&lt;p>A taxa de transferência de transferência de dados $S$ é a quantidade de transferência de dados por unidade de tempo, e é modelada da seguinte forma:&lt;/p>
$$ S(B) = \frac{B}{L_{setup} + \frac{B}{R_{max}}} $$&lt;ul>
&lt;li>$B$: Tamanho do bloco (Bytes)&lt;/li>
&lt;li>$L_{setup}$: Latência fixa associada à configuração de solicitações de E/S e à troca de contexto&lt;/li>
&lt;li>$R_{max}$: A largura de banda máxima do hardware na cópia ou transferência de dispositivo&lt;/li>
&lt;/ul>
&lt;p>No acesso a arquivos por meio do protocolo 9P do WSL2, este $L_{setup}$ é muito grande (devido à comunicação de soquete e à serialização/desserialização do protocolo). Portanto, quando o tamanho do bloco $B$ é pequeno (como leitura e gravação em massa de arquivos pequenos de cerca de alguns KB), a influência do $L_{setup}$ no denominador se torna dominante, e a taxa de transferência $S$ diminui drasticamente.
Por outro lado, em acessos VHDX via VMBus do Hyper-V, como o $L_{setup}$ é otimizado para um nível próximo a interrupções de hardware, operações altas de IOPS podem ser mantidas mesmo com blocos de pequeno tamanho.&lt;/p>
&lt;p>Esta realidade matemática é o fundamento lógico por trás da melhor prática de que &amp;ldquo;você não deve colocar arquivos de projeto no lado do Windows no WSL2&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h2 id="7-conclusão-duas-tecnologias-de-virtualização-que-coexistem">7. Conclusão: Duas tecnologias de virtualização que coexistem
&lt;/h2>&lt;p>O Hyper-V e o WSL2 não se tratam de um ser superior ao outro; eles são &lt;strong>&amp;ldquo;duas soluções com propósitos diferentes&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;ul>
&lt;li>O &lt;strong>WSL2&lt;/strong> é a &amp;ldquo;melhor ferramenta de integração&amp;rdquo; para romper a casca do SO Windows e entregar o ecossistema Linux aos usuários do Windows de forma contínua e rápida. Não é exagero dizer que é o melhor ambiente CLI para desenvolvedores.&lt;/li>
&lt;li>O &lt;strong>Hyper-V&lt;/strong> é um &amp;ldquo;hipervisor completo&amp;rdquo; que traz o robusto isolamento e capacidade de gerenciamento cultivados em data centers corporativos para o desktop. Não tem rival na construção de redes, no teste de SOs Windows e na simulação de ambientes de infraestrutura.&lt;/li>
&lt;/ul>
&lt;p>Nos ambientes Windows modernos, essas duas tecnologias não competem uniformemente, mas coexistem lindamente na mesma plataforma de VM. Ao usá-las nos lugares certos, dependendo da finalidade, o Windows será indiscutivelmente a estação de trabalho de engenharia mais poderosa e flexível do mundo.&lt;/p></description></item><item><title>Passos para Construir um Ambiente de Desenvolvimento Local Reprodutível usando Docker</title><link>http://kenji.blog/pt/p/docker-reproducible-local-dev-environment/</link><pubDate>Sun, 13 Sep 2026 01:00:00 +0900</pubDate><guid>http://kenji.blog/pt/p/docker-reproducible-local-dev-environment/</guid><description>&lt;img src="http://kenji.blog/p/docker-reproducible-local-dev-environment/img/eyecatch.jpg" alt="Featured image of post Passos para Construir um Ambiente de Desenvolvimento Local Reprodutível usando Docker" />&lt;h2 id="1-introdução-rompendo-com-o-na-minha-máquina-funciona">1. Introdução: Rompendo com o &amp;ldquo;Na minha máquina funciona&amp;rdquo;
&lt;/h2>&lt;p>No ambiente de desenvolvimento de software, o problema de &amp;ldquo;Na minha máquina funciona&amp;rdquo; (It works on my machine), causado por diferenças de ambiente entre os desenvolvedores, tem sido um fator de desperdício de tempo em muitos projetos por um longo período. Diferenças de sistema operacional, versões de linguagens instaladas, dependências de bibliotecas e conflitos de ferramentas instaladas globalmente fazem com que o ambiente local esteja sempre exposto à &amp;ldquo;incerteza de estado&amp;rdquo;.&lt;/p>
&lt;p>O que resolve fundamentalmente esses desafios são as tecnologias de contêineres, como o &lt;strong>Docker&lt;/strong>, e o paradigma de &lt;strong>Infrastructure as Code (IaC)&lt;/strong>. Ao conteinerizar o ambiente de desenvolvimento local, é possível alcançar isolamento em nível de SO e gerenciar a versão do ambiente em si junto com a base de código.&lt;/p>
&lt;p>Neste artigo, utilizando Docker, Docker Compose e VSCode DevContainers, explicaremos de forma minuciosa os passos para construir um &lt;strong>&amp;ldquo;ambiente de desenvolvimento local reprodutível em que o estado será exatamente o mesmo, não importando quem, quando ou em qual máquina ele for iniciado&amp;rdquo;&lt;/strong>, juntamente com os profundos mecanismos técnicos por trás disso, incluindo perspectivas matemáticas.&lt;/p>
&lt;hr>
&lt;h2 id="2-a-afinidade-entre-infrastructure-as-code-iac-e-a-tecnologia-de-contêineres">2. A Afinidade entre Infrastructure as Code (IaC) e a Tecnologia de Contêineres
&lt;/h2>&lt;h3 id="princípios-do-iac-e-sua-aplicação-ao-ambiente-local">Princípios do IaC e sua Aplicação ao Ambiente Local
&lt;/h3>&lt;p>Infrastructure as Code (IaC) é a abordagem de gerenciar a configuração e o provisionamento da infraestrutura através de arquivos de definição legíveis por máquina, em vez de processos manuais. Os princípios centrais do IaC incluem os seguintes elementos:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Abordagem Declarativa (Declarative Approach)&lt;/strong>: Define &amp;ldquo;como o estado final deve ser&amp;rdquo; em vez de &amp;ldquo;como alterar o estado&amp;rdquo;.&lt;/li>
&lt;li>&lt;strong>Idempotência (Idempotency)&lt;/strong>: Não importa quantas vezes o script seja executado, o mesmo resultado (estado) é sempre garantido.&lt;/li>
&lt;li>&lt;strong>Controle de Versão (Version Control)&lt;/strong>: O estado da infraestrutura é salvo como código em um VCS, como o Git, permitindo o rastreamento do histórico de alterações e a revisão por pares.&lt;/li>
&lt;/ol>
&lt;p>Praticar IaC no ambiente de desenvolvimento local significa codificar o &amp;ldquo;estado ideal&amp;rdquo; do ambiente de desenvolvimento usando &lt;code>Dockerfile&lt;/code>, &lt;code>docker-compose.yml&lt;/code> e &lt;code>devcontainer.json&lt;/code>. Isso proporciona uma experiência de integração (onboarding) na qual os novos membros da equipe podem clonar o repositório e executar apenas um comando para começar a desenvolver imediatamente.&lt;/p>
&lt;h3 id="recursos-do-kernel-que-suportam-a-tecnologia-de-contêineres">Recursos do Kernel que Suportam a Tecnologia de Contêineres
&lt;/h3>&lt;p>A tecnologia de contêineres, diferente da virtualização baseada em hypervisor como as máquinas virtuais (VMs), é uma tecnologia de virtualização leve que isola os processos enquanto compartilha o kernel do SO hospedeiro. Para realizar isso, os seguintes recursos do kernel do Linux são usados principalmente:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Namespaces&lt;/strong>: Fornece visualizações independentes dos recursos do sistema (PID, rede, pontos de montagem, usuários, etc.) para cada processo.&lt;/li>
&lt;li>&lt;strong>Cgroups (Control Groups)&lt;/strong>: Limita e aloca os recursos físicos (CPU, memória, E/S de disco, etc.) que um processo pode usar.&lt;/li>
&lt;li>&lt;strong>UnionFS (Union File System)&lt;/strong>: Uma tecnologia que sobrepõe transparentemente várias árvores de diretórios (camadas) e as apresenta como um único sistema de arquivos. As camadas de imagem do Docker dependem dessa tecnologia.&lt;/li>
&lt;/ul>
&lt;p>Vamos considerar um modelo matemático para a restrição de recursos. Seja $M_{\text{total}}$ a capacidade total de memória da máquina host e $m_i$ o limite de memória para $n$ contêineres rodando no host. A condição necessária para que o sistema opere de forma estável, considerando a memória base $M_{\text{os}}$ consumida pelo SO host e outros processos, pode ser expressa pela seguinte inequação:&lt;/p>
$$ \sum_{i=1}^{n} m_i \le M_{\text{total}} - M_{\text{os}} $$&lt;p>Ao definir estritamente $m_i$ para cada contêiner usando Cgroups, mesmo que um contêiner específico cause um vazamento de memória, podemos evitar que o OOM (Out Of Memory) Killer derrube outros contêineres ou o sistema host inteiro.&lt;/p>
&lt;hr>
&lt;h2 id="3-design-eficiente-do-dockerfile-dominando-os-multi-stage-builds">3. Design Eficiente do Dockerfile: Dominando os Multi-stage Builds
&lt;/h2>&lt;p>O primeiro passo para um ambiente reprodutivo é o design do &lt;code>Dockerfile&lt;/code> que define o ambiente de execução da aplicação. Aqui, usando Python (FastAPI) como exemplo, explicaremos as melhores práticas para um Dockerfile seguro e leve utilizando &lt;strong>multi-stage builds&lt;/strong> (builds de múltiplos estágios).&lt;/p>
&lt;p>O multi-stage build é uma técnica que usa várias instruções &lt;code>FROM&lt;/code> em um único &lt;code>Dockerfile&lt;/code> para separar o ambiente de build (um ambiente pesado contendo compiladores e ferramentas de desenvolvimento) do ambiente de execução (um ambiente leve contendo apenas os artefatos necessários).&lt;/p>
&lt;h3 id="exemplo-prático-de-dockerfile-para-python-fastapi">Exemplo Prático de Dockerfile para Python FastAPI
&lt;/h3>&lt;p>O código a seguir é um exemplo de um &lt;code>Dockerfile&lt;/code> avançado que combina o gerenciamento de dependências com o Poetry e multi-stage builds.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-dockerfile" data-lang="dockerfile">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># ---------------------------------------------------------&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Stage 1: Builder (Ambiente de build)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># ---------------------------------------------------------&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">FROM&lt;/span>&lt;span class="s"> python:3.11-slim AS builder&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Configuração de variáveis de ambiente necessárias&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">ENV&lt;/span> &lt;span class="nv">PYTHONUNBUFFERED&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">1&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="nv">PYTHONDONTWRITEBYTECODE&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">1&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="nv">POETRY_VERSION&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">1&lt;/span>.6.1 &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="nv">POETRY_HOME&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;/opt/poetry&amp;#34;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="nv">POETRY_VIRTUALENVS_IN_PROJECT&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">true&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="nv">POETRY_NO_INTERACTION&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">1&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Instalação de pacotes dependentes&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">RUN&lt;/span> apt-get update &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> apt-get install -y --no-install-recommends &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> curl build-essential &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> curl -sSL https://install.python-poetry.org &lt;span class="p">|&lt;/span> python3 - &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> apt-get clean &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> rm -rf /var/lib/apt/lists/*&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">ENV&lt;/span> &lt;span class="nv">PATH&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$POETRY_HOME&lt;/span>&lt;span class="s2">/bin:&lt;/span>&lt;span class="nv">$PATH&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">WORKDIR&lt;/span>&lt;span class="s"> /app&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Cópia dos arquivos de dependência e instalação&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> pyproject.toml poetry.lock ./&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">RUN&lt;/span> poetry install --no-root --only main&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># ---------------------------------------------------------&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Stage 2: Runtime (Ambiente de execução)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># ---------------------------------------------------------&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">FROM&lt;/span>&lt;span class="s"> python:3.11-slim AS runtime&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">ENV&lt;/span> &lt;span class="nv">PYTHONUNBUFFERED&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">1&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="nv">PYTHONDONTWRITEBYTECODE&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">1&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="nv">PATH&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;/app/.venv/bin:&lt;/span>&lt;span class="nv">$PATH&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Criação de um usuário sem privilégios mínimos&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">RUN&lt;/span> groupadd -r appuser &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> useradd -r -g appuser appuser&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">WORKDIR&lt;/span>&lt;span class="s"> /app&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Copia apenas o ambiente virtual (dependências) do builder&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> --from&lt;span class="o">=&lt;/span>builder --chown&lt;span class="o">=&lt;/span>appuser:appuser /app/.venv /app/.venv&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Cópia do código da aplicação&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> --chown&lt;span class="o">=&lt;/span>appuser:appuser ./src /app/src&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Mudança para o usuário sem privilégios&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">USER&lt;/span>&lt;span class="s"> appuser&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Comando padrão ao iniciar o contêiner&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">ENTRYPOINT&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;uvicorn&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;src.main:app&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;--host&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;0.0.0.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;--port&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;8000&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="avaliação-matemática-do-tamanho-da-imagem-por-multi-stage-build">Avaliação Matemática do Tamanho da Imagem por Multi-stage Build
&lt;/h3>&lt;p>Seja $S_{\text{single}}$ o tamanho da imagem quando construída em um único estágio, e $S_{\text{multi}}$ o tamanho da imagem quando o multi-stage build é aplicado. A taxa de redução de tamanho $R$ é calculada da seguinte forma:&lt;/p>
$$ R = \left( 1 - \frac{S_{\text{multi}}}{S_{\text{single}}} \right) \times 100 \ (\%) $$&lt;p>Por exemplo, suponha que $S_{\text{single}}$ inclua a imagem base do SO (cerca de 110 MB), pacotes de desenvolvimento (como gcc, cerca de 150 MB), o próprio Poetry (cerca de 40 MB), as bibliotecas dependentes do projeto (cerca de 80 MB) e o código fonte (cerca de 5 MB), totalizando 385 MB.
Por outro lado, em $S_{\text{multi}}$, apenas as bibliotecas dependentes (80 MB) e o código fonte (5 MB) são copiados para a imagem base (110 MB), resultando em um total de 195 MB.&lt;/p>
$$ R = \left( 1 - \frac{195}{385} \right) \times 100 \approx 49.35\% $$&lt;p>Dessa forma, introduzir o multi-stage build pode reduzir o tamanho da imagem pela metade. A redução do tamanho da imagem traduz-se diretamente em tempos de pull mais curtos do registro, economia de espaço em disco e melhor segurança devido à redução da superfície de ataque (Attack Surface).&lt;/p>
&lt;hr>
&lt;h2 id="4-orquestração-de-múltiplos-contêineres-com-docker-compose">4. Orquestração de Múltiplos Contêineres com Docker Compose
&lt;/h2>&lt;p>No desenvolvimento moderno de aplicações web, arquiteturas de microsserviços em que vários componentes colaboram, como servidores web, bancos de dados e servidores de cache, são comuns. Para gerenciá-los centralmente no ambiente local, usamos o &lt;code>docker-compose.yml&lt;/code>.&lt;/p>
&lt;p>Desta vez, construiremos localmente um sistema de 3 camadas com &amp;ldquo;Web (FastAPI)&amp;rdquo;, &amp;ldquo;Database (PostgreSQL)&amp;rdquo; e &amp;ldquo;Cache (Redis)&amp;rdquo;.&lt;/p>
&lt;h3 id="diagrama-de-arquitetura-mermaid">Diagrama de Arquitetura (Mermaid)
&lt;/h3>&lt;p>O diagrama abaixo é um diagrama de blocos que representa o relacionamento entre cada contêiner, a rede e os volumes na máquina local.&lt;/p>
&lt;pre class="mermaid">
graph TD
User[&amp;#34;Máquina Host (Navegador/curl)&amp;#34;] --&amp;gt;|Localhost:8000| Web[&amp;#34;Contêiner Web FastAPI&amp;#34;]
subgraph &amp;#34;Rede Bridge do Docker (app-network)&amp;#34;
Web --&amp;gt;|Porta 5432| DB[&amp;#34;Contêiner PostgreSQL&amp;#34;]
Web --&amp;gt;|Porta 6379| Redis[&amp;#34;Contêiner Redis&amp;#34;]
end
DB --&amp;gt; Volume1[&amp;#34;Volume Nomeado (postgres_data)&amp;#34;]
Redis --&amp;gt; Volume2[&amp;#34;Volume Nomeado (redis_data)&amp;#34;]
HostDir[&amp;#34;Código Fonte do Host (./src)&amp;#34;] -.-&amp;gt;|Bind Mount| Web
&lt;/pre>
&lt;h3 id="implementação-e-explicação-detalhada-do-docker-composeyml">Implementação e Explicação Detalhada do docker-compose.yml
&lt;/h3>&lt;p>Abaixo, é mostrado um exemplo de um &lt;code>docker-compose.yml&lt;/code> robusto que pode suportar a construção de um ambiente prático.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;3.8&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">services&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">web&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">build&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">context&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">.&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">target&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">runtime&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">container_name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">dev_web&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">ports&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;8000:8000&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">volumes&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">./src:/app/src:ro &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># Monta o código do host como somente leitura (para hot reload)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">environment&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">REDIS_URL=redis://redis:6379/0&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">env_file&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">.env&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">depends_on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">db&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">condition&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">service_healthy&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">redis&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">condition&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">service_started&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">networks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">app-network&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">command&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;uvicorn&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;src.main:app&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;--host&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;0.0.0.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;--port&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;8000&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;--reload&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">db&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">postgres:15-alpine&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">container_name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">dev_db&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">ports&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;5432:5432&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">environment&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">POSTGRES_USER&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">postgres&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">POSTGRES_PASSWORD&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${POSTGRES_PASSWORD}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">POSTGRES_DB&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${POSTGRES_DB}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">volumes&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">postgres_data:/var/lib/postgresql/data&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">networks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">app-network&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">healthcheck&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">test&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;CMD-SHELL&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;pg_isready -U postgres -d ${POSTGRES_DB}&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">interval&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">5s&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">timeout&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">5s&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">retries&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">5&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">redis&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">redis:7-alpine&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">container_name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">dev_redis&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">ports&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;6379:6379&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">volumes&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">redis_data:/data&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">networks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">app-network&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">command&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;redis-server&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;--appendonly&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;yes&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">volumes&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">postgres_data&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">redis_data&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">networks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">app-network&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">driver&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">bridge&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="volumes-volumes-e-persistência-de-dados">Volumes (Volumes) e Persistência de Dados
&lt;/h3>&lt;p>Por princípio, os contêineres são &amp;ldquo;sem estado&amp;rdquo; (stateless) e &amp;ldquo;efêmeros&amp;rdquo; (ephemeral). Quando um contêiner é destruído, os dados internos também são perdidos. Para reter dados do banco de dados ou caches, é necessário montar uma área do sistema de arquivos da máquina host no contêiner.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Bind Mount (Montagem de Ligação)&lt;/strong>: O &lt;code>./src:/app/src:ro&lt;/code> no serviço &lt;code>web&lt;/code> acima se enquadra nisso. Ele mapeia um diretório específico do host diretamente para dentro do contêiner. Usado para refletir as edições de código local imediatamente no contêiner (hot reload). Do ponto de vista de segurança, a melhor prática é adicionar a opção &lt;code>:ro&lt;/code> (Read-Only) para evitar que o código fonte do host seja modificado a partir do contêiner.&lt;/li>
&lt;li>&lt;strong>Named Volume (Volume Nomeado)&lt;/strong>: &lt;code>postgres_data&lt;/code> e &lt;code>redis_data&lt;/code> se enquadram nisso. É uma área gerenciada internamente pelo Docker (por exemplo, &lt;code>/var/lib/docker/volumes/&lt;/code>), com desempenho de E/S superior aos bind mounts e absorve as diferenças de sistema de arquivos entre os SOs. Sempre use este método para a persistência de bancos de dados.&lt;/li>
&lt;/ul>
&lt;h3 id="rede-networking-e-descoberta-de-serviços">Rede (Networking) e Descoberta de Serviços
&lt;/h3>&lt;p>O Docker Compose cria, por padrão, uma rede de ponte (bridge network) exclusiva para cada projeto. É a &lt;code>app-network&lt;/code> mencionada acima.
Contêineres pertencentes à mesma rede podem resolver nomes (resolução DNS) usando o &amp;ldquo;nome do serviço&amp;rdquo; (ex: &lt;code>db&lt;/code>, &lt;code>redis&lt;/code>) como hostname, em vez do endereço IP.
Por exemplo, do contêiner Web, é possível acessar o banco de dados pela URL &lt;code>postgresql://postgres:password@db:5432/mydb&lt;/code>. Isso torna possível alternar os destinos de conexão de forma transparente por meio de variáveis de ambiente, tanto no ambiente local quanto em produção.&lt;/p>
&lt;h3 id="verificação-de-integridade-healthcheck-e-controle-da-ordem-de-inicialização">Verificação de Integridade (Healthcheck) e Controle da Ordem de Inicialização
&lt;/h3>&lt;p>A diretiva &lt;code>depends_on&lt;/code> controla a ordem de inicialização dos contêineres, mas apenas especificar &lt;code>depends_on&lt;/code> fará com que o contêiner Web seja iniciado assim que o &amp;ldquo;contêiner do DB for iniciado&amp;rdquo;. Na realidade, o processo de inicialização do DB (início do processo do PostgreSQL e preparação das tabelas) leva vários segundos, o que pode causar erros de conexão do DB a partir do contêiner Web.
Para evitar isso, é possível definir um &lt;code>healthcheck&lt;/code> e especificar &lt;code>condition: service_healthy&lt;/code> para iniciar o contêiner Web apenas após confirmar que &amp;ldquo;o DB está em um estado em que pode aceitar requisições de conexão&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h2 id="5-gerenciamento-de-variáveis-de-ambiente-e-segurança-env">5. Gerenciamento de Variáveis de Ambiente e Segurança (.env)
&lt;/h2>&lt;p>O hardcoding de informações sensíveis, como senhas de banco de dados e chaves de API, no &lt;code>docker-compose.yml&lt;/code> é um antipadrão que deve ser evitado a todo custo. Em vez disso, usamos um arquivo de variáveis de ambiente &lt;code>.env&lt;/code> para injetar esses valores.&lt;/p>
&lt;p>Crie um arquivo &lt;code>.env&lt;/code> na raiz do projeto.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-ini" data-lang="ini">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Arquivo .env (Lembre-se de adicioná-lo ao .gitignore para não ser gerenciado pelo Git)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">POSTGRES_PASSWORD&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">supersecretpassword&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">POSTGRES_DB&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">devdb&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">API_SECRET_KEY&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">dev_secret_key_12345&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>O Docker Compose lê, por padrão, o arquivo &lt;code>.env&lt;/code> localizado no diretório de execução e expande os espaços reservados &lt;code>${VAR_NAME}&lt;/code> dentro do arquivo YAML. Com este método, é possível gerenciar com segurança valores de configuração diferentes para cada ambiente (como local, staging e produção) sem alterar o código da infraestrutura.&lt;/p>
&lt;hr>
&lt;h2 id="6-a-melhor-experiência-de-desenvolvimento-com-vscode-devcontainers">6. A Melhor Experiência de Desenvolvimento com VSCode DevContainers
&lt;/h2>&lt;p>Até aqui, construímos um ambiente de backend robusto usando Docker. No entanto, podemos ir um passo além. Utilizando o recurso &lt;strong>VSCode DevContainers (Remote - Containers)&lt;/strong>, torna-se possível executar o próprio backend do editor (VSCode) dentro do contêiner.&lt;/p>
&lt;p>Isso elimina a necessidade de instalar sequer o Python ou Node.js na máquina local e permite que tudo, desde linters (flake8/eslint) e formatadores (black/prettier) até extensões da IDE, seja definido dentro da base de código e compartilhado com toda a equipe.&lt;/p>
&lt;h3 id="configuração-do-devcontainerjson">Configuração do devcontainer.json
&lt;/h3>&lt;p>Crie um diretório &lt;code>.devcontainer&lt;/code> na raiz do projeto e coloque o arquivo de configuração dentro dele.&lt;/p>
&lt;p>&lt;code>.devcontainer/devcontainer.json&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Python FastAPI Dev Environment&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;dockerComposeFile&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;../docker-compose.yml&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;service&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;web&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;workspaceFolder&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;/app&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;customizations&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;vscode&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;settings&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;python.defaultInterpreterPath&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;/app/.venv/bin/python&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;python.formatting.provider&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;black&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;editor.formatOnSave&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;extensions&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ms-python.python&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ms-python.vscode-pylance&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ms-python.black-formatter&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;tamasfe.even-better-toml&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;forwardPorts&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">8000&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5432&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">6379&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;remoteUser&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;appuser&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;postCreateCommand&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;poetry install&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Ao incluir este arquivo no repositório, no momento em que você abre o projeto no VSCode, um prompt &amp;ldquo;Reopen in Container&amp;rdquo; será exibido. Com apenas um clique, todos os contêineres necessários são iniciados, as extensões são instaladas e você estará imediatamente pronto para começar a codificar. É uma experiência verdadeiramente mágica.&lt;/p>
&lt;hr>
&lt;h2 id="7-sequência-de-processamento-de-requisições-e-modelagem-de-desempenho">7. Sequência de Processamento de Requisições e Modelagem de Desempenho
&lt;/h2>&lt;p>Vamos verificar o ciclo de vida do processamento de requisições da aplicação web no ambiente de desenvolvimento local construído com um diagrama de sequência e considerar o modelo matemático de seu desempenho.&lt;/p>
&lt;h3 id="diagrama-de-sequência-fluxo-de-requisições">Diagrama de Sequência (Fluxo de Requisições)
&lt;/h3>&lt;pre class="mermaid">
sequenceDiagram
participant Client as &amp;#34;Navegador / VSCode&amp;#34;
participant Web as &amp;#34;FastAPI (Web)&amp;#34;
participant Redis as &amp;#34;Cache Redis&amp;#34;
participant DB as &amp;#34;PostgreSQL&amp;#34;
Client-&amp;gt;&amp;gt;Web: &amp;#34;GET /api/users/123&amp;#34;
activate Web
Web-&amp;gt;&amp;gt;Redis: &amp;#34;Verificar Cache para user:123&amp;#34;
activate Redis
alt &amp;#34;Cache Hit (Dados encontrados)&amp;#34;
Redis--&amp;gt;&amp;gt;Web: &amp;#34;Retornar Dados de Usuário em Cache&amp;#34;
Web--&amp;gt;&amp;gt;Client: &amp;#34;200 OK (Resposta Rápida)&amp;#34;
else &amp;#34;Cache Miss (Dados não encontrados)&amp;#34;
Redis--&amp;gt;&amp;gt;Web: &amp;#34;Nulo (Não Encontrado)&amp;#34;
deactivate Redis
Web-&amp;gt;&amp;gt;DB: &amp;#34;SELECT * FROM users WHERE id = 123&amp;#34;
activate DB
DB--&amp;gt;&amp;gt;Web: &amp;#34;Retornar Linha do Banco de Dados&amp;#34;
deactivate DB
Web-&amp;gt;&amp;gt;Redis: &amp;#34;SET user:123 Data (TTL: 60s)&amp;#34;
activate Redis
Redis--&amp;gt;&amp;gt;Web: &amp;#34;OK&amp;#34;
deactivate Redis
Web--&amp;gt;&amp;gt;Client: &amp;#34;200 OK (Resposta Padrão)&amp;#34;
end
deactivate Web
&lt;/pre>
&lt;h3 id="modelo-matemático-de-atraso-de-processamento-latência">Modelo Matemático de Atraso de Processamento (Latência)
&lt;/h3>&lt;p>Modelaremos matematicamente o tempo médio de processamento de requisições $T_{\text{total}}$ no sistema acima.
A latência de cada processamento é definida a seguir:&lt;/p>
&lt;ul>
&lt;li>$T_{\text{net}}$: Latência de rede entre o cliente e o contêiner Web&lt;/li>
&lt;li>$T_{\text{app}}$: Tempo de processamento puro no lado da aplicação (como serialização)&lt;/li>
&lt;li>$T_{\text{cache}}$: Tempo gasto lendo e escrevendo no Redis&lt;/li>
&lt;li>$T_{\text{db}}$: Tempo gasto na execução de consultas ao PostgreSQL&lt;/li>
&lt;li>$p_{\text{miss}}$: Taxa de cache miss ($0 \le p_{\text{miss}} \le 1$)&lt;/li>
&lt;/ul>
&lt;p>O tempo médio de resposta é expresso pela seguinte fórmula de valor esperado:&lt;/p>
$$ T_{\text{total}} = T_{\text{net}} + T_{\text{app}} + T_{\text{cache}} + p_{\text{miss}} \times (T_{\text{db}} + T_{\text{cache\_write}}) $$&lt;p>No ambiente de desenvolvimento local (dentro do Docker), $T_{\text{net}}$ fica quase próximo a 0, mas o que deve ser notado é a &lt;strong>performance de E/S durante o bind mount&lt;/strong>. Especialmente ao usar o Docker Desktop no Windows/macOS, devido ao overhead de compartilhamento de arquivos entre o SO host e a VM (contêiner), $T_{\text{app}}$ (tempo de carregamento do código, etc.) tende a se tornar inflado. Para eliminar esse gargalo de desempenho, é altamente recomendada uma arquitetura que utilize DevContainers, conforme mencionado anteriormente, colocando todo o código fonte dentro de um volume nomeado ou executando a engine do Docker nativamente em um ambiente WSL2 (Windows Subsystem for Linux 2).&lt;/p>
&lt;hr>
&lt;h2 id="8-otimização-do-desempenho-do-build-do-docker-estratégia-de-cache-de-camadas">8. Otimização do Desempenho do Build do Docker: Estratégia de Cache de Camadas
&lt;/h2>&lt;p>Ao escrever um Dockerfile, entender o mecanismo de &amp;ldquo;cache de camadas&amp;rdquo; muda drasticamente o tempo de build.
O Docker cria um diferencial de sistema de arquivos (camada) para cada instrução no Dockerfile (&lt;code>FROM&lt;/code>, &lt;code>RUN&lt;/code>, &lt;code>COPY&lt;/code>, etc.) e a retém como cache. Nas reconstruções, o cache das camadas inalteradas é reutilizado.&lt;/p>
&lt;p>O princípio importante é &lt;strong>&amp;ldquo;escrever as instruções em ordem crescente da frequência de alterações&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;p>Vamos considerar a modelagem do impacto das alterações do código fonte no tempo de build. Seja o tempo total de build $T_{\text{build}}$, o tempo de execução de cada etapa $T_{\text{layer}_i}$ e a presença ou ausência do cache hit o valor booleano $c_i \in \{0, 1\}$ (1 quando houver cache hit).&lt;/p>
$$ T_{\text{build}} = T_{\text{init}} + \sum_{i=1}^{n} (1 - c_i) \times T_{\text{layer}_i} $$&lt;p>Uma vez que ocorre um cache miss ($c_k = 0$) na camada $k$, o cache é invalidado ($c_j = 0$) para todas as camadas subsequentes $j > k$.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-dockerfile" data-lang="dockerfile">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Exemplo ruim (Copiando o código fonte primeiro)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> ./src /app/src&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> pyproject.toml poetry.lock ./&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">RUN&lt;/span> poetry install&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Neste caso, mudar apenas uma linha de código causará um cache miss na primeira instrução &lt;code>COPY&lt;/code>, resultando na demorada instrução &lt;code>RUN poetry install&lt;/code> sendo executada a cada vez.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-dockerfile" data-lang="dockerfile">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Bom exemplo (Resolvendo as dependências primeiro)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> pyproject.toml poetry.lock ./&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">RUN&lt;/span> poetry install&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> ./src /app/src&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Se for escrito dessa forma, mesmo que o código fonte seja alterado, o cache da camada para o &lt;code>poetry install&lt;/code> ($c_i = 1$) será efetivo, e o tempo de build será reduzido drasticamente de minutos para segundos.&lt;/p>
&lt;hr>
&lt;h2 id="9-solução-de-problemas-e-dicas-troubleshooting">9. Solução de Problemas e Dicas (Troubleshooting)
&lt;/h2>&lt;p>Aqui estão problemas comuns e soluções ao operar em um ambiente local.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Erro de Conflito de Portas&lt;/strong>
Se ocorrer um erro como &lt;code>Bind for 0.0.0.0:8000 failed: port is already allocated&lt;/code>, outro processo na máquina local está usando essa porta. Você pode evitar isso alterando o número da porta do lado do host para algo como &lt;code>ports: - &amp;quot;8080:8000&amp;quot;&lt;/code>.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Esgotamento do Espaço em Disco&lt;/strong>
Ao usar o Docker por um longo tempo, imagens ou volumes não utilizados (Dangling Images / Volumes) podem se acumular, consumindo dezenas de GB do espaço em disco. Recomenda-se limpar regularmente o sistema com o seguinte comando:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">docker system prune -a --volumes
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>Problema de Permissões de Arquivos&lt;/strong>
Ao usar bind mounts no ambiente Linux, o proprietário dos arquivos criados no contêiner será &lt;code>root&lt;/code>, e não será possível editá-los no lado do host. Você pode resolver isso criando um usuário sem privilégios no Dockerfile que coincida com o seu próprio UID/GID do SO host (ex: 1000:1000).&lt;/p>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="10-conclusão-a-melhoria-na-velocidade-de-desenvolvimento-trazida-pela-reprodutibilidade">10. Conclusão: A Melhoria na Velocidade de Desenvolvimento Trazida pela Reprodutibilidade
&lt;/h2>&lt;p>Ao combinar o Docker, Docker Compose e VSCode DevContainers, um ambiente de desenvolvimento local robusto é alcançado, onde &amp;ldquo;não importa quem inicie o ambiente, o estado será perfeitamente o mesmo&amp;rdquo;.&lt;/p>
&lt;p>Trazer o paradigma IaC para o ambiente local não reduz apenas o tempo de configuração inicial. Ele melhora drasticamente a velocidade e a qualidade de todo o ciclo de desenvolvimento, removendo a ansiedade em relação às mudanças de configuração da infraestrutura, facilitando a experimentação de novas pilhas de tecnologias e possibilitando uma transição suave para as pipelines de CI/CD.&lt;/p>
&lt;p>Utilize as melhores práticas explicadas neste artigo, como a otimização do tamanho da imagem por meio de multi-stage builds, controle de dependências usando healthchecks e a escrita do Dockerfile focada no cache de camadas, e, com certeza, implemente a melhor experiência de desenvolvimento (DX: Developer Experience) em seu próprio projeto.&lt;/p></description></item></channel></rss>