<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Poveda</title>
    <description>The latest articles on DEV Community by Poveda (@poveda).</description>
    <link>https://dev.to/poveda</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F260018%2F06660fa4-ef90-41cd-9d7d-38187d0aec48.png</url>
      <title>DEV Community: Poveda</title>
      <link>https://dev.to/poveda</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/poveda"/>
    <language>en</language>
    <item>
      <title>Performance pode ser simples: Arquivo gigante em memória</title>
      <dc:creator>Poveda</dc:creator>
      <pubDate>Tue, 04 Feb 2025 13:48:56 +0000</pubDate>
      <link>https://dev.to/poveda/performance-pode-ser-simples-arquivo-gigante-em-memoria-5g29</link>
      <guid>https://dev.to/poveda/performance-pode-ser-simples-arquivo-gigante-em-memoria-5g29</guid>
      <description>&lt;p&gt;Quando se fala em performance de uma aplicação é muito comum pensar em escovação de bit, mudança de paradigmas de implementação ou até mesmo de linguagem. No entanto, as principais otimizações acontecem olhando o básico: o gargalo atual da aplicação.&lt;/p&gt;

&lt;p&gt;Nessa série de posts vou trazer alguns desafios que ajudei a resolver. A ideia é mostrar a linha de raciocínio, quais soluções se mostraram promissoras e quais soluções foram descartadas devido aos riscos adicionados. Em todos os casos demonstro que a ideia da otimização não teve qualquer coleta de ferramentas especializadas ou escovação de bit, apenas uso dos recursos do próprio visual studio, leitura de documentação, análise de código e conhecimento na linguagem utilizada.&lt;/p&gt;

&lt;h2&gt;
  
  
  Desafio: Geração do arquivo csv de 65Mb consumindo 1,2Gb de ram
&lt;/h2&gt;

&lt;p&gt;Objetivo:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O sistema deve buscar no banco cerca de 200k registros, transformar os dados, gerar um arquivo &lt;em&gt;.csv&lt;/em&gt; e transferi-lo para um fileserver remoto.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Cenário atual:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Todo o processamento e "armazenamento" dos dados fica em memória, ou seja, nada é salvo em disco do lado da aplicação. O arquivo só será salvo no disco do servidor de arquivos.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O problema encontrado:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Todo processamento aloca aproximadamente de 1,2Gb de memória para gerar um arquivo de aproximadamente 65Mb. Portanto existe um consumo de memória de 18x maior para gerar o arquivo em questão.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Mapeamento das restrições
&lt;/h2&gt;

&lt;p&gt;O primeiro questionamento foi:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Por que não podemos salvar o arquivo localmente e em seguida transferi-lo o servidor de arquivos?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A resposta:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A data de publicação do sistema foi acordada com o cliente previamente e não pode mudar. Qualquer correção que ultrapasse a data acordada ficará para um segundo momento e o sistema subirá em produção no estado em que se encontra.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Inicio da análise
&lt;/h2&gt;

&lt;p&gt;Com a restrição definida, hora de baixar o código, analisá-lo e colocá-lo para rodar.&lt;/p&gt;

&lt;p&gt;Lendo novamente o objetivo do sistema pensei em 3 pontos de gargalo:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A quantidade de dados retornados do banco&lt;/li&gt;
&lt;li&gt;A transformação dos dados&lt;/li&gt;
&lt;li&gt;A forma como o .csv é gerado&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Analisando o código para cada uma das suspeitas cheguei nessas observações:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;O problema principal do retorno do banco de dados é que todos os registros são do tipo string.&lt;/li&gt;
&lt;li&gt;A transformação dos dados não é muito preocupante, pois 96% das informações já vêm prontas para serem escritas no arquivo.&lt;/li&gt;
&lt;li&gt;Na geração do csv é onde o problema começa a ficar evidente:

&lt;ol&gt;
&lt;li&gt;Temos diversas operações com strings: Join, ToString.&lt;/li&gt;
&lt;li&gt;Diversos StringBuilders de uso único que invocam o método &lt;strong&gt;.ToString()&lt;/strong&gt; ao final de cada execução&lt;/li&gt;
&lt;li&gt;StringBuilder mal utilizado&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;Com essas suspeitas anotadas hora de rodar a aplicação!&lt;/p&gt;

&lt;h2&gt;
  
  
  Rodando a aplicação
&lt;/h2&gt;

&lt;p&gt;Realizo a primeira execução da aplicação no estado atual para entender melhor o fluxo, tempos de processamento, validar acessos, etc. Ao final do teste o resultado vai de encontro com o problema informado:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3tjynj4fv5x4xunh5mx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3tjynj4fv5x4xunh5mx.png" alt="primeira execução mostra consumo de 1,2Gb de memória am e picos de 5% de uso do processador" width="296" height="181"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tamanho do arquivo gerado:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fytqgdfdkov0hzlx108s2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fytqgdfdkov0hzlx108s2.png" alt="evidencia provando que tamanho do arquivo csv gerado é 68Mb" width="365" height="28"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Executo a aplicação novamente para observar as mudanças de memória e encontrar o motivo da sua subida vertiginosa.&lt;/p&gt;

&lt;p&gt;Utilizando o gráfico acima como referência, nota-se que existem 3 etapas no aumento de memória:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A primeira curva representa a obtenção dos dados. &lt;/li&gt;
&lt;li&gt;Um platô representado pela configuração do arquivo csv&lt;/li&gt;
&lt;li&gt;Uma subida rápida representada pela geração do csv em memória&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Portanto é na terceira etapa que o consumo de memória torna-se expressivo. Gargalo encontrado!&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementando melhorias
&lt;/h2&gt;

&lt;p&gt;Com o gargalo encontrado, voltamos as observações levantadas para a etapa 3: A forma como o .csv é construído.&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Temos diversas operações com strings: Join, ToString.&lt;/li&gt;
&lt;li&gt;Diversos StringBuilders de uso único e invocando o método &lt;strong&gt;.ToString()&lt;/strong&gt; ao final de cada execução&lt;/li&gt;
&lt;li&gt;StringBuilder subutilizados&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;Os trechos de código abaixo mimetizam a estrutura original da aplicação:&lt;/p&gt;

&lt;p&gt;Método GenerateInMemoryCsv: gera um CSV em memória&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GenerateInMemoryCsv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Vehicle&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;vehicles&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;headerFields&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;  &lt;span class="n"&gt;Vehicle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetHeaderFields&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;    
   &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;";"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headerFields&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\n"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vehicles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertToCsv&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StringBuilder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;AppendJoin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\n"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;    
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Método GetHeaderField: obtém o cabeçalho do csv&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;GetHeaderFields&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
   &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"Marca"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Ano"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Modelo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Quantidade de Portas"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Motor"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Método ConvertToCsv: converte o registro em uma linha válida para o csv&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;ConvertToCsv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;StringBuilder&lt;/span&gt; &lt;span class="n"&gt;sb&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AppendJoin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;";"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Marca&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Ano&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Modelo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QtdPortas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Motor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Reduzindo a alocação de strings
&lt;/h3&gt;

&lt;p&gt;Pensando na questão do uso excessivo de operações com string que retornam outras strings, é necessário lembrar que a string é um tipo readonly. Parafraseando &lt;a href="https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/strings/#immutability-of-strings" rel="noopener noreferrer"&gt;a documentação oficial do C#&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Objetos do tipo string são imutáveis: não podem ser alterados após serem criados. &lt;br&gt;
Todos os métodos String e operadores C# que aparecem para modificar uma string retornam, na verdade, os resultados em um novo string.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ou seja, para cada Join e para cada ToString utilizado, uma nova string é gerada sem descartar ou sobrescrever a antiga. Isso implica em dobrar a quantidade de memória cada vez que essas operações são utilizadas. Portanto o primeiro passo para otimização é reduzir a quantidade de operações do tipo &lt;strong&gt;Join&lt;/strong&gt; e &lt;strong&gt;ToString&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Analisando os códigos acima o método que possui mais operações que retornam novas strings é o ConvertToCsv. Pode não parecer óbvio olhando os métodos separados, mas lembre-se do enunciado do problema: &lt;strong&gt;&lt;code&gt;O sistema deve buscar no banco cerca de 200k registros&lt;/code&gt;&lt;/strong&gt;. &lt;br&gt;
Outra situação que chama atenção nesse método é a utilização de um &lt;strong&gt;StringBuilder&lt;/strong&gt; efêmero utilizado para concatenar as strings. Apesar do StringBuilder ser ótimo para evitar a criação desnecessária de strings, neste caso ele gera um impacto negativo devido sua frequência de criação e descarte. Portanto, nessa correção o AppendJoin do StringBuilder foi substituído por um string.Join e o ToString do final do método foi removido. Essa mudança reduziu a quantidade de alocações de duas (criação do StringBuilder + nova string utilizando ToString) para uma (nova string utilizando Join).&lt;/p&gt;

&lt;p&gt;O código do método ConvertToCsv refatorado fica assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;ConvertToCsv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;   
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;";"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Marca&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Ano&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Modelo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QtdPortas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Motor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Após essa alteração, rodei novamente a aplicação e obtive o seguinte resultado:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fah8gk7goviebqkmog2yj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fah8gk7goviebqkmog2yj.png" alt="segunda execução" width="667" height="205"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;É possível notar uma redução de 200Mb de memória ou 17% de ganho em relação a primeira operação. Ainda sim, não parece ser uma melhoria satisfatória, visto que a aplicação ainda utiliza 1Gb de ram para gerar um arquivo de 65Mb (aproximadamente 16x mais).&lt;/p&gt;

&lt;h3&gt;
  
  
  Otimizando a utilização do StringBuilder do método GenerateInMemoryCsv
&lt;/h3&gt;

&lt;p&gt;Conforme comentado anteriormente, a aplicação possuía diversos StringBuilders mal utilizados e em sua maioria desnecessários. O StringBuilder do método GenerateInMemoryCsv é o único caso útil para o fluxo e encontra-se subutilizado. Contudo, a forma atual de sua utilização, concatenar o cabeçalho com o corpo, gera o mesmo resultado de uma concatenação de string simples e com alocação de memória semelhante. Portanto o código deve ser alterado para melhor aproveitar esse StringBuilder.&lt;/p&gt;

&lt;p&gt;Realizando a mudança do código para melhor aproveitamento do StringBuilder o método ficaria assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GenerateInMemoryCsv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Vehicle&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;vehicles&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;headerFields&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;  &lt;span class="n"&gt;Vehicle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetHeaderFields&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;    
   &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;";"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headerFields&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="n"&gt;StringBuilder&lt;/span&gt; &lt;span class="n"&gt;csvInMemory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StringBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="n"&gt;csvInMemory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AppendJoin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\n"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vehicles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertToCsv&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;

   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;csvInMemory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;    
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Obs: Poderíamos realizar o AppendJoin dos campos de header direto no StringBuilder e evitar uma alocação extra de string, porém essa otimização aqui não compensa. Preferi manter a legibilidade do código do que ganhar alguns Kb nessa operação.&lt;br&gt;&lt;br&gt;
Esse tipo de escolha também faz parte do processo de otimização, pois evita gastar energia onde não haverá melhorias expressivas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Rodando novamente o código obtive o seguinte resultado:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flae9ecvspjzdwtkhk56i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flae9ecvspjzdwtkhk56i.png" alt="terceira execução" width="665" height="190"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Agora sim uma redução de memória expressiva. A aplicação reduziu o consumo em aproximadamente 750Mb ou 60% em relação a implementação original.&lt;/p&gt;

&lt;p&gt;Com toda essa redução de consumo fica a pergunta&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Será é possível diminuir a alocação de memória ainda mais?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Nem toda otimização traz benefícios
&lt;/h2&gt;

&lt;p&gt;Com as melhorias no fluxo mais crítico concluídas e ainda sobrando um tempo, resolvi revisitar a primeira rampa de memória e descobri que essa alocação é gerada pela obtenção dos registros no banco de dados. Revisando o método de obtenção dos dados, notei que mesmo utilizando um IEnumerable ocorria essa alocação de memória expressiva. Supus que ocorria a alocação de uma lista por baixo dos panos (viva o polimorfismo). No método implementado não existia o uso do ToList, portanto a alocação deveria ocorrer no método Query do &lt;a href="https://github.com/DapperLib/Dapper" rel="noopener noreferrer"&gt;Dapper&lt;/a&gt;. Olhando os parâmetros do método Query encontrei o parâmetro chamado buffered(opcional). O buffered é utilizado para decidir se o resultado da query deve ser carregado numa lista em memória ou não. Por padrão esse parâmetro é true, ou seja, cria a lista em memória. Buscando o código do método Query na lib, é possível ter uma ideia do que acontece:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;IDbConnection&lt;/span&gt; &lt;span class="n"&gt;cnn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IDbTransaction&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;buffered&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;commandTimeout&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CommandType&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;commandType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;CommandDefinition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;commandTimeout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;commandType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buffered&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;CommandFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Buffered&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CommandFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QueryImpl&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;cnn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Buffered&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Nesse caso usei o disassembly do próprio visual studio, mas é possível obter o código a partir do repositório do github&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Método ToList encontrado! Quando o parâmetro buffered é passado como true o método Query devolve um List mesmo que o IEnumerable seja retornado.&lt;/p&gt;

&lt;p&gt;Resolvi passar o valor dessa variável como &lt;strong&gt;false&lt;/strong&gt; e realizar um nova execução. O resultado foi mais surpreendente do que o esperado. O gráfico abaixo mostra a diferença de alocação de memória:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0g7usqnv0e711r8lmsdk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0g7usqnv0e711r8lmsdk.png" alt="quarta execução" width="668" height="199"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tivemos uma queda de 64% no consumo de memória(306Mb) em relação a execução anterior. Inclusive o processador teve um pequeno ganho (não calculado). No entanto, o tempo da execução cresceu 2,5x, pois agora toda operação realizada sobre os resultados necessita iterar sobre essa lista. No processo existem pelo menos 3 operações na lista (Any, Count e Geração do CSV). Mesmo eliminando ou remanejando o Count, o tempo de execução segue alto. Outro ponto bastante preocupante é o risco de uma desconexão com o banco ocasionar um erro no processo.&lt;/p&gt;

&lt;p&gt;Para o cenário apresentado, o tempo de execução e a confiabilidade da execução também eram requisitos importantes. Portanto, por mais que essa otimização reduza bastante a quantidade de memória alocada, ela não compensa pelos dois pontos mencionados.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ideias de evolução
&lt;/h2&gt;

&lt;p&gt;A trilha de otimização dessa aplicação gerou um resultado satisfatório, porém distante do ideal. Boa parte do trabalho de otimização poderia ser atingido mudando a forma como o arquivo é gerado e transferido. &lt;/p&gt;

&lt;p&gt;A primeira ideia é salvar o arquivo localmente antes de envia-lo para o destino. Essa abordagem faz o consumo de memória ficar muito próximo ao da otimização de leitura direto do banco (sem buffer), pois não seria necessário criar todo o arquivo em memória antes da transferência. Extrapolando a ideia, poderia ser feita a leitura da informação direto do banco, transformar cada linha e salvar direto no arquivo. É óbvio que outros tipos de decisão e controle deveriam ser tomados, mas isso faz parte do processo de otimização.&lt;/p&gt;

&lt;p&gt;Outra ideia que tive durante esse processo e que ainda carece de estudos e testes é utilizar stream de dados e gravar o documento direto no destino, sem a necessidade de gerar um arquivo local ou construir todo o arquivo em memória. Algumas dúvidas que teriam que ser respondidas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;O C# permite tal abordagem apontando para um servidor remoto?&lt;/li&gt;
&lt;li&gt;O que fazer em caso de falha de comunicação com servidor remoto durante o processo de escrita?&lt;/li&gt;
&lt;li&gt;Faria a escrita do arquivo em blocos de x registros ou tudo de uma vez?&lt;/li&gt;
&lt;li&gt;Escrevendo o arquivo em blocos, em caso de falha, iniciar todo o processo novamente ou ter alguma forma de continuar onde parou?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O projeto está disponível no github para quem desejar baixar e conferir a implementação e os testes executados&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/julianopoveda/export_file" rel="noopener noreferrer"&gt;https://github.com/julianopoveda/export_file&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Como foi mostrado nesse post, pequenas melhorias no código podem trazer grandes vantagens na alocação de recursos. Já outras soluções podem trazer melhorias de um lado, agregando mais risco e exigindo novos controles para a aplicação.&lt;/p&gt;

&lt;p&gt;Por fim, uma questão que pode ter sido levantada na mente do leitor é o fato de eu ter focado exclusivamente na alocação de memória e não ter me preocupado com o uso da CPU. Tal decisão foi tomada lá no inicio da análise ao descobrir que a aplicação lida muito com IO (consulta no banco, alocação de memória, transferência do arquivo) e pouco com CPU. A medida que a correção ia evoluindo, o uso de CPU manteve-se estável, provando que estávamos trabalhando com uma aplicação de pouco processamento.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ko-fi.com/R6R119R3QG" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstorage.ko-fi.com%2Fcdn%2Fkofi6.png%3Fv%3D6" alt="Buy Me a Coffee at ko-fi.com" width="580" height="146"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Referências
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/strings/#immutability-of-strings" rel="noopener noreferrer"&gt;Documentação do tipo string&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>csharp</category>
      <category>performance</category>
    </item>
    <item>
      <title>Podman + Windows: Resolvendo erro "No connection could be made because the target machine actively refused it"</title>
      <dc:creator>Poveda</dc:creator>
      <pubDate>Wed, 10 Jul 2024 11:47:40 +0000</pubDate>
      <link>https://dev.to/poveda/podman-windows-resolvendo-erro-no-connection-could-be-made-because-the-target-machine-actively-refused-it-142l</link>
      <guid>https://dev.to/poveda/podman-windows-resolvendo-erro-no-connection-could-be-made-because-the-target-machine-actively-refused-it-142l</guid>
      <description>&lt;p&gt;Enquanto estava estudando para escrever o post &lt;a href="https://dev.to/poveda/wsl-gerenciando-o-disco-da-distro-ld1"&gt;WSL: Gerenciando o disco da distro&lt;/a&gt; precisei reiniciar as distros do WSL algumas vezes. Entre essas distros estava a VM utilizada pelo &lt;a href="https://podman-desktop.io/" rel="noopener noreferrer"&gt;Podman Desktop&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Qual foi a minha surpresa quando no dia seguinte precisei utilizar o podman e recebi a seguinte mensagem&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Cannot connect to Podman. Please verify your connection to the Linux system using &lt;code&gt;podman system connection list&lt;/code&gt;, or try &lt;code&gt;podman machine init&lt;/code&gt; and &lt;code&gt;podman machine start&lt;/code&gt; to manage a new Linux VM&lt;br&gt;
Error: unable to connect to Podman socket: failed to connect: dial tcp 127.0.0.1:63708: connectex: No connection could be made because the target machine actively refused it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Num primeiro momento tentei parar e subir a VM novamente com os comandos &lt;code&gt;podman machine stop&lt;/code&gt; e &lt;code&gt;podman machine start&lt;/code&gt; porém sem sucesso. Depois disso resolvi ler a mensagem de erro em busca mais pistas. A mensagem dizia para rodar o comando &lt;code&gt;podman system connection list&lt;/code&gt; e validar se o podman esta escutando na porta mencionada.&lt;/p&gt;

&lt;p&gt;Rodando o comando a saída confirmou que porta 63708 estava sendo utilizada pela VM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;podman&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;system&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="w"&gt;                         &lt;/span&gt;&lt;span class="nx"&gt;URI&lt;/span&gt;&lt;span class="w"&gt;                                                &lt;/span&gt;&lt;span class="nx"&gt;Identity&lt;/span&gt;&lt;span class="w"&gt;                                                        &lt;/span&gt;&lt;span class="nx"&gt;Default&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nx"&gt;ReadWrite&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;podman-machine-default&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nx"&gt;ssh://root&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;127.0.0.1:64624/run/podman/podman.sock&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;~\.local\share\containers\podman\machine\machine&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;false&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nx"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;podman-machine-default-root&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;ssh://root&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;127.0.0.1:63708/run/podman/podman.sock&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;~\.local\share\containers\podman\machine\machine&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;true&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Obs: Os caminhos do identity foram encurtados para facilitar a leitura&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ainda sem ideia sobre o que fazer resolvi olhar o que mais a mensagem dizia. A outra opção sugerida pela mensagem era subir uma nova VM do podman para solucionar o problema, entretanto essa era uma opção que não desejava executar num primeiro momento pois tenho alguns pods parados e imagens salvas no cache que demorariam muito para baixar novamente (ex: sql server).&lt;/p&gt;

&lt;p&gt;Com o cenário desenhado, iniciei as pesquisas para tentar solucionar o problema. Encontrei a &lt;a href="https://github.com/containers/podman/issues/19554" rel="noopener noreferrer"&gt;"issue No connection could be made because the target machine actively refused it"&lt;/a&gt; e tentei a maioria das soluções propostas na issue porém sem sucesso. Inclusive vi que &lt;a href="https://github.com/containers/podman/pull/19557" rel="noopener noreferrer"&gt;implementaram uma correção&lt;/a&gt; para o podman e que também não resolveu meu problema 😢.&lt;/p&gt;

&lt;p&gt;Voltei novamente para as informações fornecidas pelo podman e tive um estalo:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"O podman desktop se comunica com a VM via SSH. Será que a porta 63708 está habilitada no serviço"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Com essa suspeita acessei a distro do podman e abri o arquivo &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt; no editor de texto. Indo para o final do arquivo constatei que somente a porta 64624 estava habilitada para acesso ssh. Então resolvi adicionar a porta 63708. O arquivo que ficou da seguinte forma após editado&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
# override default of no subsystems
Subsystem       sftp    /usr/libexec/openssh/sftp-server

# Example of overriding settings on a per-user basis
#Match User anoncvs
#       X11Forwarding no
#       AllowTcpForwarding no
#       PermitTTY no
#       ForceCommand cvs server
Port 64624
Port 63708
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois de salvar a alteração o próximo passo foi reiniciar o serviço do ssh com o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart sshd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aguardei uns segundos e rodei o comando &lt;code&gt;systemctl status sshd&lt;/code&gt; a fim de validar se o serviço havia iniciado. O resultado do comando  comprova que o serviço estava rodando sem problemas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;● sshd.service - OpenSSH server daemon
     Loaded: loaded &lt;span class="o"&gt;(&lt;/span&gt;/usr/lib/systemd/system/sshd.service&lt;span class="p"&gt;;&lt;/span&gt; enabled&lt;span class="p"&gt;;&lt;/span&gt; preset: enabled&lt;span class="o"&gt;)&lt;/span&gt;
    Drop-In: /usr/lib/systemd/system/service.d
             └─10-timeout-abort.conf
     Active: active &lt;span class="o"&gt;(&lt;/span&gt;running&lt;span class="o"&gt;)&lt;/span&gt; since Wed 2024-07-03 21:02:01 &lt;span class="nt"&gt;-03&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 3s ago
       Docs: man:sshd&lt;span class="o"&gt;(&lt;/span&gt;8&lt;span class="o"&gt;)&lt;/span&gt;
             man:sshd_config&lt;span class="o"&gt;(&lt;/span&gt;5&lt;span class="o"&gt;)&lt;/span&gt;
   Main PID: 7207 &lt;span class="o"&gt;(&lt;/span&gt;sshd&lt;span class="o"&gt;)&lt;/span&gt;
      Tasks: 1 &lt;span class="o"&gt;(&lt;/span&gt;limit: 4697&lt;span class="o"&gt;)&lt;/span&gt;
     Memory: 1.3M
        CPU: 12ms
     CGroup: /system.slice/sshd.service
             └─7207 &lt;span class="s2"&gt;"sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups"&lt;/span&gt;

Jul 03 21:02:01 PovedaRyzen systemd[1]: Starting sshd.service - OpenSSH server daemon...
Jul 03 21:02:01 PovedaRyzen &lt;span class="o"&gt;(&lt;/span&gt;sshd&lt;span class="o"&gt;)[&lt;/span&gt;7207]: sshd.service: Referenced but &lt;span class="nb"&gt;unset &lt;/span&gt;environment variable evaluates to an empty string: OPTIONS
Jul 03 21:02:01 PovedaRyzen sshd[7207]: Server listening on 0.0.0.0 port 63708.
Jul 03 21:02:01 PovedaRyzen sshd[7207]: Server listening on :: port 63708.
Jul 03 21:02:01 PovedaRyzen sshd[7207]: Server listening on 0.0.0.0 port 64624.
Jul 03 21:02:01 PovedaRyzen sshd[7207]: Server listening on :: port 64624.
Jul 03 21:02:01 PovedaRyzen systemd[1]: Started sshd.service - OpenSSH server daemon.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com o ssh liberado para a porta 63708, rodei alguns comandos a fim de validar a conexão. Para a minha felicidade os resultados foram esses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;podman ps &lt;span class="nt"&gt;-a&lt;/span&gt;
CONTAINER ID  IMAGE                                                  COMMAND               CREATED      STATUS                    PORTS       NAMES
5a6ba726847e  localhost/podman-pause:5.1.0-dev-4817811cb-1713312000                        3 weeks ago  Exited &lt;span class="o"&gt;(&lt;/span&gt;0&lt;span class="o"&gt;)&lt;/span&gt; 292 years ago              234f8433dbf7-infra
9fecc6f0544a  docker.io/library/nginx:latest                         nginx &lt;span class="nt"&gt;-g&lt;/span&gt; daemon o...  3 weeks ago  Exited &lt;span class="o"&gt;(&lt;/span&gt;0&lt;span class="o"&gt;)&lt;/span&gt; 292 years ago              nginx-nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;podman images
REPOSITORY                           TAG                             IMAGE ID      CREATED       SIZE
localhost/podman-pause               5.1.0-dev-4817811cb-1713312000  d3af6c318a9d  3 weeks ago   1.14 MB
docker.io/library/nginx              latest                          4f67c83422ec  5 weeks ago   192 MB
docker.io/julianopoveda/readonlyapi  v1                              ac7c4054326e  2 months ago  120 MB
docker.io/kindest/node               &amp;lt;none&amp;gt;                          09c50567d34e  4 months ago  962 MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Por algum motivo que não consegui descobrir o real motivo da porta ter se tornado incomunicável. Essa questão dificultou bastante a busca de uma solução, pois é bem provável que alguém já passou por esse problema e reportou em algum lugar como solucionar.&lt;/p&gt;

&lt;p&gt;No fim tive que contar com a minha experiência e memória para resolver o problema, sem o auxilio de uma fonte externa. E esse é um dos motivos pelos quais tenho escrito esses posts, ter uma base de solução de problemas documentada tanto online quanto offline.&lt;/p&gt;

&lt;p&gt;Uma última curiosidade: enquanto buscava algumas informações para enriquecer esse post descobri que poderia ter trocado a porta default de comunicação para a porta utilizada pelo rootless usando o comando &lt;code&gt;podman system connection default podman-machine-default&lt;/code&gt;. Esse comando teria resolvido o problema de forma bem mais simples, visto que a porta 64624 estava aberta no sshd.&lt;/p&gt;

&lt;h3&gt;
  
  
  Referências
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://podman-desktop.io/docs/podman/accessing-podman-from-another-wsl-instance" rel="noopener noreferrer"&gt;Acessar instância do podman por outra distro wsl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/containers/podman/issues/19554" rel="noopener noreferrer"&gt;Issue #19554: No connection could be made because the target machine actively refused it&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/containers/podman/pull/19557" rel="noopener noreferrer"&gt;Fix: Implement automatic port reassignment on Windows&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>WSL: Gerenciando o disco da distro</title>
      <dc:creator>Poveda</dc:creator>
      <pubDate>Tue, 18 Jun 2024 11:00:00 +0000</pubDate>
      <link>https://dev.to/poveda/wsl-gerenciando-o-disco-da-distro-ld1</link>
      <guid>https://dev.to/poveda/wsl-gerenciando-o-disco-da-distro-ld1</guid>
      <description>&lt;p&gt;Quando se trabalha com softwares pesados, geralmente é necessária uma quantidade considerável de espaço em disco a fim de armazenar todas as configurações e módulos para sua execução. Com o WSL não é diferente, afinal trata-se de um SO extra instalado na máquina. Para que seja possível realizar a instalação desse novo SO, o Windows cria um HD de tamanho variável (VHDX) no qual conterá todos os arquivos do SO e todos os programas e arquivos instalados posteriormente.&lt;/p&gt;

&lt;p&gt;De acordo com a própria &lt;a href="https://learn.microsoft.com/en-us/windows/wsl/disk-space#how-to-check-your-available-disk-space" rel="noopener noreferrer"&gt;documentação da Microsoft&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O tamanho do disco será de 1TB para as versões mais recentes do WSL2 e 512Gb ou 256GB para versões mais antigas.&lt;br&gt;
O tamanho do disco exibido é seu tamanho máximo, ainda que este espaço não esteja realmente alocado. VHD expandirá seu tamanho a medida do seu uso.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Quando é realizada a instalação do SO no WSL, por padrão o Windows cria o VHD no mesmo HD onde o próprio Windows está instalado (C:). Muitas vezes o tamanho deste disco é insuficiente para comportar um VHD tão grande e em constante expansão.&lt;/p&gt;

&lt;p&gt;Utilizando o meu próprio HD como exemplo é possível observar que o disco está quase esgotado:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyyxkhas5okcleggvqv4w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyyxkhas5okcleggvqv4w.png" alt="O espaço livre no disco atual é de 2.25GB" width="259" height="67"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Analisando a alocação do disco nota-se que o SO instalado no WSL ocupa em torno de 25% de espaço:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk2fp96qnjqia6xlkvufu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk2fp96qnjqia6xlkvufu.png" alt="O tamanho da distro Ubuntu no WSL ocupa 63.9GB no disco" width="800" height="72"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Neste post vou abordar duas propostas de como recuperar mais espaço em disco: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Realizando a compactação do disco&lt;/li&gt;
&lt;li&gt;Movendo a distro para outro HD&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Compactar o disco
&lt;/h2&gt;

&lt;p&gt;Esta opção é indicada para quem utiliza o WSL como servidor para algum container engine (docker, podman) ou para quem manipula muitos arquivos (cria, copia, exclui). Ela é aplicável independente de onde o VHD está salvo.&lt;/p&gt;

&lt;p&gt;Para efetuar a compactação do disco é necessário desligar a distro.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;wsl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--shutdown&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Obs: esse comando desliga todas as distros. Não é possível utilizar o comando terminate pois ele não libera o VHD para manipulação externa.&lt;/p&gt;

&lt;p&gt;Para reiniciar as distros basta rodar o comando &lt;code&gt;wsl -d &amp;lt;distro-name&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Para descobrir quais distros estão instaladas na máquina e seus respectivos status basta rodar o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;wsl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-v&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O resultado será parecido com esse:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="nx"&gt;STATE&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="nx"&gt;VERSION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ubuntu&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;Stopped&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="nx"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;podman-machine-default&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Stopped&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="nx"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;docker-desktop-data&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nx"&gt;Stopped&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="nx"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em seguida será necessário obter o local onde o VHD está armazenado. Por padrão o Windows adiciona todos os arquivos necessários para rodar a distro dentro de um diretório armazenado na pasta &lt;code&gt;C:\Users\%USERNAME%\AppData\Local\Packages&lt;/code&gt;. Existem algumas formas de encontrar o diretório da distro:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Rodando o comando &lt;code&gt;(Get-ChildItem -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\Lxss | Where-Object { $_.GetValue("DistributionName") -eq '&amp;lt;distribution-name&amp;gt;' }).GetValue("BasePath") + "\ext4.vhdx"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Acessar a pasta &lt;code&gt;C:\Users\%USERNAME%\AppData\Local\Packages&lt;/code&gt; e procurar pelo nome do pacote da distro

&lt;ol&gt;
&lt;li&gt;Para distros Ubuntu os arquivos estão localizados em pastas com o padrão &lt;code&gt;CanonicalGroupLimited.Ubuntuon*&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Usar a pesquisa de arquivos dentro da pasta &lt;code&gt;C:\Users\%USERNAME%\AppData\Local\Packages&lt;/code&gt; para buscar todos os &lt;code&gt;ext4.*&lt;/code&gt; disponíveis e validar qual é o caminho que contém o VHD da distro desejada.&lt;/li&gt;

&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;No meu caso a primeira opção não funcionou em nenhuma das duas máquinas das quais testei.&lt;br&gt;
No fim não encontrei uma forma fácil de encontrar os VHD's que são criados por distros instaladas diretamente pela Microsoft Store. Outras VMs criadas por outros programas, como o podman possuem comandos que facilitam a localização do VHD utilizado.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Uma vez encontrado o caminho do VHD será necessário abrir o powershell/terminal em modo administrador e executar o seguinte comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Optimize-VHD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"C:\Users\&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;UserName&lt;/span&gt;&lt;span class="s2"&gt;\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc\LocalState\ext4.vhdx"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Mode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Full&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explicando:&lt;/p&gt;

&lt;p&gt;O comando &lt;strong&gt;Optimize-VHD&lt;/strong&gt; serve para otimizar a alocação de espaço em VHDs de tamanho dinâmico, isto é, que expandem seu tamanho no decorrer do uso até o tamanho máximo definido.&lt;/p&gt;

&lt;p&gt;A opção &lt;strong&gt;Mode&lt;/strong&gt; serve para definir o nível de otimização. No meu caso testei com as opções &lt;strong&gt;Quick&lt;/strong&gt; e &lt;strong&gt;Full&lt;/strong&gt;. Abaixo explico a diferença de cada uma:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quick: desaloca os blocos não usados do disco, porém não procura por zero blocks&lt;/li&gt;
&lt;li&gt;Full: Busca por zero blocks e desaloca blocos não utilizados.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;As demais opções podem ser encontradas documentação oficial(tem nas referências 😉)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Rodando o comando com &lt;code&gt;-Mode Quick&lt;/code&gt; obtive a seguinte redução:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3615f9gpbvntvsuubmar.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3615f9gpbvntvsuubmar.png" alt="Otimização com a opção Quick reduziu o tamanho do VHD em 13.2GB" width="800" height="62"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rodando o comando com &lt;code&gt;-Mode Full&lt;/code&gt; obtive a seguinte redução:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6dbv0kb9bbx2h3e81jk2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6dbv0kb9bbx2h3e81jk2.png" alt="Otimização com a opção Full reduziu o tamanho do VHD em 13.7GB" width="800" height="56"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Obs: O comando com -Mode Full foi rodado após ter rodado o comando com o -Mode Quick. Esse é o motivo da diferença parecer pequena de um comando para o outro.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Após executar o processo de otimização do VHD o espaço disponível no HD aumentou aproximadamente 14Gb:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5m40matg4f0jgq9haaly.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5m40matg4f0jgq9haaly.png" alt="Espaço livre no HD após recuperar blocos não usados pelo VHD foi de 14GB" width="264" height="71"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Vantagens da abordagem
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Poucos passos&lt;/li&gt;
&lt;li&gt;Manter o registro do SO baixado pela Microsoft Store, beneficiando-se dos clis instalados junto com as distros.&lt;/li&gt;
&lt;li&gt;Não necessita de armazenamento extra&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Desvantagens da abordagem
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Inefetivo quando todo espaço reservado pelo VHD está ocupado&lt;/li&gt;
&lt;li&gt;Dependendo do uso é necessário executar o procedimento com frequência de forma manual ou automatizada&lt;/li&gt;
&lt;li&gt;Dificuldade de encontrar o caminho do VHD do SO desejado&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  2. Exportar o VHD para outro disco
&lt;/h2&gt;

&lt;p&gt;Esta opção é indicada para cenários onde é necessário ou desejado mover a distro para outro HD com mais capacidade ou reservado para isso.&lt;/p&gt;

&lt;p&gt;Ao término da execução desse processo, o espaço ocupado no meu HD principal reduziu consideravelmente.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwdh13c7zb9pq3mmyesg7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwdh13c7zb9pq3mmyesg7.png" alt="HD principal está com 66.2GB de espaço livre. O tamanho ocupado reduziu em 63.95GB" width="260" height="63"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  2.1 Exportar o disco
&lt;/h3&gt;

&lt;p&gt;O primeiro passo é desligar a distro desejada. Esse passo é essencial para garantir que nada esta sendo gravado durante a cópia dos arquivos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight postscript"&gt;&lt;code&gt;&lt;span class="nf"&gt;wsl&lt;/span&gt; &lt;span class="nf"&gt;--terminate&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nf"&gt;distro-name&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;alternativamente o comando &lt;code&gt;wsl --shutdown&lt;/code&gt; pode ser utilizado para desligar todas as distros&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O próximo passo é rodar o comando de exportar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;wsl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;distro-name&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;path-destino-com-nome&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;vhdx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--vhd&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explicando:&lt;/p&gt;

&lt;p&gt;O comando exporta a distro para o arquivo vhdx indicado. A opção --vhd é opcional, porém será útil para os próximos passos. Caso a opção --vhd não seja informada, um arquivo &lt;strong&gt;.tar&lt;/strong&gt; será gerado. Ambos os formatos de arquivo servem para a etapa de import.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.2 Importando e registrando a distro no WSL
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Importante: Nomes repetidos não são permitidos pois os nomes funcionam como o identificador da distro para com o WSL. Portanto, se for necessário manter o nome da distro original, primeiro deve ser feito o desregistro da distro anterior. Nesse caso a ordem de execução fica: 2.3, 2.2, 2.4&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Com o disco exportado existem duas formas de importar a distro no WSL:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Carregando uma cópia do HD com o comando &lt;strong&gt;import&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Utilizando o próprio VHD exportado com o comando &lt;strong&gt;import-in-place&lt;/strong&gt; (só funciona para arquivos &lt;strong&gt;.vhdx&lt;/strong&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A primeira forma consiste em rodar o comando import de acordo com o exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;wsl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;distro-name&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;path-instalacao-distro&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;path-disco-exportado&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;vhdx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--vhd&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explicando:&lt;/p&gt;

&lt;p&gt;Este comando restaurará uma cópia do disco exportado no local informado e o registrará a distro no WSL com o nome informado. A opção --vhd serve para informar que o arquivo utilizado é um VHD ao invés de um &lt;strong&gt;.tar&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A segunda forma de importação só funciona para arquivos do tipo &lt;strong&gt;.vhdx&lt;/strong&gt;. Para realizar esse processo basta executar o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wsl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--import-in-place&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;distro-name&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;path-disco-exportado&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;vhdx&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explicando:&lt;/p&gt;

&lt;p&gt;Este comando registrará a distro no WSL com o nome informado, utilizando o VHD como o disco daquela distro. Então ao contrário do comando &lt;code&gt;wsl --import&lt;/code&gt;, esse comando utiliza o vhd diretamente e é por este motivo que a exportação precisa da opção --vhd.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.3 Desregistrando a distro antiga
&lt;/h3&gt;

&lt;p&gt;Com a distro registrada em outro HD, o próximo passo é remover a distro antiga do HD principal. Para desregistrar a distro atual, rodar o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight postscript"&gt;&lt;code&gt;&lt;span class="nf"&gt;wsl&lt;/span&gt; &lt;span class="nf"&gt;--unregister&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nf"&gt;distro-name&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Executando o comando acima todas as configurações dessa distro serão removidas do HD principal.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.4 Definindo a distro como padrão e restaurando o usuário principal
&lt;/h3&gt;

&lt;p&gt;Apesar de todo o trabalho feito até o momento existem alguns pontos que precisam ser ajustados quando necessário.&lt;/p&gt;

&lt;p&gt;O primeiro deles é definir a distro como padrão rodando o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight postscript"&gt;&lt;code&gt;&lt;span class="nf"&gt;wsl&lt;/span&gt; &lt;span class="nf"&gt;--set-default&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nf"&gt;distro-name&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O segundo ajuste é redefinir o usuário principal. Ao exportar a distro e (re)importá-la o usuário padrão é redefinido para root. Para redefinir o usuário para o usuário anteriormente criado na distro será necessário criar o arquivo &lt;strong&gt;wsl.config&lt;/strong&gt; dentro da distro contendo a estrutura abaixo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;[&lt;span class="n"&gt;user&lt;/span&gt;]
&lt;span class="n"&gt;default&lt;/span&gt;=&amp;lt;&lt;span class="n"&gt;username&lt;/span&gt;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;este arquivo deve ser salvo no caminho &lt;code&gt;/etc/&lt;/code&gt; (lembrar que escrever na pasta etc exige &lt;code&gt;sudo&lt;/code&gt;). Após salvar o arquivo, reiniciar a máquina utilizando os comandos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight postscript"&gt;&lt;code&gt;&lt;span class="nf"&gt;wsl&lt;/span&gt; &lt;span class="nf"&gt;--terminate&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nf"&gt;distro-name&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;#desliga&lt;/span&gt; &lt;span class="nf"&gt;a&lt;/span&gt; &lt;span class="nf"&gt;máquina&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight postscript"&gt;&lt;code&gt;&lt;span class="nf"&gt;wsl&lt;/span&gt; &lt;span class="nf"&gt;-d&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nf"&gt;distro-name&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;#inicia&lt;/span&gt; &lt;span class="nf"&gt;a&lt;/span&gt; &lt;span class="nf"&gt;máquina&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Vantagens da abordagem
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Pode ser utilizada para importar qualquer distro, inclusive de outros computadores ou backups&lt;/li&gt;
&lt;li&gt;Pode ser utilizada junto com o método de Compactação de disco (Optimize-VHD)&lt;/li&gt;
&lt;li&gt;Libera todo o espaço do VHD do HD principal&lt;/li&gt;
&lt;li&gt;Não é necessário saber o local físico onde a distro está instalada.&lt;/li&gt;
&lt;li&gt;Capacidade de utilizar os cli's junto a Microsoft Store caso o nome da distro importada seja igual a distro original&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Desvantagens da abordagem
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Requer espaço extra em outro HD&lt;/li&gt;
&lt;li&gt;Necessita ajustes adicionais&lt;/li&gt;
&lt;li&gt;Perda da capacidade de utilizar as cli's baixadas junto a Microsoft Store caso o nome da distro importada seja diferente da distro original&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Referências
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/powershell/module/hyper-v/optimize-vhd?view=windowsserver2022-ps" rel="noopener noreferrer"&gt;Documentação do comando Optimize-VHD&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/windows/wsl/disk-space" rel="noopener noreferrer"&gt;Como gerenciar o espaço em disco do WSL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://winaero.com/export-import-wsl-linux-distro-windows-10/" rel="noopener noreferrer"&gt;Import export distro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://superuser.com/a/1627461" rel="noopener noreferrer"&gt;Definir um usuário padrão na distro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/windows/wsl/wsl-config#user-settings" rel="noopener noreferrer"&gt;wsl.conf - WSL advanced settings&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>wsl</category>
    </item>
    <item>
      <title>Podman + minikube</title>
      <dc:creator>Poveda</dc:creator>
      <pubDate>Sat, 30 Apr 2022 04:15:25 +0000</pubDate>
      <link>https://dev.to/poveda/podman-minikube-32e2</link>
      <guid>https://dev.to/poveda/podman-minikube-32e2</guid>
      <description>&lt;p&gt;Agora que já instalamos o podman no WSL é hora de começar a briga para fazer o kubernetes usar o podman no lugar do docker. Neste post vou instalar e configurar o &lt;a href="https://minikube.sigs.k8s.io/docs/" rel="noopener noreferrer"&gt;minikube&lt;/a&gt; pelo fato dele ser a distribuição mais popular de kubernetes para ambiente de desenvolvimento.&lt;/p&gt;

&lt;p&gt;Para fazer o podman rodar em conjunto com o minikube, precisaremos instalar 3 ferramentas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O próprio minikube&lt;/li&gt;
&lt;li&gt;O kubectl&lt;/li&gt;
&lt;li&gt;Um runtime (escolhi o CRI-O)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Como o post ficou grande e cheio de seções que podem ser puladas dependendo do que já esta instalado a configurado na máquina, julguei necessário colocar um índice.&lt;/p&gt;

&lt;p&gt;De nada 😉&lt;/p&gt;

&lt;h2&gt;
  
  
  Índice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Índice&lt;/li&gt;
&lt;li&gt;
Entendendo os conceitos de driver e runtime

&lt;ul&gt;
&lt;li&gt;Runtime&lt;/li&gt;
&lt;li&gt;Driver&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Instalando o minikube&lt;/li&gt;

&lt;li&gt;Instalando o kubectl&lt;/li&gt;

&lt;li&gt;Instalando o CRI-O&lt;/li&gt;

&lt;li&gt;

Rodando o minikube

&lt;ul&gt;
&lt;li&gt;Adiconando o Podman ao sudoers&lt;/li&gt;
&lt;li&gt;Erro ao executar o minikube&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Deploy da aplicação

&lt;ul&gt;
&lt;li&gt;Adicionando a imagem ao cache do minikube&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Criando a service&lt;/li&gt;

&lt;li&gt;

Expondo a aplicação para fora do Kubernetes

&lt;ul&gt;
&lt;li&gt;Minikube Service&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Acessando a aplicação fora do WSL&lt;/li&gt;

&lt;li&gt;Alternativa rootless para o minikube&lt;/li&gt;

&lt;li&gt;Impressões e Conclusão&lt;/li&gt;

&lt;li&gt;Referencias&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Entendendo os conceitos de driver e runtime
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Sessão opcional: se você já entende o que são os conceitos de driver e runtime ou quer ir direto para a instalação pode pular para a instalação do minikube&lt;br&gt;
Antes de começar com o hands on de verdade, primeiro é necessário entender o básico de driver e runtime no mundo de containers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Runtime
&lt;/h3&gt;

&lt;p&gt;O runtime é responsável por controlar todo o ciclo de vida do container. Isso vai desde baixar um container até rodá-lo.&lt;br&gt;
&lt;a href="https://medium.com/techbeatly/container-runtimes-deep-dive-77eb0e511939" rel="noopener noreferrer"&gt;Este artigo&lt;/a&gt; escrito por &lt;a href="https://nivedv.medium.com/" rel="noopener noreferrer"&gt;Nived Velayudhan&lt;/a&gt; aprofunda mais sobre o assunto. Também vale mencionar a &lt;a href="https://github.com/opencontainers/runtime-spec/blob/main/spec.md" rel="noopener noreferrer"&gt;própria documentação oficial da especificação do runtime&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Driver
&lt;/h3&gt;

&lt;p&gt;O driver é responsável por prover o conjunto de apis nas quais o usuário irá interagir com o ecossistema de containers. Em resumo, provê os comandos usados nos CLIs e interfaces gráficas.&lt;/p&gt;
&lt;h2&gt;
  
  
  Instalando o minikube
&lt;/h2&gt;

&lt;p&gt;Para instalar a minikube não tem muito mistério, vamos seguir a &lt;a href="https://minikube.sigs.k8s.io/docs/start/" rel="noopener noreferrer"&gt;documentação oficial&lt;/a&gt;.&lt;br&gt;
Existem 2 formas de instalar para quem usa distribuições baseadas em debian (meu caso): baixando os binários ou baixando o pacote debian. No tutorial vou mostrar como instalar utilizando o pacote debian, pois foi a forma que eu instalei.&lt;/p&gt;

&lt;p&gt;O primeiro passo é rodar o comando curl e baixar a última versão:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-LO&lt;/span&gt; https://storage.googleapis.com/minikube/releases/latest/minikube_latest_amd64.deb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em seguida instalar o pacote:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;dpkg &lt;span class="nt"&gt;-i&lt;/span&gt; minikube_latest_amd64.deb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pronto! Minikube instalado&lt;/p&gt;

&lt;h2&gt;
  
  
  Instalando o kubectl
&lt;/h2&gt;

&lt;p&gt;Não podemos executar nossos comandos kubernetes sem a ferramenta que serve para isso.&lt;br&gt;
Novamente indo para a &lt;a href="https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/" rel="noopener noreferrer"&gt;documentação oficial&lt;/a&gt;, basta seguir os passos informados lá. Para o meu caso utilizei o passo-a-passo do Ubuntu.&lt;/p&gt;

&lt;p&gt;Primeiro é necessário atualizar o package index e instalar algumas ferramentas necessárias para poder baixar o Kubernetes via apt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; apt-transport-https ca-certificates curl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em seguida baixar a chave pública do GCP e adicionar o repositório do Kubernetes ao repositório do apt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;curl &lt;span class="nt"&gt;-fsSLo&lt;/span&gt; /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/apt/sources.list.d/kubernetes.list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Por fim, reatualizar o package index para buscar as informações do novo repositório e instalar o kubectl:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; kubectl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Instalando o CRI-O
&lt;/h2&gt;

&lt;p&gt;De acordo com a &lt;a href="https://minikube.sigs.k8s.io/docs/drivers/podman/#usage" rel="noopener noreferrer"&gt;documentação do minikube&lt;/a&gt;, para utilizar o podman é necessário instalar um runtime. E o runtime recomendado pela própria documentação é o CRI-O.&lt;/p&gt;

&lt;p&gt;Para instalá-lo vamos usar a &lt;a href="https://cri-o.io/" rel="noopener noreferrer"&gt;documentação oficial do CRI-O&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Assim como no último post, vamos começar importanto o arquivo /etc/os-release para as variáveis de ambiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt; /etc/os-release
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com essas variáveis importadas, podemos baixar os repositórios necessários:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;CRIO_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.23
&lt;span class="nb"&gt;sudo echo&lt;/span&gt; &lt;span class="s2"&gt;"deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/x{&lt;/span&gt;&lt;span class="nv"&gt;$Name&lt;/span&gt;&lt;span class="s2"&gt;}_{&lt;/span&gt;&lt;span class="nv"&gt;$VERSION_ID&lt;/span&gt;&lt;span class="s2"&gt;}/ /"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
&lt;span class="nb"&gt;sudo echo&lt;/span&gt; &lt;span class="s2"&gt;"deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/{&lt;/span&gt;&lt;span class="nv"&gt;$CRIO_VERSION&lt;/span&gt;&lt;span class="s2"&gt;}/x{&lt;/span&gt;&lt;span class="nv"&gt;$Name&lt;/span&gt;&lt;span class="s2"&gt;}_{&lt;/span&gt;&lt;span class="nv"&gt;$VERSION_ID&lt;/span&gt;&lt;span class="s2"&gt;}/ /"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$CRIO_VERSION&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;.list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;A variável CRIO_VERSION deve ser preenchida com a versão desejada. Na data desta publicação é a 1.23.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Agora adicionamos as chaves ao apt-key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/x&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$Name&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;_&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$VERSION_ID&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;/Release.key | apt-key add -
&lt;span class="nb"&gt;sudo &lt;/span&gt;curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$CRIO_VERSION&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;/x&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$Name&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;_&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$VERSION_ID&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;/Release.key | apt-key add -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E por fim instalamos a nossa última ferramenta necessária para rodar o minikube com o podman:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; cri-o cri-o-runc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Rodando o minikube
&lt;/h2&gt;

&lt;p&gt;Depois dessa pequena odisséia de instalação, é hora de colocar o minikube para rodar com o podman. O comando exige passar as opções de driver e container runtime, porém nada de extraordinário:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;minikube start &lt;span class="nt"&gt;--driver&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;podman &lt;span class="nt"&gt;--container-runtime&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cri-o
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ao executar o comando recebemos a seguinte mensagem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;😄  minikube v1.25.2 on Ubuntu 20.04 &lt;span class="o"&gt;(&lt;/span&gt;amd64&lt;span class="o"&gt;)&lt;/span&gt;
✨  Using the podman driver based on existing profile

💣  Exiting due to PROVIDER_PODMAN_NOT_RUNNING: &lt;span class="s2"&gt;"sudo -k -n podman version --format "&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;status 1: &lt;span class="nb"&gt;sudo&lt;/span&gt;: a password is required
💡  Suggestion: Add your user to the &lt;span class="s1"&gt;'sudoers'&lt;/span&gt; file: &lt;span class="s1"&gt;'myuser ALL=(ALL) NOPASSWD: /usr/bin/podman'&lt;/span&gt;
📘  Documentation: https://podman.io
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se o leitor pensou a mesma coisa que eu a primeira vez que viu essa mensagem, certamente deve ter tentado rodar o minikube com sudo e recebeu o erro abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;😄  minikube v1.25.2 on Ubuntu 20.04 &lt;span class="o"&gt;(&lt;/span&gt;amd64&lt;span class="o"&gt;)&lt;/span&gt;
✨  Using the podman driver based on user configuration
🛑  The &lt;span class="s2"&gt;"podman"&lt;/span&gt; driver should not be used with root privileges.
💡  If you are running minikube within a VM, consider using &lt;span class="nt"&gt;--driver&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none:
📘    https://minikube.sigs.k8s.io/docs/reference/drivers/none/

❌  Exiting due to DRV_AS_ROOT: The &lt;span class="s2"&gt;"podman"&lt;/span&gt; driver should not be used with root privileges.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O podman por ser construído utilizando a premissa rootless, não permite que o minikube seja rodado como rootfull quando utilizá-o como driver.&lt;/p&gt;

&lt;p&gt;A solução é seguir a sugestão dada na primeira execução&lt;/p&gt;

&lt;h3&gt;
  
  
  Adicionando o Podman ao sudoers
&lt;/h3&gt;

&lt;p&gt;Apesar de ser uma etapa rápida de fazer, vale parar 1 minuto para entender o que é o sudoers e o que ele faz antes de executar o comando.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;sudoers é um arquivo utilizado para definir o nível de permissão de execução de comandos no modo super usuário. Neste arquivo é possível definir desde permissão de execução de comandos em um programa em específico até execução total e irrestrita.&lt;br&gt;
Para mais informações e entendimento recomendo a &lt;a href="https://www.linux.com/training-tutorials/configuring-linux-sudoers-file/" rel="noopener noreferrer"&gt;leitura deste post&lt;/a&gt; e a &lt;a href="https://linux.die.net/man/5/sudoers" rel="noopener noreferrer"&gt;leitura do man do arquivo sudoers&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Execute o comando &lt;code&gt;sudo visudo&lt;/code&gt; e adicione a seginte linha no final do arquivo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;myuser &lt;span class="nv"&gt;ALL&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;ALL&lt;span class="o"&gt;)&lt;/span&gt; NOPASSWD: /usr/bin/podman
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explicando o nível de permissão que estamos atribuindo:&lt;/p&gt;

&lt;p&gt;O usuário &lt;em&gt;myuser&lt;/em&gt; pode executar qualquer comando dentro do programa &lt;em&gt;/usr/bin/podman&lt;/em&gt; sem a necessidade de informar o password.&lt;/p&gt;

&lt;p&gt;Com a configuração adicionada podemos rodar o minikube sem grandes problemas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Erro ao executar o minikube
&lt;/h3&gt;

&lt;p&gt;Ao tentar rodar o minikube pela primeira vez talvez ocorra o erro de download de imagem KIC (perdi o texto certo do erro 😅). Para resolver esse problema é necessário baixar a imagem manualmente com o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;minikube start &lt;span class="nt"&gt;--driver&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;podman &lt;span class="nt"&gt;--container-runtime&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cri-o &lt;span class="nt"&gt;--download-only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Após o término do download basta executar o minikube novamente&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy da aplicação
&lt;/h2&gt;

&lt;p&gt;Com tudo configurado, é hora de criar um deploy e publicar nossa aplicação de teste.&lt;br&gt;
Para isso crie um arquivo &lt;em&gt;.yaml&lt;/em&gt; igual ao exemplo abaixo (ou pega ele pronto no repositório 😉)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;juridico-deployment&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;juridico&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;juridico&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;juridico&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;juridicoapp&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;localhost/juridico:latest&lt;/span&gt;
        &lt;span class="na"&gt;imagePullPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;IfNotPresent&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3001&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com o &lt;strong&gt;deployment.yaml&lt;/strong&gt; criado, execute o comando&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; &amp;lt;path-to-deployment-file&amp;gt;/deployment.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para ver se o deployment foi feito rode o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get deployments juridico-deployment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;o resultado deve ser algo parecido com:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
juridico-deployment   2/2     2            2           15d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E para ver os pods criados:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;juridico
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A saída deve ser algo parecido com:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;NAME                                    READY   STATUS             RESTARTS   AGE
juridico-deployment-86b6b47b6-j5l9n     1/1     Running            4          15d
juridico-deployment-86b6b47b6-lzkjq     1/1     Running            4          15d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se por ventura no status estiver mensagens do tipo &lt;code&gt;ImagePullBackOff&lt;/code&gt; ou &lt;code&gt;ErrImagePull&lt;/code&gt;, provavelmente você deve possuir a imagem somente no cache do podman. Se esse for o caso, é necessário fazer um dos 3 passos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Subir a imagem para algum registry remoto (dockerhub, quay.io)&lt;/li&gt;
&lt;li&gt;Criar um &lt;a href="https://minikube.sigs.k8s.io/docs/handbook/registry/" rel="noopener noreferrer"&gt;registry local&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Subir a imagem para o cache do minikube&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Adicionando a imagem ao cache do minikube
&lt;/h3&gt;

&lt;p&gt;Se você assim como eu está tentando fazer um teste 100% local, sem dependender de registrys externos e subir mais uma aplicação, antes de ter tudo rodando é necessário executar mais esse passo. O processo é tedioso, porém pouco complexo&lt;/p&gt;

&lt;p&gt;Primeiro é necessário exportar a imagem para um arquivo &lt;em&gt;.tar&lt;/em&gt; com o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;podman save &lt;span class="nt"&gt;-o&lt;/span&gt; juridico.tar localhost/juridico:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois basta importar a imagem no minikube utilizando o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;minikube image load juridico.tar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feito isso, basta reiniciar o minikube que o problema deve estar solucionado.&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando a service
&lt;/h2&gt;

&lt;p&gt;O próximo passo é criar uma forma de nos comunicarmos com o sistema independente da quantidade de pods instanciados e qual o IP do pod que está rodando no momento.&lt;/p&gt;

&lt;p&gt;Para criar a service seguimos o mesmo passo do deployment e criamos um arquivo &lt;em&gt;.yaml&lt;/em&gt; conforme abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;juridico-service&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;juridico&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NodePort&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;juridico&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3001&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
      &lt;span class="na"&gt;nodePort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30001&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com o &lt;strong&gt;service.yaml&lt;/strong&gt; criado, execute o comando&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; &amp;lt;path-to-service-file&amp;gt;/service.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para ver se o service foi criado rode o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get services juridico-service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;o resultado deve ser algo parecido com:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;NAME       TYPE       CLUSTER-IP     EXTERNAL-IP   PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt;          AGE
juridico   NodePort   10.109.72.98   &amp;lt;none&amp;gt;        3001:30001/TCP   15d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com a service configurada as outras aplicações já conseguem resolver o nome do sistema independente do scale up ou down dos pods.&lt;/p&gt;

&lt;h2&gt;
  
  
  Expondo a aplicação para fora do Kubernetes
&lt;/h2&gt;

&lt;p&gt;Mesmo com a service configurada ainda não é possível realizar um acesso de fora do kubernetes. Para isso é necessária a utilização de um componente de rotas para expor a aplicação para fora e rotear as requisições para a aplicação. Nas minhas pesquisas encontrei duas formas de fazer o encaminhamento: usando o próprio minikube e usando o ingress. Aqui irei apresentar somente a primeira.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://minikube.sigs.k8s.io/docs/commands/service/" rel="noopener noreferrer"&gt;Minikube Service&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;O próprio minikube possui um comando que expõe a service para fora do kubernetes de forma simples e direta, podendo expor todas as services ou somente uma em específico. Para expor a aplicação deste post execute o comando abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;minikube service &lt;span class="nt"&gt;--url&lt;/span&gt; juridico-service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O resultado será algo parecido com:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; minikube service juridico
🏃  Starting tunnel &lt;span class="k"&gt;for &lt;/span&gt;service juridico.
🎉  Opening service default/juridico &lt;span class="k"&gt;in &lt;/span&gt;default browser...
👉  http://192.168.49.2:30001
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rodando o comando curl na url mostrada o valor retornado é a lista de todos os processos presentes no db.&lt;/p&gt;

&lt;h2&gt;
  
  
  Acessando a aplicação fora do WSL
&lt;/h2&gt;

&lt;p&gt;Até o momento foram realizados inúmeros testes dentro do WSL e tudo tem ocorrido bem. Porém ao tentar chamar a URL a partir da máquina host(Windows) ela não encontrará a rota (404). Isso acontece porque o minikube assume um IP interno acessível somente pelo próprio WSL. Para tornar o sistema acessível é necessário utilizar o comando de port forwarding.&lt;/p&gt;

&lt;p&gt;Para habilitar port fowarding para a service execute o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl port-forward service/juridico-deployment 3001:3001
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O resultado deve ser algo semelhante ao que segue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Forwarding from 127.0.0.1:3001 -&amp;gt; 3001
Forwarding from &lt;span class="o"&gt;[&lt;/span&gt;::1]:3001 -&amp;gt; 3001
Handling connection &lt;span class="k"&gt;for &lt;/span&gt;3001
Handling connection &lt;span class="k"&gt;for &lt;/span&gt;3001
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Infelizmente ao executar o comando de port forward o terminal fica preso e só é liberado ao encerrar o port-forward&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Agora sim é possível chamar o sistema utilizando a URL &lt;a href="http://localhost:3001" rel="noopener noreferrer"&gt;http://localhost:3001&lt;/a&gt; diretamente da máquina host.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternativa rootless para o minikube
&lt;/h2&gt;

&lt;p&gt;Como mencionado &lt;a href="https://github.com/kubernetes/minikube/issues/8719" rel="noopener noreferrer"&gt;nesta issue&lt;/a&gt;, os drivers do minikube devem executar em modo rootful. O principal risco de rodar o driver em modo root é a chance de ocorrer uma escalada de privilégios até o host. Para evitar este tipo de problema vamos recorrer a uma alternativa rootless: O usernetes&lt;/p&gt;

&lt;h2&gt;
  
  
  Impressões e Conclusão
&lt;/h2&gt;

&lt;p&gt;Rodar o minikube utilizando o podman como runtime se provou um desafio grande e demandou muito estudo para fazer tudo rodar corretamente. O principal problema foi tornar a aplicação acessível da máquina host.&lt;br&gt;
Um ponto que me chamou atenção é que durante a configuração do ecossistema é a incapacidade que o minikube tem de operar em modo rootless e as alterções necessárias para "forçar" o podman em modo rootful. Isso me levou a começar a estudar como funciona o userneter e quem sabe trazer um post novo para a série.&lt;/p&gt;

&lt;p&gt;Por fim, vejo que o podman ainda precisa percorrer algum caminho para se tornar fácil de ser integrado e configurado como driver das distribuições mais populares de kubernetes para desenvolvedores assim como o docker é hoje.&lt;/p&gt;

&lt;p&gt;Todos os arquivos e sistemas utilizados nesse post estão disponíveis no meu github no repositório &lt;a href="https://github.com/julianopoveda/wsl2-plus-podman" rel="noopener noreferrer"&gt;wsl plus podman&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Referencias
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://minikube.sigs.k8s.io/docs/start/" rel="noopener noreferrer"&gt;documentação oficial de instalação do minikube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/" rel="noopener noreferrer"&gt;documentação oficial de instalação do kubectl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cri-o.io/" rel="noopener noreferrer"&gt;documentação oficial de instalação do CRI-O&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://minikube.sigs.k8s.io/docs/drivers/podman/" rel="noopener noreferrer"&gt;documentação minikube utilizando podman como driver&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://medium.com/techbeatly/container-runtimes-deep-dive-77eb0e511939" rel="noopener noreferrer"&gt;post conceitos de driver e runtime. Autor: Nived Velayuhan&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://opensource.com/article/20/12/containers-101" rel="noopener noreferrer"&gt;link alternativo do post&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/opencontainers/runtime-spec/blob/main/spec.md" rel="noopener noreferrer"&gt;documentação da Spec do runtime pela OCI&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/kubernetes/minikube/issues/8719" rel="noopener noreferrer"&gt;discussão do porque o podman deve rodar em rootful com minikube&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/rootless-containers/usernetes" rel="noopener noreferrer"&gt;usernetes: alternativa rootless para o minikube&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/kubernetes/minikube/pull/8417" rel="noopener noreferrer"&gt;problema de download das imagens&lt;/a&gt;&lt;/li&gt;

&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>WSL2 + Podman: Uma alternativa ao Docker Desktop</title>
      <dc:creator>Poveda</dc:creator>
      <pubDate>Fri, 28 Jan 2022 12:26:47 +0000</pubDate>
      <link>https://dev.to/poveda/wsl2-podman-uma-alternativa-ao-docker-desktop-5cd6</link>
      <guid>https://dev.to/poveda/wsl2-podman-uma-alternativa-ao-docker-desktop-5cd6</guid>
      <description>&lt;p&gt;Dia 31/01/2022 o Docker desktop passará a ser pago para empresas com mais de 250 funcionários ou com faturamento a partir de 10 milhões de dólares anuais. Esse comunicado está sendo divulgado desde agosto de 2021 e com ele pensei:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Está na hora de revisitar aqueles links esquecidos no limbo sobre alternativas ao Docker.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Meu objetivo é ter uma solução na parte de execução de containers, eliminando todo o resto da ferramenta do docker que na máquina de desenvolvimento não utilizo. Em minhas pesquisas a ferramenta que mais se encaixa neste cenário é o &lt;a href="https://podman.io/" rel="noopener noreferrer"&gt;podman&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Podman is a daemonless container engine for developing, managing, and running OCI Containers on your Linux System. Containers can either be run as root or in rootless mode.&lt;/em&gt; &lt;br&gt;
&lt;em&gt;Fonte: &lt;a href="https://podman.io/" rel="noopener noreferrer"&gt;https://podman.io/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lendo a definição do que é o Podman, encontramos o primeiro problema: ele roda somente em Linux e eu uso o Windows. &lt;a href="https://podman.io/getting-started/installation#windows" rel="noopener noreferrer"&gt;Até existe um instalador para Windows&lt;/a&gt;, porém ele é um client para acessar o podman instalado em algum lugar e não a ferramenta em si.&lt;/p&gt;

&lt;h2&gt;
  
  
  WLS2 + Podman = ❤️
&lt;/h2&gt;

&lt;p&gt;Por sorte e visão da nossa amada e odiada Microsoft, não precisamos mais subir uma VM e realizar toda a configuração necessária para rodar o Linux, podemos usar o WSL2.&lt;br&gt;
No próprio site do podman existe &lt;a href="https://www.redhat.com/sysadmin/podman-windows-wsl2" rel="noopener noreferrer"&gt;o link do post que ensina como instalar a aplicação no WSL2&lt;/a&gt;. Vou seguir este post e acrescentar algumas observações e passos extras que precisei fazer para ter tudo rodando 100%.&lt;/p&gt;
&lt;h2&gt;
  
  
  Configurando o WLS2
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Etapa opcional. Se está tudo certo na parte de configuração do WSL2, pode ir direto para a instalação do Podman.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O primeiro passo é &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/install" rel="noopener noreferrer"&gt;habilitar o WSL no Windows&lt;/a&gt; e ativar o WSL2.&lt;br&gt;
Com o WSL2 habilitado e a distro instalada (estou utilizando o Ubuntu 20.04), vamos verificar se a distro esta no formato WSL2 rodando o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wsl &lt;span class="nt"&gt;--list&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O resultado será semelhante ao que segue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  NAME                   STATE           VERSION
&lt;span class="k"&gt;*&lt;/span&gt; Ubuntu                 Stopped         2
  docker-desktop         Stopped         2
  docker-desktop-data    Stopped         2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Caso a versão da distro não esteja na 2, é necessário rodar o próximo comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wsl &lt;span class="nt"&gt;--set-version&lt;/span&gt; Ubuntu 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Instalando o Podman
&lt;/h2&gt;

&lt;p&gt;Com o WSL2 configurado vamos iniciar a instalação do Podman.&lt;br&gt;
O primeiro passo é descobrir qual é o nome e a versão da sua distro. Dentro do shell da distro execute o comando&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /etc/os-release
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ele deve retornar algo parecido com as informações abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Ubuntu"&lt;/span&gt;
&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"20.04.2 LTS (Focal Fossa)"&lt;/span&gt;
&lt;span class="nv"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ubuntu
&lt;span class="nv"&gt;ID_LIKE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;debian
&lt;span class="nv"&gt;PRETTY_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Ubuntu 20.04.2 LTS"&lt;/span&gt;
&lt;span class="nv"&gt;VERSION_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"20.04"&lt;/span&gt;
&lt;span class="nv"&gt;HOME_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://www.ubuntu.com/"&lt;/span&gt;
&lt;span class="nv"&gt;SUPPORT_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://help.ubuntu.com/"&lt;/span&gt;
&lt;span class="nv"&gt;BUG_REPORT_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://bugs.launchpad.net/ubuntu/"&lt;/span&gt;
&lt;span class="nv"&gt;PRIVACY_POLICY_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"&lt;/span&gt;
&lt;span class="nv"&gt;VERSION_CODENAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;focal
&lt;span class="nv"&gt;UBUNTU_CODENAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;focal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternativamente você pode importar esse arquivo direto para as variáveis de ambiente com o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt; /etc/os-release
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O comando acima facilitará os próximos passos e por isso vou usá-lo.&lt;br&gt;
O próximo passo é adicionar o repositório do podman na lista de fontes do apt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/x&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERSION_ID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/ /"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aqui vale uma explicação de alguns pontos do comando que estamos executando:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;sudo tee&lt;/strong&gt;: Pega o valor informado no stdin (nesse caso a instrução anterior) e grava no arquivo de destino informado.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Agora adicionamos uma nova chave ao apt para o repositório que contém o podman:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="s2"&gt;"https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/x&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERSION_ID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/Release.key"&lt;/span&gt; | &lt;span class="nb"&gt;sudo &lt;/span&gt;apt-key add -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explicando:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;curl&lt;/strong&gt;: Efetua uma chamada http para o endereço informado&lt;/li&gt;
&lt;li&gt;*&lt;em&gt;sudo apt-key add - *&lt;/em&gt;: Adiciona a chave retornada no stdin a lista do apt-key&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feito! Agora basta atualizar a lista do apt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E instalar o podman:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; podman
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testando
&lt;/h2&gt;

&lt;p&gt;A parte mais legal é ver os containers funcionando. Vamos começar por algo simples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;podman run &lt;span class="nt"&gt;--rm&lt;/span&gt; hello-world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este exemplo é o mesmo exemplo de &lt;a href="https://hub.docker.com/_/hello-world" rel="noopener noreferrer"&gt;hello world do docker&lt;/a&gt; porém utilizando o podman&lt;/p&gt;

&lt;p&gt;A saída deve ser algo assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the &lt;span class="s2"&gt;"hello-world"&lt;/span&gt; image from the Docker Hub.
    &lt;span class="o"&gt;(&lt;/span&gt;amd64&lt;span class="o"&gt;)&lt;/span&gt;
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 &lt;span class="nv"&gt;$ &lt;/span&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como próximo teste, vamos buildar uma imagem nova e colocá-la para rodar. Para isso vamos usar &lt;a href="https://github.com/julianopoveda/wsl2-plus-podman" rel="noopener noreferrer"&gt;o repositório do post que contém um CRUD simples em node&lt;/a&gt;.&lt;br&gt;
Uma vez baixado o repositório, vamos buildar a imagem.&lt;br&gt;
Execute o comando abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;podman build &lt;span class="nt"&gt;-t&lt;/span&gt; juridico &lt;span class="nt"&gt;-f&lt;/span&gt; dockerfile.multistaging &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com a imagem pronta, chegou a hora de executar o container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; podman run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 3001:3001 localhost/juridico
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Executando o comando &lt;code&gt;curl http://localhost:3001/95069158262525&lt;/code&gt;, temos o seguinte resultado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"numero"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"95069158262525"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"uf_sigla"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cidade"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Mendoza"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"reu"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Kaitlin Scutter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"identidade"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"33925502749086"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cliente"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Cherlyn Floyed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ativo"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusão e Próximos Passos
&lt;/h2&gt;

&lt;p&gt;O Podman me surpreendeu pela simplicidade de uso e semelhança com os comandos de Docker. Todos os comandos do docker que uso no dia-a-dia podem ser facilmente utilizados no podman. Inclusive o próprio site do podman ensina a criar um alias para docker. Outro ponto admirável é a transparencia no mapeamento das portas do WSL para a máquina host. Não é necessário realizar qualquer configuração adicional é só mapear as portas e pronto.&lt;/p&gt;

&lt;p&gt;O próximo passo é colocar o Kubernetes para rodar utilizando o podman como container engine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Referencias
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://podman.io/" rel="noopener noreferrer"&gt;https://podman.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://podman.io/getting-started/installation#ubuntu" rel="noopener noreferrer"&gt;https://podman.io/getting-started/installation#ubuntu&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.redhat.com/sysadmin/podman-windows-wsl2" rel="noopener noreferrer"&gt;https://www.redhat.com/sysadmin/podman-windows-wsl2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/windows/wsl/install" rel="noopener noreferrer"&gt;https://docs.microsoft.com/en-us/windows/wsl/install&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;tee --help, apt-key --help, . --help&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devops</category>
      <category>podman</category>
      <category>oci</category>
    </item>
    <item>
      <title>Git apply: colocando os patch files em stage</title>
      <dc:creator>Poveda</dc:creator>
      <pubDate>Mon, 27 Sep 2021 12:20:20 +0000</pubDate>
      <link>https://dev.to/poveda/git-apply-colocando-os-patch-files-em-stage-db6</link>
      <guid>https://dev.to/poveda/git-apply-colocando-os-patch-files-em-stage-db6</guid>
      <description>&lt;p&gt;No &lt;a href="https://dev.to/poveda/git-patch-compartilhamento-de-commits-alem-do-remote-3j88"&gt;último post&lt;/a&gt; mostrei como podemos utilizar arquivos patch para compartilhar mudanças e commits quando não temos acesso ao remote. A abordagem utilizada coloca as alterações diretamente na árvore de commits e possui mecanismos para evitar duplicidades no momento da aplicação. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Mas se eu quiser revisar as alterações antes de aplicar o commit na árvore?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;É justamente para esse cenário que existe o git apply&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://git-scm.com/docs/git-apply" rel="noopener noreferrer"&gt;Git apply&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;O comando &lt;strong&gt;git apply&lt;/strong&gt; aplica as mudanças que estão dentro dos arquivos &lt;em&gt;.patch&lt;/em&gt; aos arquivos correspondentes dentro da pasta de trabalho.&lt;/p&gt;

&lt;p&gt;Para adicionar as mudanças basta executar o comando abaixo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git apply patch-commits/0001-Adiconadas-mais-motoriza-es-a-base.patch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Após a execução do comando temos a área de staging com os arquivos alterados&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/mongoblogposts&lt;span class="nv"&gt;$ &lt;/span&gt;git status
On branch main
Your branch is up to &lt;span class="nb"&gt;date &lt;/span&gt;with &lt;span class="s1"&gt;'origin/main'&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

Changes not staged &lt;span class="k"&gt;for &lt;/span&gt;commit:
  &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="s2"&gt;"git add &amp;lt;file&amp;gt;..."&lt;/span&gt; to update what will be committed&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="s2"&gt;"git restore &amp;lt;file&amp;gt;..."&lt;/span&gt; to discard changes &lt;span class="k"&gt;in &lt;/span&gt;working directory&lt;span class="o"&gt;)&lt;/span&gt;
        modified:   db_data/carro_dump.json

no changes added to commit &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="s2"&gt;"git add"&lt;/span&gt; and/or &lt;span class="s2"&gt;"git commit -a"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;E analisando os logs dos commits, nota-se que nenhum novo commit foi adicionado à árvore&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/mongoblogposts&lt;span class="nv"&gt;$ &lt;/span&gt;git log &lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="nt"&gt;--oneline&lt;/span&gt;
65182aa &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; main, origin/main&lt;span class="o"&gt;)&lt;/span&gt; Material post git patch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Verificando quais arquivos foram alterados no último commit:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/mongoblogposts&lt;span class="nv"&gt;$ &lt;/span&gt;git show &lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="nt"&gt;--compact-summary&lt;/span&gt;
commit 65182aa52f918b567e33545bd15f3bea93d67c58 &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; main, origin/main&lt;span class="o"&gt;)&lt;/span&gt;
Author: Juliano Poveda &amp;lt;julianopoveda@github.com&amp;gt;
Date:   Mon Sep 13 09:41:58 2021 &lt;span class="nt"&gt;-0300&lt;/span&gt;

    Material post git patch

 patch-commits/0001-Adiconadas-mais-motoriza-es-a-base.patch &lt;span class="o"&gt;(&lt;/span&gt;new&lt;span class="o"&gt;)&lt;/span&gt;     | 386 ++++++++++++++++++++++++++++++++++++++++++
 patch-commits/0002-Reformata-o-readme-criacao-do-ambiente.patch &lt;span class="o"&gt;(&lt;/span&gt;new&lt;span class="o"&gt;)&lt;/span&gt; |  45 +++++
 patch-commits/readme.md &lt;span class="o"&gt;(&lt;/span&gt;new&lt;span class="o"&gt;)&lt;/span&gt;                                         |  83 +++++++++
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Viram! As alterações estão na área de staging e não há nenhum novo commit na árvore.&lt;/p&gt;
&lt;h2&gt;
  
  
  O parâmetro &lt;a href="https://git-scm.com/docs/git-apply#Documentation/git-apply.txt---check" rel="noopener noreferrer"&gt;--check&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;O apply por padrão já verifica se é possível adicionar as alterações, no entanto, em determinadas ocasiões é bom fazer uam verificação do arquivo .patch antes de adicionar suas alterações. O parâmetro &lt;strong&gt;--check&lt;/strong&gt; faz justamente esta validação. Caso os arquivos estejam aptos a serem adicionados à área de staging, nenhuma mensagem é retornada&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/mongoblogposts&lt;span class="nv"&gt;$ &lt;/span&gt;git apply patch-commits/0001-Adiconadas-mais-motoriza-es-a-base.patch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Já se o arquivo não estiver apto, o comando emite a mensagem&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;error: patch failed: db_data/carro_dump.json:2&lt;/em&gt;&lt;br&gt;
&lt;em&gt;error: db_data/carro_dump.json: patch does not apply&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Note que quando é passado &lt;strong&gt;--check&lt;/strong&gt; no comando, as alterações constantes nos arquivos de patch não são aplicadas à área staging. Para que as alterações sejam aplicadas é necessário adicionar o parâmetro &lt;strong&gt;&lt;a href="https://git-scm.com/docs/git-apply#Documentation/git-apply.txt---apply" rel="noopener noreferrer"&gt;--apply&lt;/a&gt;&lt;/strong&gt; ou rodar o comando sem o &lt;strong&gt;--check&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Impressões e Conclusão
&lt;/h2&gt;

&lt;p&gt;Este comando ao contrário do git am, nos permite fazer um "PR local" antes de adicionar as alterações à árvore. &lt;br&gt;
Então, na próxima vez que ficares sem acesso ao repositório remoto e precisares entregar aquela tarefa super importante, acessa essa mini série e relembra como fazer a passagem das alterações por patch files :).&lt;/p&gt;

&lt;p&gt;Os arquivos para teste, são os mesmos do post anterior(pasta patch-commits) e estão disponíveis no github.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/julianopoveda" rel="noopener noreferrer"&gt;
        julianopoveda
      &lt;/a&gt; / &lt;a href="https://github.com/julianopoveda/mongoblogposts" rel="noopener noreferrer"&gt;
        mongoblogposts
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  Referências
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://git-scm.com/docs/git-apply" rel="noopener noreferrer"&gt;https://git-scm.com/docs/git-apply&lt;/a&gt;&lt;/p&gt;

</description>
      <category>git</category>
    </item>
    <item>
      <title>Git patch: Compartilhamento de commits além do remote</title>
      <dc:creator>Poveda</dc:creator>
      <pubDate>Mon, 13 Sep 2021 12:41:10 +0000</pubDate>
      <link>https://dev.to/poveda/git-patch-compartilhamento-de-commits-alem-do-remote-3j88</link>
      <guid>https://dev.to/poveda/git-patch-compartilhamento-de-commits-alem-do-remote-3j88</guid>
      <description>&lt;p&gt;Certa feita passei por uma situação corriqueira: Fiquei sem acesso ao repositório do projeto da equipe. Até aí nada de extraordinário, imagino que todos os devs que estão lendo isso já passaram por isso. O problema real era que eu precisava entregar uma tarefa urgente que iria para produção assim que ela estivesse revisada pelos meus pares (aquele pr básico).&lt;br&gt;
Após passar o pânico inicial e solicitar novamente os acessos, comecei a pensar como poderia fazer esse commit sem precisar encaminhar todos os arquivos alterados para alguém que tivesse acesso ao repositório e pudesse subir o trabalho feito. Relembrando minha época de estudo mais aprofundado do git (leiam o &lt;a href="https://git-scm.com/book/en/v2" rel="noopener noreferrer"&gt;livro oficial do git&lt;/a&gt;), lembrei que o kernel do Linux é versionado a partir de arquivos de commits, ou patch files, e enviados por e-mail para serem revisados e restaurados no repositório principal (que não possui acesso a partir da internet). Uma vez que a linha de raciocínio estava feita, fui para a &lt;a href="https://git-scm.com/docs" rel="noopener noreferrer"&gt;documentação oficial&lt;/a&gt; pensando:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Isso vai dar trabalho&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Qual foi a minha surpresa ao descobrir que bastam 2 comandos para fazer tal operação.&lt;/p&gt;
&lt;h2&gt;
  
  
  Gerando os arquivos
&lt;/h2&gt;

&lt;p&gt;O primeiro comando que deve ser rodado é o &lt;a href="https://git-scm.com/docs/git-format-patch" rel="noopener noreferrer"&gt;git format-patch&lt;/a&gt;. Ele é responsável por gerar os arquivos .patch. Cada commit irá gerar um arquivo .patch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git format-patch -&amp;lt;n&amp;gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &amp;lt;diretorio-de-destino-arquivo&amp;gt; &amp;lt;hash-commit&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Explicando rápidamente cada parâmetro:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;-&amp;lt;n&amp;gt;&lt;/strong&gt;: A quantidade de commits anteriores ao commit informado que devem ser exportados. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&amp;lt;hash-commit&amp;gt;&lt;/strong&gt;: Representa o último commit que deve ser exportado. Commits acima dele não serão exportados.&lt;/li&gt;
&lt;li&gt;-o &amp;lt;diretorio-de-destino-arquivo&amp;gt; (opcional): Utilizado para informar onde o arquivo .patch deve ser salvo. O padrão é no próprio diretório.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Inserindo os arquivos .patch na árvore de commits
&lt;/h2&gt;

&lt;p&gt;Agora que os arquivos .patch foram gerados, o próximo passo é adicioná-los à árvore de commits. Para isso utilizamos o comando &lt;a href="https://git-scm.com/docs/git-am" rel="noopener noreferrer"&gt;git am&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git am patch-commits/0001-Adiconadas-mais-motoriza-es-a-base.patch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Se for mais de um arquivo&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git am patch-commits/000&lt;span class="k"&gt;*&lt;/span&gt;.patch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Caso seja necessário revisar o arquivo de patch antes de aplicálo na árvore basta adicionar a opção -i:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git am &lt;span class="nt"&gt;-i&lt;/span&gt; patch-commits/000&lt;span class="k"&gt;*&lt;/span&gt;.patch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Assim, cada arquivo de patch vai ser exibido da seguinte forma:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Commit Body is:
&lt;span class="nt"&gt;--------------------------&lt;/span&gt;
Instrucoes de como rodar o mongo
&lt;span class="nt"&gt;--------------------------&lt;/span&gt;
Apply? &lt;span class="o"&gt;[&lt;/span&gt;y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all: 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Impressões e Conclusão
&lt;/h2&gt;

&lt;p&gt;É interessante ver como determinadas coisas que estudamos e não damos importância podem nos salvar algum dia. Quando li sobre o assunto de commits sendo enviados por e-mail achei cômico como o kernel do sistema operacional mais utilizado do mundo era versionado.No entanto, foi uma informação que se provou útil no final das contas.&lt;br&gt;
Muitas vezes uma informação não vai ser a resolução do problema, mas é ela quem dará a linha de raciocínio para a solução.&lt;/p&gt;

&lt;p&gt;No github (pasta patch-commits) deixei o passo a passo de como reproduzir esse post.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/julianopoveda" rel="noopener noreferrer"&gt;
        julianopoveda
      &lt;/a&gt; / &lt;a href="https://github.com/julianopoveda/mongoblogposts" rel="noopener noreferrer"&gt;
        mongoblogposts
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Enquanto revisava o material para este post me deparei com uma dúvida:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;E se eu não quiser aplicar os commits diretamente na árvore, mas quiser colocá-los em stage e revisar o código em uma ferramenta mais amigável que o console?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Essa dúvida vou responder no próximo post ;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Referências
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://git-scm.com/docs/git-format-patch" rel="noopener noreferrer"&gt;https://git-scm.com/docs/git-format-patch&lt;/a&gt;&lt;br&gt;
&lt;a href="https://git-scm.com/docs/git-am" rel="noopener noreferrer"&gt;https://git-scm.com/docs/git-am&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Exportando dados filtrados em mais de uma collection</title>
      <dc:creator>Poveda</dc:creator>
      <pubDate>Mon, 30 Aug 2021 10:46:51 +0000</pubDate>
      <link>https://dev.to/poveda/exportando-dados-filtrados-em-mais-de-uma-collection-431c</link>
      <guid>https://dev.to/poveda/exportando-dados-filtrados-em-mais-de-uma-collection-431c</guid>
      <description>&lt;p&gt;Imagine a seguinte situação: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A equipe estratégica da montadora deseja criar um relatório contendo todas as vendas feitas no mês de agosto de 2020 tanto pela concessionária quanto direto pela fábrica. &lt;br&gt;
O sistema da montadora divide essas vendas em duas collections do mongo.&lt;br&gt;
O relatório é gerado por uma ferramenta consolidada de mercado que aceita a importação dos dados por arquivos .csv ou .json&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A primeira solução que vem à cabeça é utilizar o mongoexport com o parâmetro --query para gerar os dados solicitados. No entanto, o mongoexport possui a limitação de só exportar dados de uma única collection por vez. &lt;br&gt;
Fazendo um teste simples de exportar todos os dados de um database sem definir uma collection com o mongoexport obtemos o seguinte resultado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#$&amp;gt; mongoexport mongodb://localhost:27017 --db examples #comando executado&lt;/span&gt;
2021-08-26T08:39:03.607-0300    must specify a collection
2021-08-26T08:39:03.615-0300    try &lt;span class="s1"&gt;'mongoexport --help'&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;more information
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Usando o &lt;a href="https://docs.mongodb.com/mongodb-shell/" rel="noopener noreferrer"&gt;mongosh&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;O mongosh é a ferramenta básica para interagir com qualquer mongodb. Utilizando ele é possível criar consultas, procedures, indexes e gerenciar o database de maneira geral. Outro ponto interessante é que possível importar scripts .js e executá-los dentro do mongosh. É possível importar o arquivo de duas formas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Importar diretamente dentro do mongosh
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mongosh mongodb://localhost:27017
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; load&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'export_data_multiple_databases/obter_vendas.js'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Importar no momento da execução do mongosh
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mongosh mongodb://localhost:27017/examples ~/export_data_multiple_databases/obter_vendas.js 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;No primeiro caso os resultados gerados são mostrados diretamente no console do mongosh (contexto do mongosh), tornando a tarefa exportar os dados complexa para o cenário apresentado.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Exemplo de execução&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Current Mongosh Log ID: 612918a2e3f888785924e0e9
Connecting to:          mongodb://localhost:27017/examples?directConnection&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&amp;amp;serverSelectionTimeoutMS&lt;span class="o"&gt;=&lt;/span&gt;2000
Using MongoDB:          5.0.0
Using Mongosh Beta:     0.14.0

For mongosh info see: https://docs.mongodb.com/mongodb-shell/

&lt;span class="nt"&gt;------&lt;/span&gt;
   The server generated these startup warnings when booting:
   2021-08-27T10:16:56.220+00:00: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine. See http://dochub.mongodb.org/core/prodnotes-filesystem
   2021-08-27T10:16:56.525+00:00: Access control is not enabled &lt;span class="k"&gt;for &lt;/span&gt;the database. Read and write access to data and configuration is unrestricted
   2021-08-27T10:16:56.526+00:00: /sys/kernel/mm/transparent_hugepage/enabled is &lt;span class="s1"&gt;'always'&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; We suggest setting it to &lt;span class="s1"&gt;'never'&lt;/span&gt;
&lt;span class="nt"&gt;------&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; load&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'~/export_data_multiple_databases/obter_vendas.js'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[{&lt;/span&gt;
  fabricante: &lt;span class="s1"&gt;'Lexus'&lt;/span&gt;,
  modelo: &lt;span class="s1"&gt;'LS'&lt;/span&gt;,
  ano: 2004,
  datavenda: ISODate&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"2021-08-03T00:00:00.000Z"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;,
  preco: &lt;span class="s1"&gt;'$106375.36'&lt;/span&gt;,
  collectionName: &lt;span class="s1"&gt;'vendas_concessionaria'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;,
&lt;span class="o"&gt;{&lt;/span&gt;
  fabricante: &lt;span class="s1"&gt;'GMC'&lt;/span&gt;,
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Já no segundo caso é possível exportar diretamente para um arquivo externo, pois o comando devolve o resultado no contexto do console e não no contexto do mongosh.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Importante ressaltar que o script importado fica disponível somente naquela sessão.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Exportando para um arquivo
&lt;/h2&gt;

&lt;p&gt;A forma mais simples de exportar para um arquivo é justamente usando o segundo comando de importação de scripts.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mongosh mongodb://localhost:27017/examples ~/export_data_multiple_databases/obter_vendas.js &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; arquivo_resultado.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Mongosh &lt;a href="https://docs.mongodb.com/mongodb-shell/reference/options/#std-option-mongosh.--eval" rel="noopener noreferrer"&gt;--eval&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;O parâmetro &lt;strong&gt;--eval&lt;/strong&gt; executa um script js inline usando o contexto do mongosh, porém sem carregar o ambiente do mongosh no console. O resultado é da execução é enviado para o console conforme exemplo abaixo:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mongosh mongodb://localhost:27017/examples &lt;span class="nt"&gt;--eval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"load('export_data_multiple_databases/obter_massa_dados.js');"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Como resultado é enviado diretamente para o console (fora do contexto do mongosh), exportar os dados para um arquivo .json é simples&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mongosh mongodb://localhost:27017/examples &lt;span class="nt"&gt;--eval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"load('export_data_multiple_databases/obter_massa_dados.js');"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; arquivo_resultado.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;A vantagem em relação à exportação padrão é que com o &lt;strong&gt;--eval&lt;/strong&gt; é possível adicionar outras instruções além do que está no script.&lt;/p&gt;
&lt;h2&gt;
  
  
  Eliminando o cabeçalho com o parâmetro &lt;a href="https://docs.mongodb.com/mongodb-shell/reference/options/#std-option-mongosh.--quiet" rel="noopener noreferrer"&gt;--quiet&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Examinando o arquivo exportado, nota-se que os cabeçalhos de inicialização do mongosh também foram exportados.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;Current&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Mongosh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ID:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6129153e30&lt;/span&gt;&lt;span class="err"&gt;afffaa&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="err"&gt;fb&lt;/span&gt;&lt;span class="mi"&gt;76&lt;/span&gt;&lt;span class="err"&gt;fe&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;Connecting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to:&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="err"&gt;mongodb://localhost:&lt;/span&gt;&lt;span class="mi"&gt;27017&lt;/span&gt;&lt;span class="err"&gt;/examples?directConnection=&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="err"&gt;&amp;amp;serverSelectionTimeoutMS=&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;Using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;MongoDB:&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mf"&gt;5.0&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;Using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Mongosh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Beta:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.14&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;For&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;mongosh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;info&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;see:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;mhttps://docs.mongodb.com/mongodb-shell/&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;------&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="err"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;generated&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;these&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;startup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;warnings&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;when&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;booting:&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="mi"&gt;2021-08-27&lt;/span&gt;&lt;span class="err"&gt;T&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;56.220&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;XFS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;filesystem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;strongly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;recommended&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;WiredTiger&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;storage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;engine.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;See&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;http://dochub.mongodb.org/core/prodnotes-filesystem&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="mi"&gt;2021-08-27&lt;/span&gt;&lt;span class="err"&gt;T&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;56.525&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Access&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;control&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;enabled&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;database.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Read&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;write&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;access&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;configuration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;unrestricted&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="mi"&gt;2021-08-27&lt;/span&gt;&lt;span class="err"&gt;T&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;56.526&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/sys/kernel/mm/transparent_hugepage/enabled&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'always'.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;We&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;suggest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;setting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;it&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'never'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;------&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;Loading&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;file:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;~\export_data_multiple_databases\obter_vendas.js&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;fabricante:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'Hyundai'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;modelo:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'Genesis'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;ano:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2009&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Para resolver este problema basta adicionar o parâmetro &lt;em&gt;--quiet&lt;/em&gt; ao comando de exportação.&lt;/p&gt;

&lt;p&gt;Através do método de importação pela linha de comando:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mongosh mongodb://localhost:27017/examples &lt;span class="nt"&gt;--quiet&lt;/span&gt; ~/export_data_multiple_databases/obter_massa_dados.js &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; arquivo_resultado.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Usando o --eval:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mongosh mongodb://localhost:27017/examples &lt;span class="nt"&gt;--quiet&lt;/span&gt; &lt;span class="nt"&gt;--eval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"load('export_data_multiple_databases/obter_massa_dados.js');"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; arquivo_resultado.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Ao examinar novamente o arquivo, nota-se que o cabeçalho sumiu e com isso temos um arquivo .json válido e somente com os dados solicitados.&lt;/p&gt;
&lt;h2&gt;
  
  
  Impressões e Conclusão
&lt;/h2&gt;

&lt;p&gt;A ideia deste post surgiu de uma tarefa que solicitava a exportação de dados oriundos de um schema específico para csv. Tal schema existia em diversas collections com documentos que possuiam campos diferentes entre si. O único ponto em comum dessas collections era justamente um subdocumento com o schema em questão.&lt;br&gt;
Como não sou um profundo conhecedor de mongodb e não encontrei uma forma fácil na documentação e muito menos no stackoverflow e afins, resolvi ser criativo. Me vali da capacidade do mongodb de executar scripts .js e de conhecimentos básicos de shell.&lt;/p&gt;

&lt;p&gt;A solução é um tanto verbosa, porém resolveu meu problema de forma simples e eficiente. Imagino que os especialistas em mongodb vão me contar nos comentários:&lt;br&gt;
&lt;em&gt;- basta rodar essa linha de comando que você obtém o mesmo resultado&lt;/em&gt;&lt;br&gt;
Mas até lá, vou seguir usando a mesma abordagem para obter esses dados sempre que forem solicitados.&lt;/p&gt;

&lt;p&gt;No github (pasta export_data_multiple_databases) deixei o passo a passo de como reproduzir esse post.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/julianopoveda" rel="noopener noreferrer"&gt;
        julianopoveda
      &lt;/a&gt; / &lt;a href="https://github.com/julianopoveda/mongoblogposts" rel="noopener noreferrer"&gt;
        mongoblogposts
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Quero deixar um agradecimento especial para o &lt;a href="https://www.instagram.com/lucenacaio/" rel="noopener noreferrer"&gt;Caio Lucena&lt;/a&gt;  pelas revisões dos posts publicados até agora. &lt;/p&gt;

&lt;h2&gt;
  
  
  Referências
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.mongodb.com/mongodb-shell/" rel="noopener noreferrer"&gt;https://docs.mongodb.com/mongodb-shell/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://stackoverflow.com/a/33107939" rel="noopener noreferrer"&gt;Solução do Erro: Como importar data em formato string como tipo date&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>mongoshell</category>
      <category>mongotools</category>
    </item>
    <item>
      <title>Exportando campos específicos com mongoexport</title>
      <dc:creator>Poveda</dc:creator>
      <pubDate>Thu, 12 Aug 2021 10:52:39 +0000</pubDate>
      <link>https://dev.to/poveda/exportando-campos-especificos-com-mongoexport-1922</link>
      <guid>https://dev.to/poveda/exportando-campos-especificos-com-mongoexport-1922</guid>
      <description>&lt;p&gt;No post anterior expliquei como filtrar os dados da base antes de exportá-los. O filtro é muito útil para obtermos somente os dados desejados já no momento da exportação e assim reduzir a carga na rede. No entanto, quando a exportação é realizada, o &lt;em&gt;document&lt;/em&gt; inteiro é exportado. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;E se quisermos somente alguns campos daquele &lt;em&gt;document&lt;/em&gt;?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;É para esses casos que o mongoexport possui as opções --fields e --fieldFile.&lt;/p&gt;

&lt;h2&gt;
  
  
  O parâmetro &lt;a href="https://docs.mongodb.com/database-tools/mongoexport/#std-option-mongoexport.--fields" rel="noopener noreferrer"&gt;--fields&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;O parâmetro field recebe os campos desejados separados por vírgula diretamente no comando do mongoexport. Pode ser adicionado qualquer campo do document, incluindo os campos de subdocuments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mongoexport.exe mongodb://localhost:27017 &lt;span class="nt"&gt;--db&lt;/span&gt; example &lt;span class="nt"&gt;-c&lt;/span&gt; cars &lt;span class="nt"&gt;--queryFile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"~/filter2.json"&lt;/span&gt; &lt;span class="nt"&gt;--fields&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"ano,fabricante,motorizacao.litros"&lt;/span&gt; &lt;span class="nt"&gt;--csv&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Note que além do parâmetro --fields, também utilizei o parâmetro --csv para forçar a exportação em csv, pois no json (formato de exportação padrão) existem algumas peculiaridades.&lt;/p&gt;

&lt;p&gt;O resultado obtido rodando o comando na nossa base de testes foi o seguinte&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ano,fabricante,motorizacao.litros
1984,Toyota,1.6
1994,Toyota,2.2
1976,Toyota,1.4
2001,Toyota,1.8
1976,Toyota,1.6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Peculiaridades da exportação em json
&lt;/h3&gt;

&lt;p&gt;Quando a opção de exportação é json (default), o campo _id também é exportado, independentemente de ter sido adicionado a lista ou não.&lt;br&gt;
Outra particularidade é que se um campo do subdocument for adicionado como campo de exportação, todos os campos do subdocument serão exportados.&lt;/p&gt;
&lt;h4&gt;
  
  
  Exportação sem um campo do subdocument
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mongoexport.exe mongodb://localhost:27017 &lt;span class="nt"&gt;--db&lt;/span&gt; example &lt;span class="nt"&gt;-c&lt;/span&gt; cars &lt;span class="nt"&gt;--queryFile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"~/filter2.json"&lt;/span&gt; &lt;span class="nt"&gt;--fields&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"ano,fabricante"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;O resultado obtido foi o seguinte&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"_id"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"$oid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"60f6e2eefc13ae490c000bb8"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"ano"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1984&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"fabricante"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Toyota"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"_id"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"$oid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"60f6e2eefc13ae490c000d61"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"ano"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1994&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"fabricante"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Toyota"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"_id"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"$oid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"60f6e2effc13ae490c000d91"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"ano"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1976&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"fabricante"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Toyota"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"_id"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"$oid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"60f6e2effc13ae490c000e76"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"ano"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2001&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"fabricante"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Toyota"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"_id"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"$oid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"60f6e2effc13ae490c000e93"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"ano"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1976&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"fabricante"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Toyota"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Conforme foi descrito anteriormente, o campo _id(pk do registro) foi exportado mesmo que ele não conste nos campos no parâmetro --fields&lt;/p&gt;
&lt;h4&gt;
  
  
  Exportação com um campo do subdocument.
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mongoexport.exe mongodb://localhost:27017 &lt;span class="nt"&gt;--db&lt;/span&gt; example &lt;span class="nt"&gt;-c&lt;/span&gt; cars &lt;span class="nt"&gt;--queryFile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"~/filter2.json"&lt;/span&gt; &lt;span class="nt"&gt;--fields&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"ano,fabricante, motorizacao.litros"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Como pode ser visto neste exemplo, só foi pedido para retornar o campo litros do subdocument motorização, no entando o resultado listado abaixo, mostra que o campo &lt;strong&gt;hp&lt;/strong&gt; foi enviado para o resultado final&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"_id"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"$oid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"60f6e2eefc13ae490c000bb8"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"ano"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1984&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"fabricante"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Toyota"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"motorizacao"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"litros"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;1.6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"hp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;190&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"_id"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"$oid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"60f6e2eefc13ae490c000d61"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"ano"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1994&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"fabricante"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Toyota"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"motorizacao"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"litros"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;2.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"hp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;221&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"_id"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"$oid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"60f6e2effc13ae490c000d91"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"ano"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1976&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"fabricante"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Toyota"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"motorizacao"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"litros"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;1.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"hp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;134&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"_id"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"$oid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"60f6e2effc13ae490c000e76"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"ano"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2001&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"fabricante"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Toyota"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"motorizacao"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"litros"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;1.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"hp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;140&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"_id"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"$oid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"60f6e2effc13ae490c000e93"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"ano"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1976&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"fabricante"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Toyota"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"motorizacao"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"litros"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;1.6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"hp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;134&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  O parâmetro &lt;a href="https://docs.mongodb.com/database-tools/mongoexport/#std-option-mongoexport.--fieldFile" rel="noopener noreferrer"&gt;--fieldFile&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Com o parâmetro --fieldFile é possível passar o caminho de um arquivo que contém a lista de campos a serem exportados. Cada linha deve conter somente um campo, caso contrário ocorre erro na exportação. Infelizmente este parâmetro só pode ser utilizado para as exportações do tipo &lt;strong&gt;--csv&lt;/strong&gt;, sendo ignorado quando a exportação é para json.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mongoexport.exe mongodb://localhost:27017 &lt;span class="nt"&gt;--db&lt;/span&gt; example &lt;span class="nt"&gt;-c&lt;/span&gt; cars &lt;span class="nt"&gt;--queryFile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"~/filter2.json"&lt;/span&gt; &lt;span class="nt"&gt;--fieldFile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"~/fields_to_export.txt"&lt;/span&gt; &lt;span class="nt"&gt;--csv&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Resultado da execução&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fabricante,ano,motorizacao.hp
Toyota,1984,190
Toyota,1994,221
Toyota,1976,134
Toyota,2001,140
Toyota,1976,134
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Impressões e Conclusão
&lt;/h2&gt;

&lt;p&gt;Vejo que estes parâmetros são muito úteis, principalmente se necessitamos exportar determinados campos do banco para um arquivo csv que poderá ser utilizado em algum teste de cargas ou importação em outros sistemas, pois com a seleção dos campos é possível planificar um documento do mongo.&lt;br&gt;
Já para a exportação em json, vejo este método como uma forma de sanitizar campos do documento principal, deixando somente os campos relevantes para uma nova base de dados ou arquivo de mock.&lt;/p&gt;

&lt;p&gt;O que me motivou a escrever esse post foi uma extrapolação do &lt;a href="https://dev.to/poveda/exportando-dados-filtrados-com-mongoexport-1k36"&gt;post anterior&lt;/a&gt; quando pensei:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Consegui filtrar os dados, mas e se eu quiser retornar somente determinados campos como no sql? Será que consigo?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No github (pasta fields_mongoexport) deixei o passo a passo de como reproduzir esse post.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/julianopoveda" rel="noopener noreferrer"&gt;
        julianopoveda
      &lt;/a&gt; / &lt;a href="https://github.com/julianopoveda/mongoblogposts" rel="noopener noreferrer"&gt;
        mongoblogposts
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  Referencias
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.mongodb.com/database-tools/mongoexport/" rel="noopener noreferrer"&gt;https://docs.mongodb.com/database-tools/mongoexport/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>mongoexport</category>
      <category>mongotools</category>
    </item>
    <item>
      <title>Exportando dados filtrados com mongoexport</title>
      <dc:creator>Poveda</dc:creator>
      <pubDate>Thu, 29 Jul 2021 12:16:34 +0000</pubDate>
      <link>https://dev.to/poveda/exportando-dados-filtrados-com-mongoexport-1k36</link>
      <guid>https://dev.to/poveda/exportando-dados-filtrados-com-mongoexport-1k36</guid>
      <description>&lt;p&gt;Quem já precisou filtrar os dados da base antes de exportar sabe que nem sempre é uma tarefa simples. Quando falamos de mongodb essa situação fica um pouco mais complicada, pois as ferramentas visuais (como Compass e robo 3T) não possuem uma forma direta de salvar as consultas.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Falei besteira?&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Comenta no post e me ajuda a melhorar a difusão de conhecimento :)&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Para esses casos o mongo possui as ferramentas cli conhecidas como &lt;a href="https://docs.mongodb.com/database-tools/mongoexport/" rel="noopener noreferrer"&gt; mongoexport&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;resumo: Exporta os dados em formato json ou csv&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Executar o mongoexport é bem direto. No exemplo abaixo já é possível obter uma massa de dados da tabela desejada.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mongoexport mongodb://localhost:27017 &lt;span class="nt"&gt;--db&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;example &lt;span class="nt"&gt;-c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;carros
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  O parâmetro &lt;a href="https://docs.mongodb.com/database-tools/mongoexport/#std-option-mongoexport.--query" rel="noopener noreferrer"&gt;--query&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;O parâmetro query recebe como valor um &lt;a href="https://docs.mongodb.com/manual/reference/mongodb-extended-json/" rel="noopener noreferrer"&gt;json (padrão extended v2)&lt;/a&gt; o qual será utilizado como critério pela ferramenta na hora de selecionar quais documentos devem ser exportados.&lt;/p&gt;

&lt;p&gt;Os atributos de pesquisa permitidos estão restritos aos &lt;a href="https://docs.mongodb.com/manual/reference/operator/query/#query-selectors" rel="noopener noreferrer"&gt;query selectors&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Atributos de aggregation não são permitidos&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mongoexport mongodb://localhost:27017 &lt;span class="nt"&gt;--db&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;example &lt;span class="nt"&gt;-c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;carros &lt;span class="nt"&gt;--query&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{ "modelo":"Dodge", "ano":{ "$gt": 2011 } }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  O parâmetro --queryFile
&lt;/h2&gt;

&lt;p&gt;Já o &lt;strong&gt;--queryFile&lt;/strong&gt; recebe o caminho do arquivo json. Este arquivo funciona da mesma maneira, incluindo as restrições, que o json inline passado no parâmetro --query.&lt;/p&gt;

&lt;p&gt;Exemplo de arquivo json&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"modelo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Dodge"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ano"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"$gt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2011&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mongoexport mongodb://localhost:27017 &lt;span class="nt"&gt;--db&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;example &lt;span class="nt"&gt;-c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cars &lt;span class="nt"&gt;--queryFile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"~/filtros.json"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Impressões e Conclusão
&lt;/h2&gt;

&lt;p&gt;Dadas as duas abordagens, eu prefiro a segunda por ser mais simples de ler e manter do que a abordagem com a query inline.Porém, se a consulta for simples e pontual (não sendo necessário compartilhá-la ou salvá-la para uso posterior), utilizaria o inline por ser mais direto e menos burocrático.&lt;/p&gt;

&lt;p&gt;O que me motivou a escrever esse post foi a necessidade de realizar um export de uma quantidade significativa de dados para outra aplicação sem onerar a aplicação existente. O principal desafio de tal consulta, foi ter de encontrar uma solução que não envolve-se o uso de filtros do método &lt;em&gt;aggregate&lt;/em&gt;. Com um pouco de busca na documentação oficial do mongodb, imaginação e validação dos dados(aquele diff salvador), consegui realizar a exportação dos dados.&lt;/p&gt;

&lt;p&gt;No github (pasta quering_mongoexport) deixei o passo a passo de como reproduzir esse post.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/julianopoveda" rel="noopener noreferrer"&gt;
        julianopoveda
      &lt;/a&gt; / &lt;a href="https://github.com/julianopoveda/mongoblogposts" rel="noopener noreferrer"&gt;
        mongoblogposts
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  Referencias
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.mongodb.com/database-tools/mongoexport/" rel="noopener noreferrer"&gt;https://docs.mongodb.com/database-tools/mongoexport/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.mongodb.com/manual/reference/operator/query/#query-selectors" rel="noopener noreferrer"&gt;https://docs.mongodb.com/manual/reference/operator/query/#query-selectors&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.mongodb.com/manual/reference/mongodb-extended-json/" rel="noopener noreferrer"&gt;https://docs.mongodb.com/manual/reference/mongodb-extended-json/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>mongoexport</category>
      <category>mongotools</category>
    </item>
  </channel>
</rss>
