<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[SimplesCloud]]></title><description><![CDATA[Um blog de Cloud DevOps • SRE para compartilhar meus estudos, o que aprendi e experiências através de artigos, tutoriais, cursos gratuitos, cases e dicas. Confira!]]></description><link>https://simplescloud.com.br</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1730669355085/41756266-d860-44ed-8995-03e31e71977a.jpeg</url><title>SimplesCloud</title><link>https://simplescloud.com.br</link></image><generator>RSS for Node</generator><lastBuildDate>Sun, 12 Apr 2026 14:05:54 GMT</lastBuildDate><atom:link href="https://simplescloud.com.br/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Como Reiniciar Automaticamente um Droplet do Digital Ocean]]></title><description><![CDATA[Introdução
Você pode ter diversos motivos diferentes para querer reiniciar automaticamente um droplet no Digital Ocean, se você estiver procurando por alguma opção no console, observará algo parecido com essa imagem:

Há apenas duas opções disponívei...]]></description><link>https://simplescloud.com.br/como-reiniciar-automaticamente-um-droplet-do-digital-ocean</link><guid isPermaLink="true">https://simplescloud.com.br/como-reiniciar-automaticamente-um-droplet-do-digital-ocean</guid><category><![CDATA[reboot-droplet]]></category><category><![CDATA[reiniciar-droplet]]></category><category><![CDATA[auto-reboot-droplet]]></category><category><![CDATA[auto-reiniciar-droplet]]></category><category><![CDATA[droplet]]></category><dc:creator><![CDATA[SimplesCloud]]></dc:creator><pubDate>Fri, 21 Nov 2025 03:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1710697594914/dc2a635d-2ea9-41c4-962d-8e5f42e01248.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introducao">Introdução</h2>
<p>Você pode ter diversos motivos diferentes para querer reiniciar automaticamente um droplet no Digital Ocean, se você estiver procurando por alguma opção no console, observará algo parecido com essa imagem:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710707271333/c24d7cb9-3f96-4901-9569-424c303ecd95.png" alt class="image--center mx-auto" /></p>
<p>Há apenas duas opções disponíveis:</p>
<ul>
<li><p><code>Turn off</code></p>
</li>
<li><p><code>Power Cycle</code></p>
</li>
</ul>
<p>Mas infelizmente nenhuma que nos ajude a reiniciar nosso droplet.</p>
<p>Podemos também por exemplo acessar o droplet através de <code>SSH</code> e executar o comando:</p>
<pre><code class="lang-bash">sudo shutdown -r now
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Porém essa ação ainda não é automática</div>
</div>

<p>Então se você está procurando uma forma de reiniciar automaticamente seu Droplet no Digital Ocean, compartilho neste artigo o passo a passo de como consegui fazer isso.</p>
<hr />
<h2 id="heading-resposta-curta">Resposta Curta</h2>
<p>1- Acesse seu Droplet através do <code>SSH</code> com seu aplicativo de terminal de sua preferência</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710961428221/26d5222d-4937-411d-8d00-fa5047bdca4e.png" alt class="image--center mx-auto" /></p>
<p>2- Copie e cole o comando:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Create reboot script file</span>
cat &lt;&lt;<span class="hljs-string">'EOF'</span> | sudo tee -a ~/reboot-script.sh &gt; /dev/null
<span class="hljs-comment">#!/bin/bash</span>

<span class="hljs-comment"># Add timestamp to the log file before shutdown</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Reboot initiated at <span class="hljs-subst">$(date)</span>"</span> &gt;&gt; ~/reboot-log.txt

<span class="hljs-comment"># Shutdown the machine</span>
sudo shutdown -r now
EOF

<span class="hljs-comment"># Set reboot script file executable</span>
chmod +x ~/reboot-script.sh &amp;&amp; \

(crontab -l 2&gt;/dev/null; \
<span class="hljs-built_in">echo</span> <span class="hljs-string">"0 7 * * * ~/reboot-script.sh"</span>; \
<span class="hljs-built_in">echo</span> <span class="hljs-string">"0 19 * * * ~/reboot-script.sh"</span>) | crontab - &amp;&amp; \

<span class="hljs-comment"># Create log file</span>
touch ~/reboot-log.txt &amp;&amp; \

<span class="hljs-comment"># Set logrotate to log file</span>
cat &lt;&lt;<span class="hljs-string">'EOF'</span> | sudo tee -a /etc/logrotate.conf &gt; /dev/null
~/reboot-log.txt {
    daily
    rotate 15
    compress
    delaycompress
    missingok
    notifempty
}
EOF
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710961502970/339fe41a-7d40-4691-a93e-f993c388ce75.png" alt class="image--center mx-auto" /></p>
<p>3- Edite o <code>cron</code> para os horários de sua preferência alterando esse trecho:</p>
<pre><code class="lang-bash">(crontab -l 2&gt;/dev/null; \
<span class="hljs-built_in">echo</span> <span class="hljs-string">"0 7 * * * ~/reboot-script.sh"</span>; \
<span class="hljs-built_in">echo</span> <span class="hljs-string">"0 19 * * * ~/reboot-script.sh"</span>) | crontab - &amp;&amp; \
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710961819862/24f6de9f-debf-42ac-9c50-9f917d81c725.png" alt class="image--center mx-auto" /></p>
<p>4- Pressione <code>Enter</code> para executar</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">☑</div>
<div data-node-type="callout-text">Pronto! Seu Droplet agora já está configurado para reiniciar automaticamente!</div>
</div>

<ul>
<li><p>Se você não editou o cron, ele irá reiniciar todos os dias as 07 e 19 horas UTC</p>
</li>
<li><p>Se você editou o cron, ele irá reiniciar de acordo com sua preferência</p>
</li>
</ul>
<p>Caso você queira entender um pouco mais sobre os detalhes do que foi feito, acompanhe nosso tutorial detalhado abaixo, senão achar necessário, você está pronto!</p>
<hr />
<h2 id="heading-tutorial">Tutorial</h2>
<p>1- Utilize seu terminal preferido e acesse seu Droplet através do <code>SSH</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710707465548/ef9c6316-c1eb-466c-b413-cf8bad76ad8d.png" alt class="image--center mx-auto" /></p>
<p>2- Crie um arquivo chamado <code>reboot-script.sh</code> com o comando:</p>
<pre><code class="lang-bash">touch reboot-script.sh
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710707361032/e8884833-f58a-4905-8f08-020579e31552.png" alt class="image--center mx-auto" /></p>
<p>3- Agora edite esse arquivo com o comando:</p>
<pre><code class="lang-bash">sudo nano reboot-script.sh
</code></pre>
<p>E adicione o seguinte conteúdo:</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>

<span class="hljs-comment"># Add timestamp to the log file before shutdown</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Reboot initiated at <span class="hljs-subst">$(date)</span>"</span> &gt;&gt; ~/reboot-log.txt

<span class="hljs-comment"># Shutdown the machine</span>
sudo shutdown -r now
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710707542402/eb870927-ca03-4c0b-8445-e3564e98697a.png" alt class="image--center mx-auto" /></p>
<p>4- Torne o arquivo executável com o comando:</p>
<pre><code class="lang-bash">chmod +x reboot-script.sh
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710707405037/908df890-3126-4894-a7da-b3fba7cf9113.png" alt class="image--center mx-auto" /></p>
<p>5- Edite o <code>crontab</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710707337095/315af6a9-d69e-4990-9011-d006b09e4954.png" alt class="image--center mx-auto" /></p>
<p>Por exemplo, para executar todos os dias às <code>07 horas UTC</code>, isso seria:</p>
<pre><code class="lang-bash">0 7 * * *
</code></pre>
<ul>
<li><p><strong>0</strong>: é o minuto em que o cron será executado. Neste caso, o que significa que a tarefa será executada quando o relógio marcar exatamente 0 minutos.</p>
</li>
<li><p><strong>7</strong>: é a hora em que o cron será executado. Neste caso, o que significa que a tarefa será executada às 7 horas.</p>
</li>
<li><p><strong>*</strong>: o asterisco é um caractere curinga que representa "todos". Quando usado nos campos de dias do mês e dias da semana, significa "todos os dias do mês" e "todos os dias da semana", respectivamente.</p>
</li>
</ul>
<p>Uma vez compreendido o formato do <code>cron</code>, e lembrando que você deve usar o horário em <code>UTC</code>, você pode ajustar para sua necessidade.</p>
<p>Depois disso, execute o comando:</p>
<pre><code class="lang-bash">crontab -e
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710707498427/19daa173-814c-467c-8e51-6e210ecba533.png" alt class="image--center mx-auto" /></p>
<p>E adicione o seguinte conteúdo na última linha:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Lembre-se de ajustar o exemplo abaixo para a expressão <code>cron</code> de sua escolha</div>
</div>

<pre><code class="lang-bash">0 7 * * * ~/reboot-script.sh
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710707582563/c72ff77e-1f7e-4e52-9c2e-28fc5e1397bd.png" alt class="image--center mx-auto" /></p>
<p>6- Crie o arquivo chamado <code>reboot-log.txt</code> com o comando:</p>
<pre><code class="lang-bash">touch reboot-log.txt
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710707608711/d52bf9c3-4919-4bfa-b877-974e7f1d6764.png" alt class="image--center mx-auto" /></p>
<p>7- Esse arquivo de log pode se tornar grande com o passar do tempo, então vamos automatizar a limpeza do tamanho dele também para que não ocupe muito espaço no disco com o comando:</p>
<pre><code class="lang-bash">sudo nano /etc/logrotate.conf
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710707522549/40b98114-32c8-4c41-a4cb-5fb097cf55b3.png" alt class="image--center mx-auto" /></p>
<p>E ao final do arquivo, adicione o conteúdo:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Isso irá manter os logs por 15 dias, você pode alterar o <code>rotate</code> para o número de sua preferência e necessidade.</div>
</div>

<pre><code class="lang-bash">~/reboot-log.txt {
    daily
    rotate 15
    compress
    delaycompress
    missingok
    notifempty
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710707757331/848c0aa0-baa9-4723-8c42-4bfeca4ca9ad.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Como usamos o editor nano, lembre-se de salvar pressionando <code>Ctrl + X + Y (yes) + Enter</code> em seu teclado para salvar.</div>
</div>

<hr />
<h2 id="heading-conclusao">Conclusão</h2>
<p>Vimos que não há opções disponíveis diretamente no console do Digital Ocean para reiniciar um Droplet até o momento que este artigo foi criado, também vimos que é possível reiniciar esse droplet através do <code>SSH</code> de forma manual, mas passamos por uma resposta curta com copiar e colar um único comando para atingir esse objetivo, até um tutorial mais detalhado para que você possa fazer o passo a passo que automatiza esse processo seguindo essa ordem de etapas:</p>
<ol>
<li><p>Crie um arquivo de script chamado <code>reboot-script.sh</code>, ele será responsável por adicionar linhas no log e reiniciar o droplet</p>
</li>
<li><p>Torne esse arquivo executável</p>
</li>
<li><p>Crie um arquivo chamado <code>reboot-log.txt</code>, ele será responsável por armazenar os logs de reinicialização</p>
</li>
<li><p>Configure um <code>log rotate</code> para este arquivo <code>reboot-log.txt</code>, ele será responsável por limpar e manter o arquivo de log otimizado</p>
</li>
<li><p>Configure um <code>cron</code> para executar o <code>reboot-script.sh</code>, ele será responsável por "chamar" nosso <code>reboot-script.sh</code> no horário adequado, desta forma adicionando uma linha no log e reiniciando o droplet</p>
</li>
</ol>
<p>Você pode visualizar o log com o comando:</p>
<pre><code class="lang-bash">cat reboot-log.txt
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710962849460/253aebc9-72a4-45d7-9c3f-7a1bb225445c.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Observe que na imagem acima, alterei em um dos dias o <code>cron</code> para <code>17 horas UTC</code>, era um horário que estava conectado no <code>SSH</code> e que podia testar seu reboot sem precisar aguardar o horário do <code>cron</code>, você pode fazer o mesmo para testar sem ter que ficar esperando, uma vez que achar que está certo, ajuste novamente o <code>cron</code> para seu horário de preferência.</div>
</div>

<p>Se você estiver buscando outras opções, talvez essas leituras e tutoriais sejam de seu interesse:</p>
<ul>
<li><p>👉 <a target="_blank" href="https://simplescloud.io/aprenda-a-reiniciar-sua-instancia-lightsail-com-agendamento-automatico">Aprenda a Reiniciar sua Instância Lightsail com Agendamento Automático</a></p>
</li>
<li><p>👉 <a target="_blank" href="https://simplescloud.io/aprenda-a-reiniciar-sua-instancia-ec2-com-agendamento-automatico">Aprenda a Reiniciar sua instância EC2 com Agendamento Automático</a></p>
</li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se de excluir todos os recursos ao final para não obter cobranças indesejadas e manter sua conta Digital Ocean limpa e organizada.</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Espero que essa informação tenha sido útil para você!</div>
</div>]]></content:encoded></item><item><title><![CDATA[Como Agendar um START/STOP Automático no Fargate]]></title><description><![CDATA[Introdução
Você pode ter diversos motivos e casos de uso diferentes para querer iniciar e parar de forma agendada e automática o AWS Fargate, no meu caso específico eu precisava de um Fargate para um ambiente de QA que não tinha a necessidade de esta...]]></description><link>https://simplescloud.com.br/como-agendar-um-start-stop-automatico-no-fargate</link><guid isPermaLink="true">https://simplescloud.com.br/como-agendar-um-start-stop-automatico-no-fargate</guid><category><![CDATA[aws-fargate-auto-start-stop]]></category><category><![CDATA[aws-fargate-start-stop-schedule]]></category><category><![CDATA[aws-fargate-agendamento-automatico]]></category><category><![CDATA[aws-fargate-iniciar-parar-agendamento-automatico]]></category><category><![CDATA[aws-fargate]]></category><category><![CDATA[AWS]]></category><dc:creator><![CDATA[SimplesCloud]]></dc:creator><pubDate>Tue, 16 Jul 2024 13:00:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730680196576/78fcdbcb-ebfc-4948-b979-32c2e42eef24.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introducao">Introdução</h2>
<p>Você pode ter diversos motivos e casos de uso diferentes para querer iniciar e parar de forma agendada e automática o AWS Fargate, no meu caso específico eu precisava de um Fargate para um ambiente de QA que não tinha a necessidade de estar funcionando o tempo todo, então precisava de alguma solução que me permitisse iniciar e parar o Fargate em horários agendados e de forma automática.</p>
<p>Isso me levou a analisar algumas opções, considerar alguns desafios e então este artigo irá descrever um pouco sobre tudo isso e demonstrar como consegui atingir esse objetivo.</p>
<hr />
<h2 id="heading-algumas-opcoes">Algumas Opções</h2>
<h3 id="heading-evite-usar-cron-dentro-de-um-container">Evite usar Cron dentro de um Container</h3>
<p>Parece ser uma escolha fácil e óbvia, assim como faria em uma instância Linux através de uma conexão SSH a configuração de um <code>crontab -e</code>, a primeira opção que nos vem na mente é:</p>
<blockquote>
<p>"E se eu acessar meu container e criar um <code>cron</code> nele também, da mesma forma que eu faria em uma instância Linux?"</p>
</blockquote>
<p>Alguns motivos para você responder <strong>não</strong> a esta pergunta são:</p>
<ul>
<li><p>Não é o padrão, seu container deve estar preocupado somente com o processo principal da sua aplicação, ele não deve se preocupar com processos adicionais como o <code>cron</code> por exemplo</p>
</li>
<li><p>Não é "limpo", nosso objetivo é iniciar e parar o Fargate, então a cada vez que isso acontecer, seguindo o princípio da infraestrutura imutável, um novo container será criado e não o mesmo, então se você não automatizar a criação do <code>cron</code>, não haverá nenhum sentido no que estamos tentando fazer aqui, além disso essa automatização pode ser um obstáculo desnecessário</p>
</li>
<li><p>Não é colaborativo e intuitivo, se você estiver em um projeto pequeno, ainda sim deverá lembrar dessa configuração, mas e se você estiver em um projeto maior e com uma equipe maior, certamente outros devs não lembrarão ou perceberão de forma fácil e intuitiva que existe um <code>cron</code> dentro do container</p>
</li>
</ul>
<hr />
<h3 id="heading-evite-usar-ecs-scheduled-tasks">Evite usar ECS Scheduled Tasks</h3>
<p>Essa seria a segunda opção óbvia a ser usada, pois podemos encontrar essa opção no console AWS:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712150046782/187bd270-f993-4cd3-9958-ecc8dcec03ba.png" alt class="image--center mx-auto" /></p>
<p>Porém, se possível evite usar essa opção ou pelo menos considere isso antes em seu caso de uso:</p>
<ul>
<li>Ao criar um <code>ECS Schedule Tasks</code>, no background a AWS estará criando de uma forma simplificada uma regra de evento no <code>Cloudwatch</code> que inicia uma <code>task</code> do Fargate com base no cronograma definido:</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712150520157/5c82cf5d-1ca4-4618-98e0-0af574183ea2.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>O motivo para eu sugerir você considerar evitar isso, é porque nessa abordagem faltam algumas coisas importantes como:</p>
<ul>
<li><p>Definir um tempo limite para o agendamento</p>
</li>
<li><p>Definir uma repetição se houver alguma falha no agendamento</p>
</li>
<li><p>Apenas inicia, mas não atualiza o número de tasks para cima ou para baixo</p>
</li>
<li><p>Também não interrompe as tasks, dessa forma não atualiza o tamanho desejado para 0</p>
</li>
<li><p>Em resumo, essa forma está operando no modo "disparar e esquecer", ou seja o Cloudwatch envia a requisição para iniciar e acaba nisso, sem garantias, sem controles e sem resiliência</p>
</li>
</ul>
</li>
</ul>
<p>Porém entendo que para alguns casos isso pode ser o suficiente e funcionar, só quis compartilhar esses pontos que achei relevante.</p>
<hr />
<h3 id="heading-prefira-usar-o-eventbridge">Prefira usar o EventBridge</h3>
<p>Essa seria a terceira opção que me veio a mente, a que acabei utilizando e a que descreverei o passo a passo de como consegui fazer isso, mas antes algumas notas importantes também:</p>
<ul>
<li><p>Ao contrário da abordagem anterior, aqui há mais resiliência, pois o <code>EventBridge</code> não irá apenas iniciar uma task, mas ele também terá a capacidade de atualizar o número de tasks para cima, para baixo ou interromper atualizando o tamanho desejado para 0</p>
</li>
<li><p>O <code>EventBridge</code> possui opções mais avançadas e flexíveis que você poderá escolher se houver uma falha, como por exemplo se irá monitorar isso, se tentará novamente, se deseja adicionar em uma fila de processamento ou outra ação que você deseja tomar</p>
</li>
<li><p>O <code>EventBridge</code> é mais avançado, permite chamar o nível da API ECS Fargate passando uma carga personalizada com <code>JSON</code>, que ajuda a personalizar a chamada API conforme necessário</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712153290506/30aabe2f-fe40-4ed7-bc98-cfc18bc1f85c.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-tutorial">Tutorial</h2>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Esse tutorial está considerando o START/STOP para um <strong>serviço</strong> do Fargate, e não para tasks individuais (sem serviço) e também não a nível de cluster para todos os serviços dentro dele, mas sim para um único serviço do Fargate dentro de um Cluster.</div>
</div>

<p>1- Acesse o console <strong>AWS → IAM → Policies → crie uma política</strong> conforme abaixo:</p>
<p><code>Name:</code></p>
<ul>
<li><p>Defina um nome de sua preferência</p>
</li>
<li><p>Por exemplo:</p>
<ul>
<li><code>ecs-fargate-scheduler-qa-policy</code></li>
</ul>
</li>
</ul>
<p><code>Description:</code></p>
<ul>
<li><p>Defina uma descrição de sua preferência</p>
</li>
<li><p>Por exemplo:</p>
<ul>
<li><code>Policy that grants EventBridge permission to automatically start and stop Fargate tasks in the QA environment</code></li>
</ul>
</li>
</ul>
<pre><code class="lang-json">{
    <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
    <span class="hljs-attr">"Statement"</span>: [
        {
            <span class="hljs-attr">"Sid"</span>: <span class="hljs-string">"VisualEditor0"</span>,
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Action"</span>: [
                <span class="hljs-string">"ecs:ListServicesByNamespace"</span>,
                <span class="hljs-string">"ecs:GetTaskProtection"</span>,
                <span class="hljs-string">"ecs:ListAttributes"</span>,
                <span class="hljs-string">"ecs:DescribeTaskSets"</span>,
                <span class="hljs-string">"ecs:DescribeTaskDefinition"</span>,
                <span class="hljs-string">"ecs:DescribeClusters"</span>,
                <span class="hljs-string">"ecs:ListServices"</span>,
                <span class="hljs-string">"ecs:ListAccountSettings"</span>,
                <span class="hljs-string">"ecs:DescribeCapacityProviders"</span>,
                <span class="hljs-string">"ecs:ListTagsForResource"</span>,
                <span class="hljs-string">"ecs:ListTasks"</span>,
                <span class="hljs-string">"ecs:ListTaskDefinitionFamilies"</span>,
                <span class="hljs-string">"ecs:DescribeServices"</span>,
                <span class="hljs-string">"ecs:ListContainerInstances"</span>,
                <span class="hljs-string">"ecs:DescribeContainerInstances"</span>,
                <span class="hljs-string">"ecs:DescribeTasks"</span>,
                <span class="hljs-string">"ecs:ListTaskDefinitions"</span>,
                <span class="hljs-string">"ecs:ListClusters"</span>,
                <span class="hljs-string">"ecs:UpdateService"</span>
            ],
            <span class="hljs-attr">"Resource"</span>: <span class="hljs-string">"*"</span>
        }
    ]
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712154063107/c0a154a1-8e59-4ffc-b1ee-93b00c218c42.png" alt class="image--center mx-auto" /></p>
<p>2- Agora vá para <strong>IAM → Role → crie uma role</strong> conforme abaixo:</p>
<ul>
<li><p><code>Name:</code></p>
<ul>
<li><p>Defina um nome de sua preferência</p>
</li>
<li><p>Por exemplo:</p>
<ul>
<li><code>ecs-fargate-scheduler-qa-role</code></li>
</ul>
</li>
</ul>
</li>
<li><p><code>Description:</code></p>
<ul>
<li><p>Defina uma descrição de sua preferência</p>
</li>
<li><p>Por exemplo:</p>
<ul>
<li><code>Role with necessary EventBridge permissions to automatically start and stop Fargate tasks in the QA environment</code></li>
</ul>
</li>
</ul>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712154620079/8888d667-53a1-4dab-b059-0c4dd14c049a.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712154685762/784e6a82-bbb0-4d96-be27-9b6eb46d862c.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Remova a política anexada automaticamente</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712154821801/0895780f-fea0-4f60-b161-3c11e485a9b3.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Adicione a política que criamos nesta role</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712154967263/aac37703-8d37-485b-b460-52fe080c6b2f.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712155022060/a754b106-e77a-43c7-b2de-bf213de3126e.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Edite a aba <code>Trust Relashionship</code> para conceder permissão ao <code>EventBridge</code>, conforme abaixo</div>
</div>

<pre><code class="lang-json">{
    <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
    <span class="hljs-attr">"Statement"</span>: [
        {
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Principal"</span>: {
                <span class="hljs-attr">"Service"</span>: <span class="hljs-string">"scheduler.amazonaws.com"</span>
            },
            <span class="hljs-attr">"Action"</span>: <span class="hljs-string">"sts:AssumeRole"</span>
        }
    ]
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712155108350/4e1084fd-68df-4896-b4b0-89fec19087de.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712155183891/2c3c8c3a-f538-436a-a2b8-fd1c0b2fea80.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712772037873/73470231-d999-4ff4-a142-7fb30ad7c461.png" alt class="image--center mx-auto" /></p>
<hr />
<p>3- Agora vá para o console <strong>AWS → EventBridge → Rules → Create rule</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712155395639/5baeb5f7-5f09-4500-831a-9842e7e49d90.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712155489308/dfe8e6f7-d100-4208-b484-096ce80bf39d.png" alt class="image--center mx-auto" /></p>
<p>4- Defina um nome e descrição de sua preferência, por exemplo:</p>
<ul>
<li><p><strong>Name:</strong><code>fargate-start-tasks-qa-monday-to-friday-morning</code></p>
</li>
<li><p><strong>Description:</strong><code>Rule that automatically starts QA environment ECS Fargate</code></p>
</li>
<li><p>Altere para a opção <code>Schedule</code></p>
</li>
<li><p>Clique em <code>Continue in EventBridge Scheduler</code></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712155787463/11339b8c-a9b2-4c7a-a894-279043ed7a32.png" alt class="image--center mx-auto" /></p>
<p>5- Altere para <code>Recurring schedule</code> → defina uma expressão <code>cron</code> de sua preferência</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Por exemplo, eu gostaria de iniciar as tasks no Fargate de segunda a sexta as 9 horas (horário de Brasília)</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712156399173/4e15e434-0d73-442d-b596-a858797e2090.png" alt class="image--center mx-auto" /></p>
<p>Por exemplo, para executar de segunda a sexta às <code>09 horas</code> (UTC -3), isso seria:</p>
<pre><code class="lang-bash">00 9 ? * MON-FRI *
</code></pre>
<ul>
<li><p><strong>00</strong>: é o minuto em que o cron será executado. Neste caso, o que significa que a tarefa será executada quando o relógio marcar exatamente 0 minutos.</p>
</li>
<li><p><strong>9</strong>: é a hora em que o cron será executado. Neste caso, o que significa que a tarefa será executada às 9 horas. (UTC -3)</p>
</li>
<li><p><strong>?:</strong> isso indica que não estamos definindo um dia específico do mês. A tarefa será executada independentemente do dia do mês.</p>
</li>
<li><p><strong>*</strong>: isso indica que a tarefa será executada em todos os meses. Não estamos definindo um mês específico.</p>
</li>
<li><p><strong>MON-FRI</strong>: especifica os dias da semana em que a tarefa será executada. Neste caso, a tarefa será executada de segunda a sexta-feira.</p>
</li>
<li><p><strong>*</strong>: indica que a tarefa será executada em todos os anos. Não estamos definindo um ano específico.</p>
</li>
</ul>
<p>Uma vez compreendido o formato do <code>cron</code>, lembre-se de ajustar seu <code>Time Zone</code> e preencher de acordo com suas necessidades.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712157457290/69fe2d29-acee-41bb-bb6f-c5bbd119c624.png" alt class="image--center mx-auto" /></p>
<p>6- Defina a opção <code>Flexible Time Window</code>, essa opção é útil quando você quiser que o <code>EventBridge</code> funcione dentro do tempo dessa janela que você definiu, pense nisso em casos que as tasks ou targets ainda não estão prontos, desta forma você define um intervalo de tempo para que isso seja feito.</p>
<p>Por exemplo, se eu definisse o <code>cron as 9 horas</code> e um <code>Flexible Time Window de 15 minutos</code>, na prática significa que o <code>EventBridge Scheduler</code> garantirá que ele seja executado dentro deste período, ou seja entre <code>9:00 às 9:15</code>, mas isso não significa que ele será executado as <code>9:15</code>, mas sim que será acionado dentro deste intervalo a qualquer momento a partir do horário agendado (no exemplo as <code>9:00 + flexible time window</code>).</p>
<p>Isso é muito bom para distribuir as execuções nesta janela de tempo, reduzindo os impactos de várias solicitações ao mesmo tempo em um ambiente grande.</p>
<p>Como neste meu caso isso não é um requisito necessário, defino como <code>Off</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712157724902/83d52048-0374-4e1f-9365-382035d0b6d2.png" alt class="image--center mx-auto" /></p>
<p>7- Você também pode definir uma data de início e término, como eu espero que a expressão <code>cron</code> funcione e não planejo inserir uma data para que esse <code>cron</code> comece a funcionar ou terminar, <strong>não preencho</strong> e clico em <code>Next</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712161872657/54132aa9-b8ce-41c5-85e7-5805fa61988f.png" alt class="image--center mx-auto" /></p>
<p>8- Agora altere para <code>All APIs</code> → pesquise por <code>ecs</code> → selecione a opção <code>ECS</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712162072765/01b311ac-2b68-4bc2-8966-3120e6fef809.png" alt class="image--center mx-auto" /></p>
<p>9- Agora pesquise por <code>update</code> → selecione a opção <code>UpdateService</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712162193596/2dd25538-1c92-445a-9fb8-a144e664ee94.png" alt class="image--center mx-auto" /></p>
<p>10- Como nessa regra estamos querendo iniciar o Fargate, defino o campo <code>DesiredCount</code> como 1 para então ter uma task em execução, você pode ajustar isso para suas necessidades e preferência:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Lembre-se de alterar <code>&lt;Service-ARN&gt;</code> e <code>&lt;Cluster-ARN&gt;</code> para seus valores reais</div>
</div>

<pre><code class="lang-json">{
     <span class="hljs-attr">"DesiredCount"</span>: <span class="hljs-number">1</span>,
     <span class="hljs-attr">"Service"</span>: <span class="hljs-string">"&lt;Service-ARN&gt;"</span>,
     <span class="hljs-attr">"Cluster"</span>: <span class="hljs-string">"&lt;Cluster-ARN&gt;"</span>

}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712162373517/829c41d1-927c-4e43-b9b7-3f9eba42f4ae.png" alt class="image--center mx-auto" /></p>
<p>11- Deixo a opção <code>Schedule</code><strong>habilitada</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712162487788/6deb866d-c979-46e6-b08b-1501924f4dd5.png" alt class="image--center mx-auto" /></p>
<p>12- Não defino nenhuma ação após o agendamento ser executado, pois neste caso de uso não planejo excluir o agendamento</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712162750996/1194d900-0a48-43de-bb55-48f932613017.png" alt class="image--center mx-auto" /></p>
<p>13- Agora você pode definir uma <code>DLQ (Dead Letter Queue)</code>, isso seria uma fila <code>SQS</code> para armazenar os eventos que falharam, aqui ainda existem dois tipos:</p>
<ul>
<li><p><strong>Recuperáveis</strong></p>
<ul>
<li>Se houver uma falha ou uma entrega mal sucedida no <code>target (que no nosso caso é a API UpdateService do ECS)</code>, por padrão o EventBridge tentará fazer ela novamente por 24 horas e até 185 vezes.</li>
</ul>
</li>
<li><p><strong>Não recuperáveis</strong></p>
<ul>
<li>Se houver um erro não recuperável, como <code>AccessDenied</code> por exemplo, isso não será repetido pelo EventBridge, mas ele poderá adicionar se você quiser isso em uma fila DLQ para ser tratado ou processado posteriormente</li>
</ul>
</li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Mesmo desabilitando a opção <code>Retry Policy</code>, ainda sim o EventBridge tentará repetir para eventos recuperáveis por 24 horas e até 185 vezes. Isso é um comportamento padrão, você configurando ou não.</div>
</div>

<p>Para este tutorial, defino isso como <code>Disable</code>, mas se isso for importante para você, este é o momento de configurar de acordo com suas preferências:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712163699095/40c03df6-e176-4b4b-b9d1-cf9c02bb3e6d.png" alt class="image--center mx-auto" /></p>
<p>14- Não defino nenhuma criptografia</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712163737855/b07d1ae9-1c12-4185-a7ae-a804f0411565.png" alt class="image--center mx-auto" /></p>
<p>15- Seleciono a <code>Role</code> que criamos no início do tutorial</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712163804355/8376dcfe-5461-4e9e-bbb0-de5b9212419a.png" alt class="image--center mx-auto" /></p>
<p>16- Clico em <code>Create</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712163915275/b270e815-da93-45fb-b347-fedb1f20dba2.png" alt class="image--center mx-auto" /></p>
<hr />
<p>Pronto! 😄</p>
<p>Porém criamos até agora apenas para iniciar o Fargate, ainda falta uma parte importante que seria parar o Fargate, para isso basta repetir os mesmos passos, porém mudando os nomes, descrições e principalmente o código <code>JSON</code> para o <code>DesireCount</code> igual a 0, isso significa que não desejamos nenhuma task em execução:</p>
<pre><code class="lang-json">{
     <span class="hljs-attr">"DesiredCount"</span>: <span class="hljs-number">0</span>,
     <span class="hljs-attr">"Service"</span>: <span class="hljs-string">"&lt;Service-ARN&gt;"</span>,
     <span class="hljs-attr">"Cluster"</span>: <span class="hljs-string">"&lt;Cluster-ARN&gt;"</span>

}
</code></pre>
<p>Para não tornar o tutorial muito grande e ser repetitivo, não vou descrever todo o passo a passo novamente, mas para sua comodidade, aqui estariam a sequência de imagens para parar o Fargate também:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712164202206/16f2b802-99e4-4311-9352-83cc03372e45.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712164337268/d789db10-dde5-418a-ad34-9ab1d0da8eda.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712164518730/39346c86-ec36-4bf0-8a2d-a29cc5e62904.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712164588037/e429b9ed-5d6c-478c-965b-0a3f26059843.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712164625792/945d995b-d6b8-48e0-8508-fabaa7a013d9.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712164693919/48aae342-3e94-43a8-b82b-3cfd8f1a4159.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-limitacoes">Limitações</h2>
<ul>
<li><p>O Event Bridge é capaz de fazer um único request por vez, isso significa que você não pode adicionar vários Fargates no mesmo request, e isso pode gerar duplicação de trabalho, pois deverá repetir este passo a passo para cada Fargate que desejar.</p>
</li>
<li><p>O Fargate e o Event Bridge precisam estar na mesma região.</p>
</li>
</ul>
<hr />
<h2 id="heading-conclusao">Conclusão</h2>
<p>Pronto! 😄</p>
<p>Agora sim temos todo o nosso objetivo completo.</p>
<p>Vimos neste artigo algumas opções para iniciar e parar o Fargate, analisamos e consideramos alguns desafios e limitações entre as opções, elegemos o uso do EventBridge como melhor opção para este caso e fizemos um tutorial passo a passo para iniciar e parar o Fargate que faz:</p>
<ol>
<li><p>O <code>EventBridge Scheduler</code> configurado com uma expressão <code>cron</code> que <strong>inicia</strong> o Fargate enviando uma chamada <code>API</code> para o <code>UpdateService</code> do <code>ECS</code></p>
</li>
<li><p>Definindo o <code>DesiredCount</code> como <code>1</code> task por exemplo.</p>
</li>
<li><p>E também repetimos isso para <strong>parar</strong> o Fargate, mas agora definindo o <code>DesiredCount</code> para <code>0</code> para que não haja tasks em execução.</p>
</li>
</ol>
<hr />
<p>Por fim, depois que o <code>cron</code> for executado em seu horário definido, poderemos ver no <code>cluster</code> do fargate nenhuma task originada pelo nosso agendamento automático:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712181202837/d86e9787-705f-4b12-91d3-bd59607829a4.png" alt class="image--center mx-auto" /></p>
<p>E no <code>service</code> também podemos ver o <code>DesiredCount</code> como <code>0</code> como definimos:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712181185051/28c5efc1-ec33-483f-a4fe-4459791a82f8.png" alt class="image--center mx-auto" /></p>
<p>E depois novamente a task iniciada também pelo nosso agendamento automático em seu horário definido:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712762758540/0e9a6069-464a-44a5-9f1d-fac9de3cc06a.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712762887100/0ce16d17-4fa4-4248-a8b7-fb273dfc8af1.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se de excluir todos os recursos ao final para não obter cobranças indesejadas e manter sua conta AWS limpa e organizada.</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Espero que essas informações tenham sido úteis para você!</div>
</div>]]></content:encoded></item><item><title><![CDATA[Como Agendar um START/STOP Automático no RDS]]></title><description><![CDATA[Introdução
Você pode ter vários motivos e razões diferentes para querer agendar um start e stop automático para o RDS. No meu caso eu estava criando um ambiente de QA onde não precisava que o RDS ficasse ligado o tempo todo para manter os custos redu...]]></description><link>https://simplescloud.com.br/como-agendar-um-start-stop-automatico-no-rds</link><guid isPermaLink="true">https://simplescloud.com.br/como-agendar-um-start-stop-automatico-no-rds</guid><category><![CDATA[aws-rds-start-stop]]></category><category><![CDATA[aws-rds-auto-start-stop]]></category><category><![CDATA[AWS RDS]]></category><category><![CDATA[AWS]]></category><dc:creator><![CDATA[SimplesCloud]]></dc:creator><pubDate>Mon, 15 Jul 2024 13:00:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730672555729/df26fb95-8e4e-457a-9db2-6b68af8ab5d4.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introducao">Introdução</h2>
<p>Você pode ter vários motivos e razões diferentes para querer agendar um <code>start</code> e <code>stop</code> automático para o RDS. No meu caso eu estava criando um ambiente de QA onde não precisava que o RDS ficasse ligado o tempo todo para manter os custos reduzidos, felizmente a AWS disponibilizou uma opção no console para parar temporariamente durante 7 dias seu RDS, isso pode ser encontrado em:</p>
<ul>
<li><code>Console AWS → RDS → DB Instance → Action → Stop</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712769349222/42062140-df20-4c44-ab2a-0f87ac674038.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712769460765/8a6ff51e-0ffb-416b-8504-2e3d8eaf72df.png" alt class="image--center mx-auto" /></p>
<p>Embora isso já ajude para muitos casos, não se encaixava muito bem ao que eu precisava, pois eu não gostaria de ficar repetindo essa tarefa e esses cliques, então era hora de pensar em uma solução e automatizar esse processo, compartilho neste artigo como consegui atingir esse objetivo.</p>
<hr />
<h2 id="heading-tutorial">Tutorial</h2>
<p>1- Acesse o console <strong>AWS → IAM → Policies → crie uma política</strong> conforme abaixo:</p>
<p><code>Name:</code></p>
<ul>
<li><p>Defina um nome de sua preferência</p>
</li>
<li><p>Por exemplo:</p>
<ul>
<li><code>rds-scheduler-qa-policy</code></li>
</ul>
</li>
</ul>
<p><code>Description:</code></p>
<ul>
<li><p>Defina uma descrição de sua preferência</p>
</li>
<li><p>Por exemplo:</p>
<ul>
<li><code>Policy that grants EventBridge permission to automatically start and stop RDS in the QA environment</code></li>
</ul>
</li>
</ul>
<pre><code class="lang-json">{
    <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
    <span class="hljs-attr">"Statement"</span>: [
        {
            <span class="hljs-attr">"Sid"</span>: <span class="hljs-string">"VisualEditor0"</span>,
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Action"</span>: [
                <span class="hljs-string">"rds:DescribeDBProxyTargetGroups"</span>,
                <span class="hljs-string">"rds:StartDBCluster"</span>,
                <span class="hljs-string">"rds:DescribeDBInstanceAutomatedBackups"</span>,
                <span class="hljs-string">"rds:DescribeDBRecommendations"</span>,
                <span class="hljs-string">"rds:DescribeGlobalClusters"</span>,
                <span class="hljs-string">"rds:DescribeEngineDefaultParameters"</span>,
                <span class="hljs-string">"rds:DescribeRecommendations"</span>,
                <span class="hljs-string">"rds:DescribeDBClusterAutomatedBackups"</span>,
                <span class="hljs-string">"rds:DescribeDBProxyTargets"</span>,
                <span class="hljs-string">"rds:DownloadDBLogFilePortion"</span>,
                <span class="hljs-string">"rds:DescribeSourceRegions"</span>,
                <span class="hljs-string">"rds:StopDBCluster"</span>,
                <span class="hljs-string">"rds:DescribeDBSnapshots"</span>,
                <span class="hljs-string">"rds:DescribeDBSecurityGroups"</span>,
                <span class="hljs-string">"rds:StartDBInstance"</span>,
                <span class="hljs-string">"rds:DescribeReservedDBInstances"</span>,
                <span class="hljs-string">"rds:DescribeBlueGreenDeployments"</span>,
                <span class="hljs-string">"rds:DescribeValidDBInstanceModifications"</span>,
                <span class="hljs-string">"rds:DescribeDbSnapshotTenantDatabases"</span>,
                <span class="hljs-string">"rds:DescribeIntegrations"</span>,
                <span class="hljs-string">"rds:DescribeOrderableDBInstanceOptions"</span>,
                <span class="hljs-string">"rds:DescribeCertificates"</span>,
                <span class="hljs-string">"rds:DescribeOptionGroups"</span>,
                <span class="hljs-string">"rds:DescribeDBShardGroups"</span>,
                <span class="hljs-string">"rds:DescribeDBEngineVersions"</span>,
                <span class="hljs-string">"rds:DescribeDBSubnetGroups"</span>,
                <span class="hljs-string">"rds:DescribeExportTasks"</span>,
                <span class="hljs-string">"rds:DescribeTenantDatabases"</span>,
                <span class="hljs-string">"rds:DescribePendingMaintenanceActions"</span>,
                <span class="hljs-string">"rds:DescribeDBParameterGroups"</span>,
                <span class="hljs-string">"rds:DescribeDBClusterBacktracks"</span>,
                <span class="hljs-string">"rds:DescribeReservedDBInstancesOfferings"</span>,
                <span class="hljs-string">"rds:DescribeRecommendationGroups"</span>,
                <span class="hljs-string">"rds:DescribeDBInstances"</span>,
                <span class="hljs-string">"rds:DescribeEngineDefaultClusterParameters"</span>,
                <span class="hljs-string">"rds:DescribeDBProxies"</span>,
                <span class="hljs-string">"rds:DescribeDBParameters"</span>,
                <span class="hljs-string">"rds:DescribeEventCategories"</span>,
                <span class="hljs-string">"rds:DescribeDBProxyEndpoints"</span>,
                <span class="hljs-string">"rds:DescribeEvents"</span>,
                <span class="hljs-string">"rds:DescribeDBClusterSnapshotAttributes"</span>,
                <span class="hljs-string">"rds:DescribeDBClusterParameters"</span>,
                <span class="hljs-string">"rds:DescribeEventSubscriptions"</span>,
                <span class="hljs-string">"rds:DescribeDBLogFiles"</span>,
                <span class="hljs-string">"rds:StopDBInstance"</span>,
                <span class="hljs-string">"rds:DescribeDBSnapshotAttributes"</span>,
                <span class="hljs-string">"rds:ListTagsForResource"</span>,
                <span class="hljs-string">"rds:DescribeDBClusterSnapshots"</span>,
                <span class="hljs-string">"rds:DescribeOptionGroupOptions"</span>,
                <span class="hljs-string">"rds:DownloadCompleteDBLogFile"</span>,
                <span class="hljs-string">"rds:DescribeDBClusterEndpoints"</span>,
                <span class="hljs-string">"rds:DescribeAccountAttributes"</span>,
                <span class="hljs-string">"rds:DescribeDBClusters"</span>,
                <span class="hljs-string">"rds:DescribeDBClusterParameterGroups"</span>
            ],
            <span class="hljs-attr">"Resource"</span>: <span class="hljs-string">"*"</span>
        }
    ]
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712769923600/aa2669bc-5b53-4dcc-a8f7-ce03132a86f0.png" alt class="image--center mx-auto" /></p>
<p>2- Agora vá para <strong>IAM → Role → crie uma role</strong> conforme abaixo:</p>
<ul>
<li><p><code>Name:</code></p>
<ul>
<li><p>Defina um nome de sua preferência</p>
</li>
<li><p>Por exemplo:</p>
<ul>
<li><code>rds-scheduler-qa-role</code></li>
</ul>
</li>
</ul>
</li>
<li><p><code>Description:</code></p>
<ul>
<li><p>Defina uma descrição de sua preferência</p>
</li>
<li><p>Por exemplo:</p>
<ul>
<li><code>Role with necessary EventBridge permissions to automatically start and stop RDS in the QA environment</code></li>
</ul>
</li>
</ul>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712770268858/eb1d758c-2f76-451c-88c5-f62a17cb3466.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Filtre por <code>Customer managed</code> e <code>rds</code> → selecione a política que criamos anteriormente</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712770397069/fc18be01-2c6e-4f9a-a8db-2ee27682420d.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712770515750/c694e5ee-0b58-4722-9d49-58e512605797.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Edite a aba <code>Trust Relashionship</code> para conceder permissão ao <code>EventBridge</code>, conforme abaixo</div>
</div>

<pre><code class="lang-json">{
    <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
    <span class="hljs-attr">"Statement"</span>: [
        {
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Principal"</span>: {
                <span class="hljs-attr">"Service"</span>: <span class="hljs-string">"scheduler.amazonaws.com"</span>
            },
            <span class="hljs-attr">"Action"</span>: <span class="hljs-string">"sts:AssumeRole"</span>
        }
    ]
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712771968637/4962b516-19ed-4b3a-bd04-4ab2c934e8b0.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712772045845/64321be6-b2c3-4048-ac0f-2c79513d5b64.png" alt class="image--center mx-auto" /></p>
<hr />
<p>3- Agora vá para o console <strong>AWS → EventBridge → Rules → Create rule</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712770592096/52481e39-95b0-4423-bb0f-644df2a35f47.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712770609729/3a466e64-c0da-4922-a94b-f2f1208f4786.png" alt class="image--center mx-auto" /></p>
<p>4- Defina um nome e descrição de sua preferência, por exemplo:</p>
<ul>
<li><p><strong>Name:</strong><code>rds-name-start-qa-monday-to-friday-morning</code></p>
</li>
<li><p><strong>Description:</strong><code>Rule that automatically starts QA environment RDS</code></p>
</li>
<li><p>Altere para a opção <code>Schedule</code></p>
</li>
<li><p>Clique em <code>Continue in EventBridge Scheduler</code></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712770835412/9a3e1a03-c81d-46d9-b545-6a20ab083913.png" alt class="image--center mx-auto" /></p>
<p>5- Altere para <code>Recurring schedule</code> → defina uma expressão <code>cron</code> de sua preferência</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Por exemplo, eu gostaria de iniciar o RDS de segunda a sexta as 9 horas (horário de Brasília)</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712770956318/9db760fc-701f-4039-982e-91572ec6ca0c.png" alt class="image--center mx-auto" /></p>
<p>Por exemplo, para executar de segunda a sexta às <code>09 horas</code> (UTC -3), isso seria:</p>
<pre><code class="lang-plaintext">00 9 ? * MON-FRI *
</code></pre>
<ul>
<li><p><strong>00</strong>: é o minuto em que o cron será executado. Neste caso, o que significa que a tarefa será executada quando o relógio marcar exatamente 0 minutos.</p>
</li>
<li><p><strong>9</strong>: é a hora em que o cron será executado. Neste caso, o que significa que a tarefa será executada às 9 horas. (UTC -3)</p>
</li>
<li><p><strong>?:</strong> isso indica que não estamos definindo um dia específico do mês. A tarefa será executada independentemente do dia do mês.</p>
</li>
<li><p><strong>*</strong>: isso indica que a tarefa será executada em todos os meses. Não estamos definindo um mês específico.</p>
</li>
<li><p><strong>MON-FRI</strong>: especifica os dias da semana em que a tarefa será executada. Neste caso, a tarefa será executada de segunda a sexta-feira.</p>
</li>
<li><p><strong>*</strong>: indica que a tarefa será executada em todos os anos. Não estamos definindo um ano específico.</p>
</li>
</ul>
<p>Uma vez compreendido o formato do <code>cron</code>, lembre-se de ajustar seu <code>Time Zone</code> e preencher de acordo com suas necessidades.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712771022388/5fa6387c-c891-4a76-a5cf-a8bb166e8d24.png" alt class="image--center mx-auto" /></p>
<p>6- Defina a opção <code>Flexible Time Window</code>, essa opção é útil quando você quiser que o <code>EventBridge</code> funcione dentro do tempo dessa janela que você definiu, pense nisso em casos que as tasks ou targets ainda não estão prontos, desta forma você define um intervalo de tempo para que isso seja feito.</p>
<p>Por exemplo, se eu definisse o <code>cron as 9 horas</code> e um <code>Flexible Time Window de 15 minutos</code>, na prática significa que o <code>EventBridge Scheduler</code> garantirá que ele seja executado dentro deste período, ou seja entre <code>9:00 às 9:15</code>, mas isso não significa que ele será executado as <code>9:15</code>, mas sim que será acionado dentro deste intervalo a qualquer momento a partir do horário agendado (no exemplo as <code>9:00 + flexible time window</code>).</p>
<p>Isso é muito bom para distribuir as execuções nesta janela de tempo, reduzindo os impactos de várias solicitações ao mesmo tempo em um ambiente grande.</p>
<p>Como neste meu caso isso não é um requisito necessário, defino como <code>Off</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712771148456/7358c047-bb24-4fd1-9eca-67cd9cafb11e.png" alt class="image--center mx-auto" /></p>
<p>7- Você também pode definir uma data de início e término, como eu espero que a expressão <code>cron</code> funcione e não planejo inserir uma data para que esse <code>cron</code> comece a funcionar ou terminar, <strong>não preencho</strong> e clico em <code>Next</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712771172857/65036601-3565-4169-b40e-05c48cf2b43c.png" alt class="image--center mx-auto" /></p>
<p>8- Agora altere para <code>All APIs</code> → pesquise por <code>rds</code> → selecione a opção <code>RDS</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712771288195/b1bb2e03-8bbd-4bb9-b01c-46cdbef7ddb5.png" alt class="image--center mx-auto" /></p>
<p>9- Agora pesquise por <code>start</code> → selecione a opção <code>StartDBInstance</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712771384729/200810af-5143-4727-bee8-102affee66b9.png" alt class="image--center mx-auto" /></p>
<p>10- Como nessa regra estamos querendo iniciar o RDS, defino o campo <code>DbInstanceIdentifier</code> com o nome da minha instância RDS</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"DbInstanceIdentifier"</span>: <span class="hljs-string">"&lt;RDS-NAME&gt;"</span>
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712771524801/d9ed8afc-5226-4ad3-abe8-63c208331f93.png" alt class="image--center mx-auto" /></p>
<p>11- Deixo a opção <code>Schedule</code> <strong>habilitada</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712771553013/1066bc4a-adec-4a96-880c-83d857be788f.png" alt class="image--center mx-auto" /></p>
<p>12- Não defino nenhuma ação após o agendamento ser executado, pois neste caso de uso não planejo excluir o agendamento</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712771576308/b3d7d734-795b-437e-95d4-282d8b3d4208.png" alt class="image--center mx-auto" /></p>
<p>13- Agora você pode definir uma <code>DLQ (Dead Letter Queue)</code>, isso seria uma fila <code>SQS</code> para armazenar os eventos que falharam, aqui ainda existem dois tipos:</p>
<ul>
<li><p><strong>Recuperáveis</strong></p>
<ul>
<li>Se houver uma falha ou uma entrega mal sucedida no <code>target (que no nosso caso é a API StartDBInstance do RDS)</code>, por padrão o EventBridge tentará fazer ela novamente por 24 horas e até 185 vezes.</li>
</ul>
</li>
<li><p><strong>Não recuperáveis</strong></p>
<ul>
<li>Se houver um erro não recuperável, como <code>AccessDenied</code> por exemplo, isso não será repetido pelo EventBridge, mas ele poderá adicionar se você quiser isso em uma fila DLQ para ser tratado ou processado posteriormente</li>
</ul>
</li>
</ul>
<p>Mesmo desabilitando a opção <code>Retry Policy</code>, ainda sim o EventBridge tentará repetir para eventos recuperáveis por 24 horas e até 185 vezes. Isso é um comportamento padrão, você configurando ou não.</p>
<p>Para este tutorial, defino isso como <code>Disable</code>, mas se isso for importante para você, este é o momento de configurar de acordo com suas preferências:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712771648084/803d538c-33f3-462b-b328-a783412c1d4f.png" alt class="image--center mx-auto" /></p>
<p>14- Não defino nenhuma criptografia</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712771663901/94c49ecf-fec6-46e7-b3fe-65709ca3d32a.png" alt class="image--center mx-auto" /></p>
<p>15- Seleciono a <code>Role</code> que criamos no início do tutorial</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712771769444/614fd2ec-7e97-4bb7-b218-0c6d8a4daef5.png" alt class="image--center mx-auto" /></p>
<p>16- Clico em <strong>Create</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712772180734/c65cf8c7-e04c-4381-9956-0f7e72bcee2b.png" alt class="image--center mx-auto" /></p>
<hr />
<p>Pronto! 😄</p>
<p>Porém criamos até agora apenas para iniciar o RDS, ainda falta uma parte importante que seria parar o RDS, para isso basta repetir os mesmos passos, porém mudando o request da API para <code>StopDBInstance</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712772684482/9960366c-3705-41a4-a888-8384dc29a628.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712772738778/8d945da0-ca9f-4b67-9e9c-a4be4f6cfbe9.png" alt class="image--center mx-auto" /></p>
<p>E novamente passar o nome correto do seu RDS substituindo <code>&lt;RDS-NAME&gt;</code></p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"DbInstanceIdentifier"</span>: <span class="hljs-string">"&lt;RDS-NAME&gt;"</span>
}
</code></pre>
<hr />
<h2 id="heading-limitacoes">Limitações</h2>
<ul>
<li><p>O Event Bridge é capaz de fazer um único request por vez, isso significa que você não pode adicionar várias instâncias RDS no mesmo request, e isso pode gerar duplicação de trabalho, pois deverá repetir este passo a passo para cada instância do RDS que desejar.</p>
</li>
<li><p>O RDS e o Event Bridge precisam estar na mesma região.</p>
</li>
</ul>
<hr />
<h2 id="heading-conclusao">Conclusão</h2>
<p>Pronto! 😄</p>
<p>Agora sim temos todo o nosso objetivo completo.</p>
<p>Vimos neste artigo um tutorial passo a passo para iniciar e parar o RDS que faz:</p>
<ol>
<li><p>O <code>EventBridge Scheduler</code> configurado com uma expressão <code>cron</code> que <strong>inicia</strong> o RDS enviando uma chamada <code>API</code> para o <code>StartDBInstance</code> do <code>RDS</code></p>
</li>
<li><p>O <code>EventBridge Scheduler</code> configurado com uma expressão <code>cron</code> que <strong>para</strong> o RDS enviando uma chamada <code>API</code> para o <code>StopDBInstance</code> do <code>RDS</code></p>
</li>
</ol>
<hr />
<p>Por fim, depois que o <code>cron</code> for executado em seu horário definido, poderemos ver no RDS a instância pausada ou iniciada:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712773530070/5b2f7819-d057-40b2-bfbd-d64c943978b3.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712783709443/fe6a8b10-9dea-4ab0-8b95-754f50c5b64e.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se de excluir todos os recursos ao final para não obter cobranças indesejadas e manter sua conta AWS limpa e organizada.</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Espero que essas informações tenham sido úteis para você!</div>
</div>]]></content:encoded></item><item><title><![CDATA[Como Agendar um START/STOP Automático no EC2]]></title><description><![CDATA[Introdução
Você pode ter vários motivos e razões diferentes para querer agendar um start e stop automático para suas instâncias EC2. No meu caso eu estava criando um ambiente de QA onde não precisava que o EC2 ficasse ligado o tempo todo para manter ...]]></description><link>https://simplescloud.com.br/como-agendar-um-start-stop-automatico-no-ec2</link><guid isPermaLink="true">https://simplescloud.com.br/como-agendar-um-start-stop-automatico-no-ec2</guid><category><![CDATA[aws-ec2-start-stop]]></category><category><![CDATA[aws-ec2-auto-start-stop]]></category><category><![CDATA[AWS]]></category><category><![CDATA[aws ec2]]></category><dc:creator><![CDATA[SimplesCloud]]></dc:creator><pubDate>Sun, 14 Jul 2024 17:00:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730672452784/69aa2b6a-6da4-4cb8-98a2-67aca1ec7376.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introducao">Introdução</h2>
<p>Você pode ter vários motivos e razões diferentes para querer agendar um <code>start</code> e <code>stop</code> automático para suas instâncias EC2. No meu caso eu estava criando um ambiente de QA onde não precisava que o EC2 ficasse ligado o tempo todo para manter os custos reduzidos, então compartilho como consegui atingir esse objetivo.</p>
<hr />
<h2 id="heading-tutorial">Tutorial</h2>
<p>1- Acesse o console <strong>AWS → IAM → Policies → crie uma política</strong> conforme abaixo:</p>
<p><code>Name:</code></p>
<ul>
<li><p>Defina um nome de sua preferência</p>
</li>
<li><p>Por exemplo:</p>
<ul>
<li><code>ec2-scheduler-qa-policy</code></li>
</ul>
</li>
</ul>
<p><code>Description:</code></p>
<ul>
<li><p>Defina uma descrição de sua preferência</p>
</li>
<li><p>Por exemplo:</p>
<ul>
<li><code>Policy that grants EventBridge permission to automatically start and stop EC2 in the QA environment</code></li>
</ul>
</li>
</ul>
<pre><code class="lang-json">{
    <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
    <span class="hljs-attr">"Statement"</span>: [
        {
            <span class="hljs-attr">"Sid"</span>: <span class="hljs-string">"VisualEditor0"</span>,
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Action"</span>: [
                <span class="hljs-string">"ec2:DescribeInstances"</span>,
                <span class="hljs-string">"ec2:StartInstances"</span>,
                <span class="hljs-string">"ec2:StopInstances"</span>
            ],
            <span class="hljs-attr">"Resource"</span>: <span class="hljs-string">"*"</span>
        }
    ]
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712780321010/9197cfcb-b068-4262-ab0b-a6b69717f842.png" alt class="image--center mx-auto" /></p>
<p>2- Agora vá para <strong>IAM → Role → crie uma role</strong> conforme abaixo:</p>
<ul>
<li><p><code>Name:</code></p>
<ul>
<li><p>Defina um nome de sua preferência</p>
</li>
<li><p>Por exemplo:</p>
<ul>
<li><code>ec2-scheduler-qa-role</code></li>
</ul>
</li>
</ul>
</li>
<li><p><code>Description:</code></p>
<ul>
<li><p>Defina uma descrição de sua preferência</p>
</li>
<li><p>Por exemplo:</p>
<ul>
<li><code>Role with necessary EventBridge permissions to automatically start and stop EC2 in the QA environment</code></li>
</ul>
</li>
</ul>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712780420064/dbe1b9d5-8e6e-4b11-a250-42900aa54b8c.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Filtre por <code>Customer managed</code> e <code>ec2</code> → selecione a política que criamos anteriormente</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712780536319/b68e53f6-be84-497e-b5ff-e39a4834cf62.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Edite a aba <code>Trust Relashionship</code> para conceder permissão ao <code>EventBridge</code>, conforme abaixo</div>
</div>

<pre><code class="lang-json">{
    <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
    <span class="hljs-attr">"Statement"</span>: [
        {
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Principal"</span>: {
                <span class="hljs-attr">"Service"</span>: <span class="hljs-string">"scheduler.amazonaws.com"</span>
            },
            <span class="hljs-attr">"Action"</span>: <span class="hljs-string">"sts:AssumeRole"</span>
        }
    ]
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712780705038/092d0503-9ddd-4e11-b44e-0ff4bd54e8be.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712780766831/b163ffa5-6990-45c6-b82a-607bb6e85050.png" alt class="image--center mx-auto" /></p>
<hr />
<p>3- Agora vá para o console <strong>AWS → EventBridge → Rules → Create rule</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712780811044/912c7811-b258-4bc7-8cbc-979633f2e038.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712780826296/6607b4d5-6846-4766-9c4e-87d0d51e9e55.png" alt class="image--center mx-auto" /></p>
<p>4- Defina um nome e descrição de sua preferência, por exemplo:</p>
<ul>
<li><p><strong>Name:</strong><code>ec2-start-qa-monday-to-friday-morning</code></p>
</li>
<li><p><strong>Description:</strong><code>Rule that automatically starts QA environment EC2</code></p>
</li>
<li><p>Altere para a opção <code>Schedule</code></p>
</li>
<li><p>Clique em <code>Continue in EventBridge Scheduler</code></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712780960766/acaaceb7-d7a1-4b2c-be99-f95548307bf4.png" alt class="image--center mx-auto" /></p>
<p>5- Altere para <code>Recurring schedule</code> → defina uma expressão <code>cron</code> de sua preferência</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Por exemplo, eu gostaria de iniciar o EC2 de segunda a sexta as 9 horas (horário de Brasília)</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712781018160/d0fa3900-c350-43f5-b95b-5cfbaf1ef098.png" alt class="image--center mx-auto" /></p>
<p>Por exemplo, para executar de segunda a sexta às <code>09 horas</code> (UTC -3), isso seria:</p>
<pre><code class="lang-plaintext">00 9 ? * MON-FRI *
</code></pre>
<ul>
<li><p><strong>00</strong>: é o minuto em que o cron será executado. Neste caso, o que significa que a tarefa será executada quando o relógio marcar exatamente 0 minutos.</p>
</li>
<li><p><strong>9</strong>: é a hora em que o cron será executado. Neste caso, o que significa que a tarefa será executada às 9 horas. (UTC -3)</p>
</li>
<li><p><strong>?:</strong> isso indica que não estamos definindo um dia específico do mês. A tarefa será executada independentemente do dia do mês.</p>
</li>
<li><p><strong>*</strong>: isso indica que a tarefa será executada em todos os meses. Não estamos definindo um mês específico.</p>
</li>
<li><p><strong>MON-FRI</strong>: especifica os dias da semana em que a tarefa será executada. Neste caso, a tarefa será executada de segunda a sexta-feira.</p>
</li>
<li><p><strong>*</strong>: indica que a tarefa será executada em todos os anos. Não estamos definindo um ano específico.</p>
</li>
</ul>
<p>Uma vez compreendido o formato do <code>cron</code>, lembre-se de ajustar seu <code>Time Zone</code> e preencher de acordo com suas necessidades.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712781079986/e1b648eb-9566-498e-a53b-3916f28d65e5.png" alt class="image--center mx-auto" /></p>
<p>6- Defina a opção <code>Flexible Time Window</code>, essa opção é útil quando você quiser que o <code>EventBridge</code> funcione dentro do tempo dessa janela que você definiu, pense nisso em casos que as tasks ou targets ainda não estão prontos, desta forma você define um intervalo de tempo para que isso seja feito.</p>
<p>Por exemplo, se eu definisse o <code>cron as 9 horas</code> e um <code>Flexible Time Window de 15 minutos</code>, na prática significa que o <code>EventBridge Scheduler</code> garantirá que ele seja executado dentro deste período, ou seja entre <code>9:00 às 9:15</code>, mas isso não significa que ele será executado as <code>9:15</code>, mas sim que será acionado dentro deste intervalo a qualquer momento a partir do horário agendado (no exemplo as <code>9:00 + flexible time window</code>).</p>
<p>Isso é muito bom para distribuir as execuções nesta janela de tempo, reduzindo os impactos de várias solicitações ao mesmo tempo em um ambiente grande.</p>
<p>Como neste meu caso isso não é um requisito necessário, defino como <code>Off</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712781101869/6155ee45-950f-4195-a364-09489da1ca26.png" alt class="image--center mx-auto" /></p>
<p>7- Você também pode definir uma data de início e término, como eu espero que a expressão <code>cron</code> funcione e não planejo inserir uma data para que esse <code>cron</code> comece a funcionar ou terminar, <strong>não preencho</strong> e clico em <code>Next</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712781121334/a4a68195-2075-4a71-8f9b-48534d0876c0.png" alt class="image--center mx-auto" /></p>
<p>8- Agora altere para <code>All APIs</code> → pesquise por <code>ec2</code> → selecione a opção <code>EC2</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712781264431/44505bcb-1829-4685-93f1-7de7d368ba44.png" alt class="image--center mx-auto" /></p>
<p>9- Agora pesquise por <code>start</code> → selecione a opção <code>StarInstances</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712781386527/448f572c-aac3-46b0-9880-237489df208b.png" alt class="image--center mx-auto" /></p>
<p>10- Como nessa regra estamos querendo iniciar as instâncias EC2, defino o campo <code>InstancesIds</code> com o <code>ID</code> das minhas instâncias EC2</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"InstanceIds"</span>: [
    <span class="hljs-string">"&lt;Instance-ID-1&gt;"</span>,
    <span class="hljs-string">"&lt;Instance-ID-2&gt;"</span>
  ]
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712781529405/debfa587-c840-4d19-89bd-79e6354d96f3.png" alt class="image--center mx-auto" /></p>
<p>11- Deixo a opção <code>Schedule</code><strong>habilitada</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712781578486/3ec8102f-c5a6-4902-ae79-0d83c801c440.png" alt class="image--center mx-auto" /></p>
<p>12- Não defino nenhuma ação após o agendamento ser executado, pois neste caso de uso não planejo excluir o agendamento</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712781599379/627bcd55-bddd-4f78-ac8b-2e31b36eb7a7.png" alt class="image--center mx-auto" /></p>
<p>13- Agora você pode definir uma <code>DLQ (Dead Letter Queue)</code>, isso seria uma fila <code>SQS</code> para armazenar os eventos que falharam, aqui ainda existem dois tipos:</p>
<ul>
<li><p><strong>Recuperáveis</strong></p>
<ul>
<li>Se houver uma falha ou uma entrega mal sucedida no <code>target (que no nosso caso é a API StartInstances do EC2)</code>, por padrão o EventBridge tentará fazer ela novamente por 24 horas e até 185 vezes.</li>
</ul>
</li>
<li><p><strong>Não recuperáveis</strong></p>
<ul>
<li>Se houver um erro não recuperável, como <code>AccessDenied</code> por exemplo, isso não será repetido pelo EventBridge, mas ele poderá adicionar se você quiser isso em uma fila DLQ para ser tratado ou processado posteriormente</li>
</ul>
</li>
</ul>
<p>Mesmo desabilitando a opção <code>Retry Policy</code>, ainda sim o EventBridge tentará repetir para eventos recuperáveis por 24 horas e até 185 vezes. Isso é um comportamento padrão, você configurando ou não.</p>
<p>Para este tutorial, defino isso como <code>Disable</code>, mas se isso for importante para você, este é o momento de configurar de acordo com suas preferências:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712781637666/5dafc768-a0df-4ee9-a385-284fe4300fc5.png" alt class="image--center mx-auto" /></p>
<p>14- Não defino nenhuma criptografia</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712781656721/22e7e3da-5420-4a39-84a9-534e9c3be763.png" alt class="image--center mx-auto" /></p>
<p>15- Seleciono a <code>Role</code> que criamos no início do tutorial</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712781763472/7cea3e8a-836b-4c55-976d-24859a7b1fcd.png" alt class="image--center mx-auto" /></p>
<p>16- Clico em <strong>Create</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712781809501/6e1acd5a-a3c9-4a2c-864b-56a379cef912.png" alt class="image--center mx-auto" /></p>
<hr />
<p>Pronto! 😄</p>
<p>Porém criamos até agora apenas para iniciar as instâncias EC2, ainda falta uma parte importante que seria parar as instâncias EC2, para isso basta repetir os mesmos passos, porém mudando o request da API para <code>StopInstances</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712781975601/8291a8a8-d983-4585-99d5-1a6a2312de92.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712782030509/7eb3f789-fde1-424b-b80f-4cf9e75c2b4c.png" alt class="image--center mx-auto" /></p>
<p>E novamente passar os <code>IDs</code> corretos das instâncias EC2 substituindo <code>&lt;Instance-ID&gt;</code></p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"InstanceIds"</span>: [
    <span class="hljs-string">"&lt;Instance-ID-1&gt;"</span>,
    <span class="hljs-string">"&lt;Instance-ID-2&gt;"</span>
  ]
}
</code></pre>
<hr />
<h2 id="heading-limitacoes">Limitações</h2>
<ul>
<li>As instâncias EC2 e o Event Bridge precisam estar na mesma região.</li>
</ul>
<hr />
<h2 id="heading-conclusao">Conclusão</h2>
<p>Pronto! 😄</p>
<p>Agora sim temos todo o nosso objetivo completo.</p>
<p>Vimos neste artigo um tutorial passo a passo para iniciar e parar as instâncias EC2 que faz:</p>
<ol>
<li><p>O <code>EventBridge Scheduler</code> configurado com uma expressão <code>cron</code> que <strong>inicia</strong> as instâncias EC2 enviando uma chamada <code>API</code> para o <code>StartInstances</code> do <code>EC2</code></p>
</li>
<li><p>O <code>EventBridge Scheduler</code> configurado com uma expressão <code>cron</code> que <strong>para</strong> as instâncias EC2 enviando uma chamada <code>API</code> para o <code>StopInstances</code> do <code>EC2</code></p>
</li>
</ol>
<hr />
<p>Por fim, depois que o <code>cron</code> for executado em seu horário definido, poderemos ver no EC2 a instância pausada ou iniciada:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712782864743/d51b2edc-c8b8-45b9-ac7d-a540f15d49d2.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712782284284/f69933fc-d2a1-462a-ba4e-49b0df1f6421.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se de excluir todos os recursos ao final para não obter cobranças indesejadas e manter sua conta AWS limpa e organizada.</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Espero que essas informações tenham sido úteis para você!</div>
</div>]]></content:encoded></item><item><title><![CDATA[Como Criar um NAT Instance na AWS]]></title><description><![CDATA[Introdução
Você pode ter diversas razões e motivos para querer configurar uma instância NAT na AWS, para meu caso de uso estava precisando criar um novo ambiente de QA, este ambiente consistia em ter uma função Lambda que fosse capaz de ter uma conex...]]></description><link>https://simplescloud.com.br/como-criar-um-nat-instance-na-aws</link><guid isPermaLink="true">https://simplescloud.com.br/como-criar-um-nat-instance-na-aws</guid><category><![CDATA[aws-nat-instance]]></category><category><![CDATA[aws-instancia-nat]]></category><category><![CDATA[AWS]]></category><dc:creator><![CDATA[SimplesCloud]]></dc:creator><pubDate>Sat, 13 Jul 2024 17:23:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730672681979/4cb54b19-5f67-4f8e-a94b-ed82a29b632f.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introducao">Introdução</h2>
<p>Você pode ter diversas razões e motivos para querer configurar uma instância NAT na AWS, para meu caso de uso estava precisando criar um novo ambiente de QA, este ambiente consistia em ter uma função Lambda que fosse capaz de ter uma conexão com a internet e também com recursos da VPC.</p>
<p>Felizmente uma função Lambda pode ser configurada dentro de uma VPC e então conceder acesso aos recursos dela, mas infelizmente ao fazer isso, essa mesma função que agora pode se comunicar com RDS, Elasticache e outros recursos da VPC, perde a conexão com a internet, isso ocorre porque a AWS irá atribuir um ENI com endereço IP privado na função lambda quando adicionada na VPC, desta forma impedindo sua conexão com a internet.</p>
<p>Há uma solução sugerida pela AWS para este caso, que consiste em adicionar um NAT Gateway, isso é robusto, escalável e com certeza um caminho a seguir para um ambiente de produção. O problema que me encontrei aqui é que o NAT Gateway é um serviço caro, gerenciado pela AWS e que funciona o tempo todo, então parecia um grande exagero para um ambiente de QA que funciona em alguns horários pré-definidos.</p>
<p>Como citei, esse era o meu cenário, mas novamente você pode querer ter um NAT por qualquer outro motivo, por exemplo para fornecer conexões a internet de qualquer recurso criado em uma sub-rede privada, como instâncias, RDS, etc.</p>
<p>Como alternativa, optei por não usar o serviço gerenciado NAT Gateway, mas sim criei e configurei minha própria instância NAT, compartilharei com você uma breve descrição do que significa o NAT e passaremos por um tutorial de como atingi esse objetivo.</p>
<hr />
<h2 id="heading-o-que-e-nat">O que é NAT?</h2>
<p>NAT significa <code>Network Address Translation</code>, é uma técnica utilizada em redes de computadores para traduzir endereços IP de um formato para outro. Seu principal objetivo é permitir que vários dispositivos em uma rede compartilhem um único endereço IP externo, isso é especialmente útil em redes domésticas e empresariais, onde há escassez de endereços IP públicos disponíveis.</p>
<p>Por exemplo, quando você contrata um plano de internet para sua casa, sua operadora não entregará para você um endereço IP público para cada um de seus dispositivos, como laptops, computadores, TVs, impressoras, celulares, etc. Mas sim entregará um IP público dinâmico e todos os seus equipamentos conectados em seu roteador poderão usar o mesmo IP público dinâmico fornecido através do NAT, pense nisso conforme diagrama abaixo:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712513963856/5a69fd52-03c6-4a31-acc6-895bf788afd8.png" alt class="image--center mx-auto" /></p>
<p>Onde cada endereço IP <code>192.168.0.X</code> de seus equipamentos conectados é entregue através do <code>DHCP</code> configurado em seu roteador, e todos obtém um único endereço IP público, esse funcionamento se dá através do NAT configurado em seu roteador.</p>
<p>No contexto da AWS, o NAT desempenha um papel parecido e é fundamental na comunicação entre instâncias em redes privadas e recursos externos, como a internet. Ao criar instâncias em uma sub-rede privada, ela não terá um endereço IP público, mas sim um endereço privado da sua VPC, o que as impede de se comunicar diretamente com a internet. Então é neste momento que o NAT trabalha, pois atua por meio de tradução de endereços IP, conforme diagrama abaixo:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712514295459/6e0ef329-1264-4ccb-85ff-e9a1c20b2b5c.png" alt class="image--center mx-auto" /></p>
<p>Cada recurso criado na sub-rede privada, possui uma rota para um NAT que está em uma sub-rede pública com acesso à internet, permitindo então assim que os recursos privados consigam acesso a internet.</p>
<p>Concluído essa introdução, espero que você esteja um pouco mais familiarizado com esse conceito, partiremos agora para o tutorial prático.</p>
<hr />
<h2 id="heading-tutorial">Tutorial</h2>
<p>Antigamente, a AWS fornecia uma AMI pronta para instâncias NAT, porém seu suporte foi descontinuado em dezembro de 2023, conforme anúncio oficial:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">A AMI NAT é baseado na última versão do Amazon Linux AMI, 2018.03, que atingiu o fim do suporte padrão em 31 de dezembro de 2020 e o fim do suporte de manutenção em 31 de dezembro de 2023.</div>
</div>

<p>Como alternativa, a AWS sugere criar sua própria instância NAT baseado no Amazon Linux mais recente, porém eu não gostaria de usar essa imagem e sim me basear no Ubuntu, bom e foi isso que eu fiz, abaixo estão os passos:</p>
<hr />
<h3 id="heading-pre-requisitos">Pré-Requisitos</h3>
<p>Este artigo é extenso, passaremos por muitos passos, para evitar que fique ainda maior, não cobriremos a configuração de uma VPC do zero, também não discutiremos em detalhes sobre a VPC ou rede, se você já possui uma VPC com sub-redes públicas e privadas, pode pular algumas etapas e passos que descrevo abaixo, senão for o caso, passaremos pelas principais configurações necessárias.</p>
<hr />
<h2 id="heading-criando-grupo-de-seguranca">Criando Grupo de Segurança</h2>
<p>1- Acesse o console <strong>AWS → VPC → Security Group → Create Security Group</strong> e defina de acordo com suas preferências:</p>
<ul>
<li><p><strong>Name:</strong> por exemplo <code>nat-instance-sg</code></p>
</li>
<li><p><strong>Description:</strong> por exemplo <code>Security group with permissions required for NAT Instance</code></p>
</li>
<li><p><strong>Inbound:</strong> suas regras de entrada, por exemplo <code>HTTP</code>, <code>HTTPS</code> e <code>SSH</code></p>
</li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Dica: em <code>SSH</code> estou definindo um <code>Management Prefix List</code>, você pode querer consultar esse tutorial para saber mais:</div>
</div>

<p>👉 <a target="_blank" href="https://simplescloud.io/como-melhorar-a-administracao-e-organizacao-dos-grupos-de-seguranca-da-aws-com-o-vpc-prefix-list">Como melhorar a administração e organização dos Grupos de Segurança da AWS com o VPC Prefix List</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711376743456/0918c2f0-a234-4505-a7d0-7e0bf663af4a.png" alt class="image--center mx-auto" /></p>
<ul>
<li><strong>Outbound:</strong> suas regras de saída, você precisará adicionar <code>HTTP</code> e <code>HTTPS</code> para <code>0.0.0.0/0</code> para ter conexão com a internet</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711376487040/ea39e54f-223e-446d-82fa-25a631ce9b83.png" alt class="image--center mx-auto" /></p>
<ul>
<li><strong>Tags:</strong> se preferir, adicione <code>tags</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711376621210/5a6015d0-fd25-4192-9e5e-6d5863a404af.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-criando-nat-instance">Criando Nat Instance</h2>
<p>1- Acesse o console <strong>AWS → EC2 → Instance → Launch Instance → preencha as informações:</strong></p>
<ul>
<li><p><strong>Name:</strong> defina um nome de sua preferência, por exemplo <code>NAT Instance</code></p>
</li>
<li><p><strong>AMI:</strong> escolha <code>Ubuntu</code></p>
</li>
<li><p><strong>Architecture:</strong> escolha <code>64-bit (x86)</code></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711376876107/34bc55fd-bf4a-48a7-9efc-dc47ec9aec1a.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p><strong>Instance Type:</strong> escolha o tamanho, lembre-se que todas as conexões irão passar por essa instância, então definir uma instância muito pequena pode aumentar o gargalo e a latência da conexão com a internet, porém para meu caso de uso que era um ambiente de QA, o tipo <code>micro</code> pareceu ser uma boa escolha.</p>
</li>
<li><p><strong>Keypair:</strong> escolha seu <code>keypair</code>, isso é sua chave de acesso que precisaremos dele depois para conseguir conectar através de <code>SSH</code></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711392575358/7b654d59-6c00-40e9-b68f-9876c27be769.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p><strong>VPC:</strong> escolha o <code>ID</code> da sua <code>VPC</code></p>
</li>
<li><p><strong>Subnet:</strong> defino como <code>sem preferências</code>, pois não me importa muito em qual sub-rede nossa instância NAT será criada, porém se preferir você pode definir uma <strong>subnet pública</strong> e não privada</p>
  <div data-node-type="callout">
  <div data-node-type="callout-emoji">⚠</div>
  <div data-node-type="callout-text">O NAT Instance deve ser criada em uma sub-rede <strong>Pública</strong>!</div>
  </div>
</li>
<li><p><strong>Auto-assign Public IP:</strong> escolho habilitado, pois desejo que essa instância NAT tenha um endereço IP público criado automaticamente</p>
</li>
<li><p><strong>Security Group:</strong> escolho o grupo de segurança que criamos anteriormente</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711377145028/05d5e11c-0663-4262-9d21-c0548505a9ad.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p><strong>Storage:</strong> defino um tamanho e seleciono o tipo como <code>gp3</code></p>
</li>
<li><p>Por fim clico em <strong>Launch Instance</strong></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711377215862/93030f41-b4be-4414-96de-ab0e4c35a062.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-configurando-o-nat-instance">Configurando o NAT Instance</h2>
<p>1- Com nossa instância criada, acesso através de SSH → e primeiro atualizo os pacotes do Ubuntu com o comando:</p>
<pre><code class="lang-bash">sudo apt update -y
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711377794965/1fbbfe62-d0a3-4f3c-a14e-73eef3a39855.png" alt class="image--center mx-auto" /></p>
<p>2- Agora verifico qual o nome da interface de rede primária com o comando:</p>
<pre><code class="lang-bash">ip a
</code></pre>
<p>E descubro que ela se chama <code>ens5</code></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Isso pode mudar dependendo o tipo de instância e a AMI que você selecionou, então se o nome para você for diferente, apenas anote pois o usaremos em breve.</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711378232151/2a8f013a-a4b8-4d60-89d6-06bba150cecf.png" alt class="image--center mx-auto" /></p>
<p>3- Agora ativo o encaminhamento de IP com os comandos:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">"net.ipv4.ip_forward = 1"</span> | sudo tee -a /etc/sysctl.conf
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711391955065/b2a35cb0-92f7-4ce5-a61e-2b39e5d700ed.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-bash">sudo sysctl -p
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711392002475/a00cd1e8-ca45-418c-9241-c3f1a675b0da.png" alt class="image--center mx-auto" /></p>
<p>4- Então agora criamos a regra para o NAT com o comando:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Lembre-se de alterar <code>ens5</code> para o nome correto da sua interface de rede que descobrimos anteriormente se for o caso.</div>
</div>

<pre><code class="lang-bash"><span class="hljs-comment"># Making a catchall rule for routing and masking the private IP</span>
sudo iptables -t nat -A POSTROUTING -o ens5 -s 0.0.0.0/0 -j MASQUERADE
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711378430433/1cbc8f70-52b8-4d2c-a8fa-f14c19bbe1b2.png" alt class="image--center mx-auto" /></p>
<p>5- Agora <strong>precisamos tornar essa regra persistente</strong>, pois quando acontecer um reboot ou stop nessa instância, a regra do <code>iptables</code> para o NAT <strong>será perdida</strong> e você certamente não gostará de ter que acessar ela toda vez para repetir este comando, então para isso criamos uma pasta chamada <code>iptables</code> no diretório <code>etc</code>:</p>
<pre><code class="lang-bash">sudo mkdir -p /etc/iptables
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712757767487/0fcb5dde-4eba-44be-9a08-448ebc42177b.jpeg" alt class="image--center mx-auto" /></p>
<p>6- E salvo nossa regra em um arquivo chamado <code>rules.v4</code> com o comando:</p>
<pre><code class="lang-bash">sudo iptables-save | sudo tee /etc/iptables/rules.v4
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712757784041/e29f7ef8-ed39-4e37-a387-19099e7afbbe.jpeg" alt class="image--center mx-auto" /></p>
<p>7- Neste momento, nossa regra já está salva, mas ainda assim não está automático, seria necessário ainda acessar a instância para restaurar nossa regra, bom vamos corrigir isso agora instalando o <code>iptables-persistent</code> no modo silencioso que fará esse trabalho automático para nós.</p>
<pre><code class="lang-bash">sudo debconf-set-selections &lt;&lt;EOF
iptables-persistent iptables-persistent/autosave_v4 boolean <span class="hljs-literal">true</span>
iptables-persistent iptables-persistent/autosave_v6 boolean <span class="hljs-literal">true</span>
EOF
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712757807653/14bb3aa8-7211-4fc1-a350-2d4958060f84.jpeg" alt class="image--center mx-auto" /></p>
<pre><code class="lang-bash">sudo apt-get -y install iptables-persistent
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712757852310/0c30d3aa-712c-4cc4-8346-088afec55695.jpeg" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Pronto! O NAT Instance já foi configurado e as configurações estão persistentes para que ela sempre funcione, mesmo se reiniciar ou desligar sem qualquer interação.</div>
</div>

<hr />
<h2 id="heading-desativando-verificacoes-de-origemdestino">Desativando Verificações de Origem/Destino</h2>
<p>1- Ainda não acabamos tudo, precisamos agora <strong>parar</strong> a verificação de origem e destino dessa instância, então acesso o console <strong>AWS → EC2 → seleciono a instância → Actions → Networking → Change source/destination check</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711378654898/34f335cf-6ff7-4560-818a-bbe010073cfe.png" alt class="image--center mx-auto" /></p>
<p>2- Clico em <strong>Stop</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711378728918/1725ccd2-2cb7-4178-9d3a-8a14c941ac7f.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-criando-tabela-de-roteamento-na-vpc">Criando Tabela de Roteamento na VPC</h2>
<p>1- Acesse o console <strong>AWS → VPC → Route Tables → Create Route Table</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711379167555/d1f21835-ba46-424c-8691-9a010f160afc.png" alt class="image--center mx-auto" /></p>
<p>2- Defina um nome de sua preferência como por exemplo <strong>Private Route → selecione sua VPC → defina Tags se desejar → clique em Create Route Table</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711392309707/c4123c62-5424-419b-a0d3-a2db7d05a4e4.png" alt class="image--center mx-auto" /></p>
<p>3- Agora clique em <strong>Edit Routes</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711379314300/a911c89d-4cb7-4722-91bb-3914fa1d39e8.png" alt class="image--center mx-auto" /></p>
<p>4- Adicione uma rota:</p>
<ul>
<li><p><strong>Destination:</strong><code>0.0.0.0/0</code></p>
</li>
<li><p><strong>Target:</strong><code>escolha o ID da sua instância NAT</code></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711379388763/3ac28363-133d-497a-a71d-d6b92fe7250d.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Você então verá que a interface de rede dessa instância foi adicionado corretamente para 0.0.0.0/0</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711379451767/8de29086-430a-4023-bfbf-b8178a6c387e.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-criando-sub-redes-privadas">Criando Sub-Redes Privadas</h2>
<p>Como estou na região de <code>Ohio</code>, tenho três <code>Availabilty Zones</code> disponíveis:</p>
<ul>
<li><p><code>us-east-2a</code></p>
</li>
<li><p><code>us-east-2b</code></p>
</li>
<li><p><code>us-east-2c</code></p>
</li>
</ul>
<p>Já tenho 3 sub-redes públicas criadas por padrão, então criarei outras três sub-redes privadas para cada <code>Availability Zone</code> .</p>
<hr />
<p>1- Acesse o console da <strong>AWS → VPC → Subnets → Create Subnet</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711383095612/7e59a51f-034f-46bf-b678-d95539c1a19a.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong>Dica:</strong> defina um nome fácil para identificação, se olharmos a imagem acima veremos que o último bloco CIDR é <code>172.31.32.0/20</code> para o <code>Availabilty Zone us-east-2c</code>. Para você não precisar calcular esses blocos CIDR, clique na seta para direita (<code>&gt;</code>), isso irá preencher para você o próximo bloco CIDR corretamente.</div>
</div>

<ul>
<li><code>us-east-2a</code> | <code>172.31.48.0/20</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711383497018/938f6be4-b7d5-45e2-8629-0de978c31e6b.png" alt class="image--center mx-auto" /></p>
<ul>
<li><code>us-east-2b</code> | <code>172.31.64.0/20</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711383401773/1c5fb986-5b43-49ba-9cda-9f566674651d.png" alt class="image--center mx-auto" /></p>
<ul>
<li><code>us-east-2c</code> | <code>172.31.80.0/20</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711383586047/0e4b645b-0e60-4159-8805-c50c4d899235.png" alt class="image--center mx-auto" /></p>
<p>2- Volte para o menu <strong>Route Tables → selecione a Tabela de Roteamento Privado que criamos → selecione a aba Subnet Associations → Edit</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711383717554/ef562afb-6fbc-496c-a60f-de4c50678613.png" alt class="image--center mx-auto" /></p>
<p>3- Selecione agora as <strong>sub-redes privadas</strong> criadas → clique em <strong>Save Association</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711383821504/869a3f60-5dbc-454a-990e-46eb03425da7.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-testando">Testando</h2>
<p>Fizemos muitas coisas até aqui, por favor não se sinta "perdido", recapitulando o que fizemos até aqui:</p>
<ul>
<li><p>Criamos o Grupo de Segurança</p>
</li>
<li><p>Criamos o NAT Instance na sub-rede pública</p>
</li>
<li><p>Desativamos Verificações de Origem/Destino</p>
</li>
<li><p>Criamos a Tabela Privada de Roteamento</p>
</li>
<li><p>Criamos as Sub-redes Privadas</p>
</li>
</ul>
<p>Neste momento, já temos tudo devidamente configurado, mas e agora como testar se tudo está funcionando? Bom para isso vou fazer 2 testes:</p>
<ul>
<li><p>Criar uma função Lambda dentro da VPC (lembre-se que isso perde a conexão dela com a internet) e testar sua conexão com a internet através do NAT Instance</p>
</li>
<li><p>Criar uma instância EC2 na sub-rede privada e testar sua conexão com a internet</p>
</li>
</ul>
<hr />
<h2 id="heading-lambda">Lambda</h2>
<p>Para adicionar a função Lambda que vamos criar, precisamos antes criar uma <code>policy</code> e <code>role</code> , vamos fazer isso agora:</p>
<h3 id="heading-policy">Policy</h3>
<p>1- Acesse o console <strong>AWS → IAM → Policies → Create Policy →</strong> crie a política com o código abaixo:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Lembre-se de alterar <code>&lt;your-region&gt;</code>, <code>&lt;your-account-id&gt;</code> e <code>&lt;your-lambda-function-name&gt;</code> para seus valores reais</div>
</div>

<pre><code class="lang-json">{
    <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
    <span class="hljs-attr">"Statement"</span>: [
        {
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Action"</span>: [
                <span class="hljs-string">"ec2:DescribeNetworkInterfaces"</span>,
                <span class="hljs-string">"ec2:CreateNetworkInterface"</span>,
                <span class="hljs-string">"ec2:DeleteNetworkInterface"</span>,
                <span class="hljs-string">"ec2:DescribeInstances"</span>,
                <span class="hljs-string">"ec2:AttachNetworkInterface"</span>
            ],
            <span class="hljs-attr">"Resource"</span>: <span class="hljs-string">"*"</span>
        },
        {
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Action"</span>: <span class="hljs-string">"logs:CreateLogGroup"</span>,
            <span class="hljs-attr">"Resource"</span>: <span class="hljs-string">"arn:aws:logs:&lt;your-region&gt;:&lt;your-account-id&gt;:*"</span>
        },
        {
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Action"</span>: [
                <span class="hljs-string">"logs:CreateLogStream"</span>,
                <span class="hljs-string">"logs:PutLogEvents"</span>
            ],
            <span class="hljs-attr">"Resource"</span>: [
                <span class="hljs-string">"arn:aws:logs:&lt;your-region&gt;:&lt;your-account-id&gt;:log-group:/aws/lambda/&lt;your-lambda-function-name&gt;:*"</span>
            ]
        }
    ]
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711384883009/9f840624-f949-4f46-8e68-4e8118723fd5.png" alt class="image--center mx-auto" /></p>
<p>2- Defina de acordo com suas preferências:</p>
<ul>
<li><p><strong>Name:</strong> por exemplo <code>lambda-test-internet-connection-policy</code></p>
</li>
<li><p><strong>Description:</strong> por exemplo <code>Policy with necessary permissions to be used in the lambda function named test-internet-connection</code></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711385101081/80a224ab-2d77-457b-b8ab-b107f326142a.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-role">Role</h3>
<p>1- Acesse o console <strong>AWS → IAM → Role → Create Role →</strong> crie a role escolhendo:</p>
<ul>
<li><p><code>AWS Services</code></p>
</li>
<li><p><code>Lambda</code></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711385166970/4625ab3f-8563-43aa-a023-9a62dac16b84.png" alt class="image--center mx-auto" /></p>
<p>2- Adicione a política que acabamos de criar</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711385251265/e342685b-45de-4d23-9522-99dd4e059aa9.png" alt class="image--center mx-auto" /></p>
<p>3- Defina de acordo com sua preferência:</p>
<ul>
<li><p><strong>Name:</strong> por exemplo <code>lambda-test-internet-connection-role</code></p>
</li>
<li><p><strong>Description:</strong> por exemplo <code>Role with required permissions used in lambda function named test-internet-connection</code></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711385348689/4ce837dc-2a37-4075-970f-3ab68e95863c.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-criando-o-lambda-function">Criando o Lambda Function</h3>
<p>1- Acesse o console <strong>AWS → Lambda → Create Function → Author from Scratch</strong></p>
<p>2- Defina de acordo com sua preferência:</p>
<ul>
<li><strong>Name:</strong> por exemplo <code>test-lambda-internet-connection</code></li>
</ul>
<p>3- Escolha as opções:</p>
<ul>
<li><p><strong>Runtime:</strong><code>Node.js</code></p>
</li>
<li><p><strong>Architecture:</strong><code>x86_64</code></p>
</li>
<li><p><strong>Use an existing role:</strong> escolha a role que criamos anteriormente</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711385513451/941d99d7-215c-4b44-8a64-ebf231d0856d.png" alt class="image--center mx-auto" /></p>
<p>4- A função será criada → clique na aba <strong>Code</strong> → renomeie o arquivo de <code>index.mjs</code> para <code>index.js</code> (remova o <code>m</code> do nome)</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711385580391/de1f8899-2330-4324-980b-28d371b71583.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711385633050/261a0873-8b11-48a5-84b1-530a88eec1c2.png" alt class="image--center mx-auto" /></p>
<p>5- Apague o código criado automaticamente pela AWS → adicione este código:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> getContent = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">url</span>) </span>{
  <span class="hljs-comment">// return new pending promise</span>
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
    <span class="hljs-comment">// select http or https module, depending on reqested url</span>
    <span class="hljs-keyword">const</span> lib = url.startsWith(<span class="hljs-string">'https'</span>) ? <span class="hljs-built_in">require</span>(<span class="hljs-string">'https'</span>) : <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>);
    <span class="hljs-keyword">const</span> request = lib.get(url, <span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
      <span class="hljs-comment">// handle http errors</span>
      <span class="hljs-keyword">if</span> (response.statusCode &lt; <span class="hljs-number">200</span> || response.statusCode &gt; <span class="hljs-number">299</span>) {
        reject(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Failed to load page, status code: '</span> + response.statusCode));
      }
      <span class="hljs-comment">// temporary data holder</span>
      <span class="hljs-keyword">const</span> body = [];
      <span class="hljs-comment">// on every content chunk, push it to the data array</span>
      response.on(<span class="hljs-string">'data'</span>, <span class="hljs-function">(<span class="hljs-params">chunk</span>) =&gt;</span> body.push(chunk));
      <span class="hljs-comment">// we are done, resolve promise with those joined chunks</span>
      response.on(<span class="hljs-string">'end'</span>, <span class="hljs-function">() =&gt;</span> resolve(body.join(<span class="hljs-string">''</span>)));
    });
    <span class="hljs-comment">// handle connection errors of the request</span>
    request.on(<span class="hljs-string">'error'</span>, <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> reject(err))
  })
};

<span class="hljs-built_in">exports</span>.handler = <span class="hljs-keyword">async</span> (event) =&gt; {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Received event: %j'</span>, event);

  <span class="hljs-keyword">const</span> url = event.url || <span class="hljs-string">'https://www.google.com'</span>;
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> content = <span class="hljs-keyword">await</span> getContent(url);
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Response content: %j'</span>, content);
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'You have access to the internet, congratulations!'</span>);

    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">statusCode</span>: <span class="hljs-number">200</span>,
      <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
        <span class="hljs-attr">message</span>: <span class="hljs-string">'You have access!'</span>,
        content,
      }),
    };
  } <span class="hljs-keyword">catch</span> (e) {
    <span class="hljs-built_in">console</span>.error(e);
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">statusCode</span>: <span class="hljs-number">500</span>,
      <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
        <span class="hljs-attr">message</span>: e.toString(),
      }),
    };
  }
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711385685393/5cc2de56-4c6d-4426-a4f8-559767389080.png" alt class="image--center mx-auto" /></p>
<p>6- Clique em <strong>Configure Test Event</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711385746051/7a4e9799-f173-485c-bbb3-8b005674c339.png" alt class="image--center mx-auto" /></p>
<p>7- Defina um nome de sua preferência, por exemplo <code>TestInternetConnection</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711385802318/2dbdaf33-a9ee-4fc9-b023-3446d270f951.png" alt class="image--center mx-auto" /></p>
<p>8- Clique em <strong>Deploy → Test</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711385865002/5eab64c7-c6e0-46e7-82e1-f8d3b1ecfb26.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Você receberá uma resposta que funcionou, isso aconteceu porque nossa função lambda ainda não está dentro do VPC, então ela por padrão tem conexão com a internet.</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711385932431/3ae76b53-cc77-4103-b819-8baff1b0df7b.png" alt class="image--center mx-auto" /></p>
<p>9- Vamos colocar nossa função lambda na <strong>VPC → clique na aba Configuration → VPC → Edit</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711386007796/b7539d53-405a-47e2-b363-cd0caaf495d2.png" alt class="image--center mx-auto" /></p>
<p>10- Selecione as <strong>Sub-redes privadas → e o grupo de segurança</strong> (escolhi o <code>default-vpc security group</code>)</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711386537466/0230ce16-f482-4d48-b04d-7a2d89aa02b7.png" alt class="image--center mx-auto" /></p>
<p>11- Clico em <strong>Test</strong> novamente e concluo:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">☑</div>
<div data-node-type="callout-text"><strong>A função lambda sem estar em uma VPC</strong>, por padrão possui conexão com a internet, mas não possui conexão com recursos da VPC como RDS, instâncias, Elasticache, etc.</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">☑</div>
<div data-node-type="callout-text"><strong>A função lambda adicionada na VPC em sub-redes públicas</strong>, pode se conectar com recursos da VPC como RDS, instâncias, Elasticache, etc. Mas não pode se conectar na internet, pois o lambda irá atribuir um endereço privado a um ENI em sua VPC, no qual não terá roteamento para a internet, necessitando de uma rota para um NAT.</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text"><strong>A função lambda adicionada na VPC em sub-redes privadas</strong>, pode se conectar com recursos da VPC como RDS, instâncias, Elasticache, etc. E também poderá se conectar na internet através de um NAT, pois o lambda irá atribuir um endereço privado a um ENI em sua VPC, e essa terá um roteamento para a internet.</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711386774516/796ff879-3974-4515-b1e3-127b4c3387f0.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-criando-um-ec2-privado">Criando um EC2 Privado</h2>
<p>1- Acesse o console <strong>AWS → EC2 → Launch Instance → defina de acordo com sua preferência:</strong></p>
<ul>
<li><p><strong>Name:</strong> por exemplo <code>ec2-private-test-internet-connection</code></p>
</li>
<li><p><strong>AMI:</strong><code>Amazon Linux</code></p>
</li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Escolhi a <code>AMI Amazon Linux</code> por já ter o <code>SSM Manager Agent</code> instalado por padrão para conseguirmos fazer <code>ssh</code> através do <code>Session Manager</code>, uma vez que esta instância de teste será criada na sub-rede privada e não terá um IP público.</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711388053123/d406856e-f576-43b1-ac67-72096f524013.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Escolha uma <strong>sub-rede privada</strong></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711387065157/cbc8fc0c-f77d-436f-a531-9111be4a30a3.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Verifique se a opção <code>Auto-assign public IP</code> é marcada como <code>Disable</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711387134642/819d1036-bd68-4e3c-90b4-ec597b253a72.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-role-1">Role</h3>
<p>1- Com nossa instância criada, precisaremos criar uma <code>role</code> para permitir conexões através do <code>Session Manager</code>, então vou para o console <strong>AWS → IAM → AWS Service → seleciono EC2</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711387411680/9f57c1b6-44d4-4083-80f5-f0b237d67b3a.png" alt class="image--center mx-auto" /></p>
<p>2- Adiciono a permissão <code>AmazonSSMManagedInstanceCore</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711387481329/d7b0c22c-2a22-4e5c-ad8a-d7a242ba0603.png" alt class="image--center mx-auto" /></p>
<p>3- Defina um nome e descrição de acordo com suas preferências:</p>
<ul>
<li><p><strong>Name:</strong> por exemplo <code>ec2-session-manager-role</code></p>
</li>
<li><p><strong>Description:</strong> por exemplo <code>Role with required permissions to allow access to EC2 through Session Manager</code></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711387592299/43595c8a-e08d-45d6-8ffe-6fc031850089.png" alt class="image--center mx-auto" /></p>
<p>4- Volto para o console <strong>AWS → EC2 → seleciono a instância privada de teste → Actions → Security → Modify IAM Role</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711387766050/5cb071bb-3f9d-49bf-90bf-24a28315e1a2.png" alt class="image--center mx-auto" /></p>
<p>5- Seleciono a <code>role</code> que criamos anteriormente</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711387808170/7e6e21e1-cf72-4e90-b821-47743913b364.png" alt class="image--center mx-auto" /></p>
<p>6- Estamos quase lá, agora edito as regras de entrada do grupo de segurança do NAT Instance para permitir o <code>ping</code> dos blocos <code>CIDR</code> das <code>sub-redes privadas</code></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Estou usando o mesmo grupo de segurança para o NAT Instance e para o teste, se você criar grupos de segurança separados, lembre-se de ajustar suas regras de entrada e saída seguindo a mesma lógica e raciocínio aqui.</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711389869103/c3396a90-1eca-402c-9621-7ae7561487a0.png" alt class="image--center mx-auto" /></p>
<p>7- Edito agora nas regras de saída para permitir que o NAT Instance envie o <code>ping</code> para a internet</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711389566521/c562d73b-890a-411d-b07f-8ceabc0f883c.png" alt class="image--center mx-auto" /></p>
<p>8- Agora com tudo pronto, vamos tentar conectar em nossa instância privada que não tem um IP público, através do <code>Session Manager</code> que possui permissões adequadas no <code>IAM Role</code> que foi anexada em nossa instância. Para isso seleciono novamente a instância privada de teste → <strong>Connect</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711388549355/95a2dd55-a1eb-47b6-91bc-34cf4f648768.png" alt class="image--center mx-auto" /></p>
<p>9- Altero para a aba <strong>Session Manager → Connect</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711388594537/305f8a73-1bb7-4b21-a1a5-162c827594d2.png" alt class="image--center mx-auto" /></p>
<p>10- Executo um <code>ping</code> para o Google:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712539704142/7a48744b-7a6b-4d2b-bc45-0c51b80e7a6f.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-bash">ping google.com
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711390117032/898ee399-61ae-4609-ad5c-d218712b62f5.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Pronto! Nossa instância privada que não tem um IP público, também possui conexão com a internet através do nosso NAT Instance.</div>
</div>

<hr />
<h2 id="heading-conclusao">Conclusão</h2>
<p>Fizemos uma breve explicação sobre o NAT Instance, também observamos o porque ele seria útil para meu caso de uso, além disso passamos por um tutorial de como configuramos um NAT Instance no Ubuntu com configurações persistentes para que funcione mesmo depois de reiniciar ou desligar.</p>
<p>Garantimos que mesmo após de um reboot, as regras do NAT estarão funcionando:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712758404778/5fbac141-9c99-44d7-bae8-2d8b2084e8e7.jpeg" alt class="image--center mx-auto" /></p>
<p>Garantimos também que mesmo que a instância esteja parada (<code>stopped</code>), quando ligarmos ela, automaticamente a <code>ENI da tabela de rota privada que criamos</code> mudará o status para <code>ativo</code> sem qualquer ação manual, fazendo com que o NAT funcione.</p>
<p>Também criamos dois testes práticos e reais:</p>
<ul>
<li><p>uma função lambda na VPC com conexão na internet</p>
</li>
<li><p>e outra instância EC2 privada com conexão na internet, para isso configuramos também permissões adequadas.</p>
</li>
</ul>
<p>Ao final fomos capazes de atingir o objetivo.</p>
<hr />
<p>Como mencionei no início, este meu cenário eu não precisava da instância ligada o tempo, então se você também estiver interessado em reduzir ainda mais seu custo, talvez ache interessante agendar o <code>STAR/STOP</code> de uma instância EC2, veja mais detalhes sobre como fazer isso neste outro artigo:</p>
<ul>
<li>👉 <a target="_blank" href="https://simplescloud.io/como-agendar-um-start-stop-automatico-no-ec2">Como Agendar um START/STOP Automático no EC2</a></li>
</ul>
<p>Com isso consegui reduzir um custo inteiro mensal de um NAT Gateway para o preço sob demanda do EC2 em uma instância mínima e com horários agendados de funcionamento.</p>
<hr />
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se de excluir todos os recursos ao final para não obter cobranças indesejadas e manter sua conta AWS limpa e organizada.</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Espero que as informações tenham sido úteis!</div>
</div>]]></content:encoded></item><item><title><![CDATA[Como criar um Self-Hosted Runner do Bitbucket]]></title><description><![CDATA[Introdução
Em um cenário de desenvolvimento ágil e integração contínua, a flexibilidade é importante. É nesse contexto que os Self-Hosted Runners do Bitbucket emergem como uma solução poderosa, oferecendo controle total sobre seu ambiente de build e ...]]></description><link>https://simplescloud.com.br/como-criar-um-self-hosted-runner-do-bitbucket</link><guid isPermaLink="true">https://simplescloud.com.br/como-criar-um-self-hosted-runner-do-bitbucket</guid><category><![CDATA[bitbucket runner]]></category><category><![CDATA[bitbucket-self-hosted-runner]]></category><category><![CDATA[bitbucket proprio runner]]></category><category><![CDATA[Bitbucket]]></category><dc:creator><![CDATA[SimplesCloud]]></dc:creator><pubDate>Thu, 11 Jul 2024 16:00:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1708095628941/91e3145c-01ae-49b8-a490-ed650ec8d5c6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introducao">Introdução</h2>
<p>Em um cenário de desenvolvimento ágil e integração contínua, a flexibilidade é importante. É nesse contexto que os Self-Hosted Runners do Bitbucket emergem como uma solução poderosa, oferecendo controle total sobre seu ambiente de build e deploy.</p>
<p>Neste artigo, exploraremos passo a passo como criar seu próprio Bitbucket Runner Auto Hospedado. Essa abordagem não apenas amplia a capacidade de personalização do seu pipeline, mas também proporciona maior eficiência ao permitir a execução de builds em um ambiente familiar e sob seu controle direto.</p>
<hr />
<h2 id="heading-tipos-de-runners-do-bitbucket">Tipos de Runners do Bitbucket</h2>
<p>O Bitbucket oferece flexibilidade na execução de pipelines de CI/CD através de dois tipos de Runners:</p>
<ul>
<li><p><code>Shared</code></p>
</li>
<li><p><code>Self-Hosted</code></p>
</li>
</ul>
<h3 id="heading-shared-runner"><strong>Shared Runner:</strong></h3>
<ul>
<li><p><strong>Gerenciado pela Nuvem:</strong> Você não precisa hospedar ou gerenciar nenhum servidor. O runner compartilhado é gerenciado e hospedado pelo Bitbucket na nuvem.</p>
</li>
<li><p><strong>Pronto para Uso:</strong> É uma opção pronta para uso, eliminando a necessidade de configurações adicionais.</p>
</li>
<li><p><strong>Ideal para Projetos Menores:</strong> Adequado para projetos menores e equipes que buscam uma solução rápida e eficiente sem a necessidade de manutenção direta.</p>
</li>
<li><p><strong>Cobrança:</strong> Oferece um limite de minutos de execução no plano gratuito com possibilidade de realizar upgrades.</p>
</li>
</ul>
<h3 id="heading-self-hosted-runner"><strong>Self-Hosted Runner:</strong></h3>
<ul>
<li><p><strong>Controle Total:</strong> Você precisa hospedar ou gerenciar o servidor. O runner self-hosted oferece controle total ao permitir que você configure e mantenha seus próprios agentes de build.</p>
</li>
<li><p><strong>Adaptabilidade ao Ambiente:</strong> Permite a execução de builds em um ambiente que você controla, com a flexibilidade de adaptar recursos conforme necessário.</p>
</li>
<li><p><strong>Adequado para Projetos Complexos:</strong> Ideal para projetos maiores, equipes que requerem ambientes específicos ou aqueles que precisam integrar com recursos internos.</p>
</li>
<li><p><strong>Cobrança:</strong> Você tem a cobrança do seu servidor, mas seus minutos são ilimitados e você não será cobrado pelo limite e preço do Bitbucket.</p>
</li>
</ul>
<hr />
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Neste artigo, nos concentraremos no Self-Hosted Runner, ainda há vários tipos de instalação como por exemplo em Windows, Linux e Docker, nos concentraremos também na instalação em Docker para proporcionar maior isolamento e portabilidade.</div>
</div>

<hr />
<h3 id="heading-nivel-do-workspace">Nível do Workspace</h3>
<p>Se você for um administrador do espaço de trabalho, poderá configurar e gerenciar vários runners para toda a sua conta para que possam ser usados ​​em pipelines em qualquer repositório no espaço de trabalho. Isso torna mais fácil e economiza tempo na criação e gerenciamento de seus runners quando você tem muitos repositórios em seu espaço de trabalho.</p>
<p><img src="https://bitbucket.wpengine.com/wp-content/uploads/2021/08/workspace-runners-1024x244.png" alt /></p>
<hr />
<h3 id="heading-nivel-do-repositorio">Nível do Repositório</h3>
<p>Você opcionalmente pode configurar e gerenciar runners para determinados repositórios, limitando seu uso em toda a organização, porém isso pode demandar mais tempo de administração sua.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Prefiro configurar em nível do <code>workspace</code>, isso torna o runner disponível para todos os repositórios e ajuda na administração, manutenção e gerenciamento. Para nosso tutorial prático, configuraremos um runner a nível de <code>workspace</code>.</div>
</div>

<hr />
<h2 id="heading-beneficios-do-self-hosted-runner">Benefícios do Self-Hosted Runner</h2>
<ul>
<li><p><strong>Configurações de build personalizadas:</strong> os runners permitem que você configure seu hardware para diferentes tipos de build. Por exemplo, se seu build tiver que consumir muitos recursos, usar hardware com mais memória pode melhorar o tempo de execução.</p>
</li>
<li><p><strong>Acesse aplicativos ou bancos de dados internos:</strong> ao executar pipelines na infraestrutura do Bitbucket com shared runners, dificulta o trabalho para poder acessar sistemas internos como banco de dados por exemplo. Se você precisa executar testes de integração em seus bancos de dados ou aplicativos internos, você poderá fazer isso com runners auto hospedados na mesma rede fornecendo acesso necessário aos serviços internos.</p>
</li>
<li><p><strong>Fluxos de trabalho híbridos</strong>: você pode otimizar seus recursos usando runners auto hospedados com configurações personalizadas para builds que exigem isso e usar a infraestrutura do Bitbucket com shared runners para outros trabalhos.</p>
</li>
</ul>
<hr />
<p>Todo esse contexto é interessante, mas talvez seu principal motivo seja resolver esse aviso em sua conta Bitbucket:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Your account has run out of build minutes. View plan details.</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708101492950/b6ab7f81-1b50-4190-a824-6a5569719576.png" alt class="image--center mx-auto" /></p>
<p>Se você atingir o limite mensal do plano gratuito, receberá esse aviso e ficará incapaz de continuar usando os shared runners até o próximo mês, você pode resolver isso realizando um upgrade de conta ou usando seu próprio runner, e sim, se você usar seu próprio runner você também terá os custos relacionados a isso, mas considerando que você pode cria-lo no seu mesmo ambiente e que pode obter minutos ilimitados (pois ele é seu), talvez faça sentido considerar esse custo ao invés do custo de upgrade de conta no Bitbucket, você deve colocar na balança o melhor custo-benefício e decidir pela melhor escolha no seu cenário.</p>
<hr />
<h2 id="heading-tutorial-pratico-pre-requisitos">Tutorial Prático - Pré-Requisitos</h2>
<p>Para a instalação de um Runner auto hospedado do Bitbucket, como o nome sugere você precisará de uma máquina, isso pode ser desde seu próprio computador até qualquer VPS de sua preferência.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Para o tutorial deste artigo, usaremos uma instância do AWS Lightsail, pois seu pacote de instância + tráfego de rede é ofertado a um preço mais acessível. Mas novamente você pode escolher de acordo com sua preferência como <code>AWS EC2</code>, <code>Google Compute Engine</code>, <code>Digital Ocean</code>, <code>Vultr</code>, <code>Linode</code>, etc.</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Se você já é mais experiente, ou se não deseja usar o Lightsail, você pode ignorar as etapas abaixo de criação de instância, criação de IP fixo e conexão SSH, não importa qual VPS você criou. Você pode pular diretamente para etapa de configuração dentro da instância e encurtar seu caminho deste artigo, mas se você é mais iniciante ou se está um pouco confuso nesse momento, recomendo seguir todos os passos.</div>
</div>

<hr />
<h3 id="heading-criando-uma-instancia-lightsail">Criando uma instância Lightsail</h3>
<p>1- Acesse o console <strong>AWS → Lightsail → Create Instance</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708102124604/20d8b633-3829-489c-bd43-3905a0c2ba6d.png" alt class="image--center mx-auto" /></p>
<p>2- Escolha a <strong>região</strong></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Em nosso exemplo escolhi a região <code>Norte da Virgínia</code> e a <code>Zona de Disponibilidade A</code></div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708102197827/088a9e8f-9e80-4950-9189-e8e39ebf7bb9.png" alt class="image--center mx-auto" /></p>
<p>3- Escolha o <strong>sistema operacional</strong></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Nem todos os sistemas operacionais são suportados, então escolhi a opção <code>Ubuntu 22.04</code> que é a mais recente no momento da criação deste artigo</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708102303030/f881fb52-174c-46e5-b6fe-e4614fb8fa4b.png" alt class="image--center mx-auto" /></p>
<p>4- Não adicione um <code>script de inicialização</code>, não altere sua <code>chave key-pair</code> e não habilite <code>snapshots automáticos</code>, as opções padrões parecem boas aqui.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708102404328/8c155344-8870-4bf8-93cc-7d9a36ade383.png" alt class="image--center mx-auto" /></p>
<p>5- Escolha <code>Dual Stack</code>, pois ainda há limitações para uso do <code>IPv6</code> e precisamos que nossa <strong>instância tenha IPv4 também</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708102502783/ceb3b2da-e727-43a4-9fa2-837bf2485ed7.png" alt class="image--center mx-auto" /></p>
<p>6- Selecione o <strong>tamanho da instância</strong></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se que essa decisão é muito importante, quanto menor a instância você escolher, mais lentidão e problemas seu pipeline pode ter por conta de falta de memória ou cpu. Para nosso artigo escolhi a opção <code>small de USD 10 com 2GB de memória, 2 vCPU e 3TB de transferência de dados</code>.</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Em minhas experiências, as instâncias abaixo de <code>1GB de memória não chegam a funcionar corretamente</code>, e tenho usado <code>instâncias acima de 4GB de memória em ambientes de produção</code> . Mas para efeitos de tutorial essa parece ser uma escolha boa.</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708102665985/a88dfcb6-207d-4edc-a16b-69430e9cf42d.png" alt class="image--center mx-auto" /></p>
<p>7- Defina um <strong>nome</strong>, opcionalmente você pode inserir <strong>tags</strong> e clique em <strong>criar instância</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708103177871/cffd6b78-0131-425c-ae25-7f2713969992.png" alt class="image--center mx-auto" /></p>
<p>8- Aguarde até o status <code>Pending</code> mudar para <code>Running</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708103348081/b8268815-50df-4147-bb5f-50170f4fb0f9.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708103389628/faaac9bd-22a1-4292-82a6-ba3399e6eae0.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Pronto! Nesse momento, você já tem uma instância criada com sucesso.</div>
</div>

<hr />
<h3 id="heading-criando-um-ip-fixo">Criando um IP Fixo</h3>
<p>Se olharmos bem, a instância Lightsail recebeu um <code>IPv4</code> e <code>IPv6</code> público dinâmicos, isso aconteceu porque selecionamos a opção <code>Dual Stack</code> quando criamos a instância. O dinâmico significa que quando desligarmos essa instância e ligarmos novamente, esses endereços IPs irão mudar, isso pode ser um pouco chato e frustrante de se lembrar, principalmente quando você está tentando se conectar a ela.</p>
<p>Então vamos resolver isso criando um IP Fixo.</p>
<p>1- No console <strong>AWS Lightsail → Networking</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708103655669/875fda53-8cb4-4868-acce-58f3e46e2be2.png" alt class="image--center mx-auto" /></p>
<p>2- Clique em <strong>Create Static IP</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708103734361/c813a5b9-1aff-4353-b094-3f51890f1b31.png" alt class="image--center mx-auto" /></p>
<p>3- Mantenha a <strong>mesma região e zona de disponibilidade da sua instância → escolha a instância recém criada</strong></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Em nosso exemplo <code>Norte da Virgínia</code> e <code>Zona de Disponibilidade A</code></div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708103847183/e0e6838e-40e0-4748-bfc4-9bb975602808.png" alt class="image--center mx-auto" /></p>
<p>4- Defina um <strong>nome → Create</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708103893965/c98f0e88-1c27-4821-a847-88a382f4323b.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708103931738/0bab2997-8a2a-4104-bd28-b66d531cc42f.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Pronto! Agora já temos um IP Fixo anexado a nossa instância Lightsail</div>
</div>

<hr />
<h3 id="heading-conectando-via-ssh-na-instancia-lightsail">Conectando via SSH na instância Lightsail</h3>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Você pode fazer isso de muitas formas, com qualquer cliente SSH de sua preferência.</div>
</div>

<p>Se você não quiser usar um cliente SSH, pode fazer isso diretamente no console da AWS clicando nesse botão:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708104200747/efc2d456-2ec2-42b8-815f-e1e991151ab4.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">E isso irá abrir uma nova janela com seu acesso com sucesso:</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708104232283/1ba179cd-0961-4b71-91e2-c5b064bece70.png" alt class="image--center mx-auto" /></p>
<p>Se você estiver usando uma distribuição <code>linux</code>, como por exemplo <code>ubuntu</code>, poderia acessar também através do seu terminal com o comando:</p>
<pre><code class="lang-bash">ssh -i &lt;LightsailDefaultKey.pem&gt; &lt;user&gt;@&lt;public-ip&gt;
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se que <code>LightsailDefaultKey.pem</code> é sua chave de acesso baixada do console da AWS, então especifique certinho o caminho da pasta para onde você fez download em sua máquina, também lembre-se que usamos o ubuntu, então mude <code>user</code> para <code>ubuntu</code> e <code>&lt;public-ip&gt;</code> para seu ip fixo criado.</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Para nosso exemplo isso seria:</div>
</div>

<pre><code class="lang-bash"><span class="hljs-comment"># Example</span>
ssh -i LightsailDefaultKey.pem ubuntu@44.198.68.63
</code></pre>
<p>Porém como estou usando em meu computador o sistema operacional Windows, eu poderia fazer isso através do <code>WSL2</code> com <code>Prompt de Comando</code> , <code>Powershell</code> ou <code>Terminal do Windows</code>, o <code>Putty</code> e muitas outras opções de clientes SSH disponíveis.</p>
<p>Mas prefiro usar o cliente gratuito chamado <code>Termius</code>, você pode obtê-lo em sua página de download e talvez seja necessário criar uma conta gratuita, há planos pagos disponíveis, mas o gratuito aqui é suficiente.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Importante ressaltar que a escolha do seu cliente SSH é totalmente opcional.</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708104728047/fd5b37ec-1cf1-46ec-b512-b28332f4efc5.png" alt class="image--center mx-auto" /></p>
<p>Também há opções disponíveis para Mac e Linux no final da página;</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708104779160/b47df59a-d66d-42cc-b834-6707bf38da4b.png" alt class="image--center mx-auto" /></p>
<p>Não importa qual ferramenta SSH você usará, vimos agora que há muitas opções, tudo que você precisa ter em mente aqui é que você precisa se conectar na instância de alguma forma para seguirmos o tutorial.</p>
<hr />
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Como acabamos de ver, vou utilizar o cliente SSH Termius, então nossos prints irão se basear nisso, mas uma vez que você estiver conectado, os comandos serão todos iguais independente de qual ferramenta usou.</div>
</div>

<p>1- Acesse o console <strong>AWS Lightsail → Account → SSH Keys</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708105477034/74dae1d0-e863-4dcd-a92f-c3a60f4f800a.png" alt class="image--center mx-auto" /></p>
<p>2- Procure por <strong>Default Keys → download</strong></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se que estou usando <code>Norte da Virgínia</code>, por isso faço download da chave padrão dessa região.</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708105623262/9eaa27e5-2734-43de-8801-bba602c86908.png" alt class="image--center mx-auto" /></p>
<p>3- Abra o cliente <strong>SSH (em nosso exemplo Termius) → clique no ícone de engrenagem</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708105306882/64124329-09e1-46dd-8992-08233a36715f.png" alt class="image--center mx-auto" /></p>
<p>4- Defina um <strong>nome de sua preferência → mova o arquivo da sua chave keypair que baixou do console AWS</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708105876870/8b909b8a-cb48-44a4-b6da-955173932330.png" alt class="image--center mx-auto" /></p>
<p>5- Clique em <strong>New Host</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708106087597/2c8d677c-e421-48c5-825f-9169b0928a02.png" alt class="image--center mx-auto" /></p>
<p>6- Preencha os campos com:</p>
<ul>
<li><p><code>Address</code>: o IP da instância</p>
</li>
<li><p><code>Label</code>: nome de sua preferência</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708107910901/7ca25286-8404-4c96-b5be-bef779a9e07e.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p><code>User</code>: ubuntu</p>
</li>
<li><p>Selecione <code>Key</code></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708108034554/720336fb-5c99-4bba-ae23-98697d426e96.png" alt class="image--center mx-auto" /></p>
<p>Clique em <code>Connect</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708108020163/f56241d8-e94a-4fc9-b9a3-aec063003d40.png" alt class="image--center mx-auto" /></p>
<p>Clique em <code>Continue</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708108114171/ccbca068-93ab-4664-9a92-bd641c19b652.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708108139668/990d635c-730d-4ad9-9437-8a7e39fa4b8c.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Pronto! Você está conectado.</div>
</div>

<hr />
<h3 id="heading-instalando-o-docker-e-docker-compose">Instalando o Docker e Docker Compose</h3>
<p>Uma vez conectado na instância, você precisará instalar o <code>Docker</code> e o <code>Docker Compose</code>, por favor copie o código de instalação que criamos em outro artigo disponível aqui:</p>
<ul>
<li>👉 <a target="_blank" href="https://simplescloud.io/como-instalar-ou-atualizar-o-docker-e-o-docker-compose#heading-instalacao-ou-atualizacao">Como Instalar ou Atualizar o Docker e o Docker Compose</a></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720619026889/759f3b95-6dee-4437-8fb0-a3c6633afbc0.png" alt class="image--center mx-auto" /></p>
<p>Cole em seu terminal e pressione <code>Enter</code>.</p>
<p>Aguarde a instalação e ao final você deverá ver algo parecido com:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708109718243/eb7d08a7-ce3b-4412-be9d-454a7392ee1f.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Agora feche e abra seu terminal novamente para que os comandos <code>docker</code> sejam atualizados.</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text"><strong>Essa instalação é muito importante</strong>, pois precisaremos dela mais a frente para a instalação do self-hosted, além disso muito provavelmente seu runner precisará do docker para baixar e construir imagens em seu pipeline através do <code>docker in doker (dind)</code>. <strong>Então certifique-se de concluir essa instalação antes de seguir aos próximos passos.</strong></div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Pronto! Você está com todos os pré-requisitos deste tutorial concluídos.</div>
</div>

<hr />
<h2 id="heading-adicionando-um-self-hosted-runner-do-bitbucket">Adicionando um Self-Hosted Runner do Bitbucket</h2>
<p>1- Acesse sua conta <strong>Bitbucket → ícone de engrenagem → Workspace Settings</strong></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se que comentamos que criaremos o runner a nível do workspace para disponibilizar para todos os repositórios. Mas se você preferir criar somente para o repositório você precisa entrar nas configurações do repositório e em runner, após isso todos os passos são exatamente iguais.</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708109248634/cfc1c91e-c662-47e5-ac40-58d11f23c237.png" alt class="image--center mx-auto" /></p>
<p>2- Clique em <strong>Workspace runners → Add runner</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708109347276/4d821728-bb5c-4518-879d-94cf84256cb5.png" alt class="image--center mx-auto" /></p>
<p>3- Escolha <strong>Linux Docker (x86_64)</strong></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Há várias opções disponíveis, mas vamos nos concentrar em Linux Docker, isso nos dará mais liberdade e flexibilidade para executar qualquer coisa nele.</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708110027440/d0d6da67-b9ee-4af0-9d5a-f2642fda5276.png" alt class="image--center mx-auto" /></p>
<p>4- Defina um <strong>nome de sua preferência → crie um label</strong></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">O <code>label</code> que você criar, é o que será usado de fato no arquivo <code>bitbucket-pipelines.yml</code> . Observe que para nosso tutorial prático o <code>label</code> foi definido como <code>lightsail1</code></div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708110199143/0c538378-42d7-480e-b972-a57b5e740bc3.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Você pode definir quantos <code>labels</code> quiser de sua preferência</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708110281789/29190438-ed25-46a5-a8c6-6413ea3065b3.png" alt class="image--center mx-auto" /></p>
<p>5- Clique em <strong>Next</strong> → e ele fornecerá uma saída de comando como a seguinte</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Algumas informações foram omitidas por questões de segurança</div>
</div>

<pre><code class="lang-bash">docker container run -it \
-v /tmp:/tmp -v /var/run/docker.sock:/var/run/docker.sock \
-v /var/lib/docker/containers:/var/lib/docker/containers:ro \
-e ACCOUNT_UUID={xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} \
-e REPOSITORY_UUID={xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} \
-e RUNNER_UUID={xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} \
-e RUNTIME_PREREQUISITES_ENABLED=<span class="hljs-literal">true</span> \
-e OAUTH_CLIENT_ID=xxxxxxxxxxxxxxxx \
-e OAUTH_CLIENT_SECRET=xxxxxxxxxxxxxxxxxx \
-e WORKING_DIRECTORY=/tmp --name runner-xxxxxxxxxxxxxxxxxx docker-public.packages.atlassian.com/sox/atlassian/bitbucket-pipelines-runner:1
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text"><strong>Copie o código gerado</strong></div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708110414935/8cfd338a-a3f9-4168-846f-f17c4d84cea5.png" alt class="image--center mx-auto" /></p>
<p>6- Cole em seu <strong>terminal SSH → Enter</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708110505689/c9d374f1-5bf6-4748-adc2-6fbcebfe2b9a.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Ao final você verá algo parecido com:</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708116173901/a13b5dbb-30ce-4721-b0b7-517b381ebf0a.png" alt class="image--center mx-auto" /></p>
<p>7- Feche seu <strong>terminal SSH → retorne para sua conta Bitbucket</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708110694628/2cee350c-6241-4c8f-ba9b-dcb52e6048aa.png" alt class="image--center mx-auto" /></p>
<p>8- Abra novamente seu <strong>terminal → obtenha o ID do container do seu runner</strong> com o comando:</p>
<pre><code class="lang-bash">docker ps --format <span class="hljs-string">'table {{.ID}}\t{{.Names}}\t{{.Status}}'</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708210676885/2f44480e-02c5-459d-be70-78dec0101616.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Por padrão, se desligarmos a instância por qualquer motivo, o container do runner não será iniciado automaticamente, então vamos garantir que o runner sempre esteja <code>up</code> mesmo que você reinicie sua instância.</div>
</div>

<p>9- Digite o comando abaixo para atualizar o <code>restart policy</code> deste container:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se de alterar <code>&lt;your-container-id&gt;</code> para o ID de seu container obtido no passo acima</div>
</div>

<pre><code class="lang-bash">docker update --restart always &lt;your-container-id&gt;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708210973170/be282244-fe34-4302-beeb-faf00417ce20.png" alt class="image--center mx-auto" /></p>
<p>10- Verifique a inspeção de container com o novo <code>restart policy</code> definido:</p>
<pre><code class="lang-bash">docker inspect -f <span class="hljs-string">'{{ json .HostConfig.RestartPolicy }}'</span> &lt;your-container-id&gt;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708211308788/9813c6eb-4e59-4c58-8c9c-5e7b58eaecd9.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Pronto! Seu runner auto hospedado já está online e pronto para uso.</div>
</div>

<hr />
<h2 id="heading-use-o-self-hosted-runner-do-bitbucket">Use o Self-Hosted Runner do Bitbucket</h2>
<p>Para usar seu Self-Hosted Runner criado, você deve definir o seguinte trecho em seu arquivo <code>bitbucket-pipelines.yml</code>:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">runs-on:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">"lightsail1"</span>
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembrando que <code>"lightsail1"</code> foi o nosso <code>label</code> que definimos em nosso tutorial, ajuste isso para seu valor real que está usando.</div>
</div>

<hr />
<p><strong>Vamos para um exemplo:</strong></p>
<p>1- Crie um arquivo <code>bitbucket-pipelines.yml</code> na raíz do seu repositório, por exemplo:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">definitions:</span>

  <span class="hljs-attr">hello_my_self_hosted_runner:</span> <span class="hljs-meta">&amp;hello_my_self_hosted_runner</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">Hi</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">atlassian/default-image:4</span>
    <span class="hljs-attr">services:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">docker</span>
    <span class="hljs-attr">runs-on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"lightsail1"</span>
    <span class="hljs-attr">script:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">echo</span> <span class="hljs-string">"Hello, I'm running on Bitbucket's Self-Hosted Runner"</span>

<span class="hljs-attr">pipelines:</span>

  <span class="hljs-attr">branches:</span>

    <span class="hljs-attr">main:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">stage:</span>
          <span class="hljs-attr">name:</span> <span class="hljs-string">Production</span>
          <span class="hljs-attr">deployment:</span> <span class="hljs-string">production</span>
          <span class="hljs-attr">steps:</span>
            <span class="hljs-bullet">-</span> <span class="hljs-attr">step:</span> <span class="hljs-meta">*hello_my_self_hosted_runner</span>
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Observe o trecho <code>runs-on</code></div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708112113087/ab7fe1c5-755a-4f9b-b4a0-8812615b76b6.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">É aqui que estamos definindo para rodar somente no nosso <code>runner</code> criado com este <code>label</code>.</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">E então podemos verificar sua saída com sucesso</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708112519995/28bdaa4e-0a95-439d-966c-65011eb9381b.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Pronto! Você agora tem um runner próprio executando seu pipeline.</div>
</div>

<hr />
<h2 id="heading-bonus-seguranca">Bônus - Segurança</h2>
<p>Se você utilizar uma conexão entre Bitbucket e AWS com OpenID Connect, descrevemos o passo a passo de como fazer isso aqui:</p>
<ul>
<li>👉 <a target="_blank" href="https://simplescloud.io/como-configurar-a-autenticacao-entre-bitbucket-e-aws-com-openid-connect-oidc">Como configurar a Autenticação entre Bitbucket e AWS com OpenID Connect (OIDC)</a></li>
</ul>
<p>Você pode aumentar ainda mais a sua segurança limitando o acesso apenas a este Self-Hosted Runner com o trecho <code>SourceIp</code> da seguinte forma:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
  <span class="hljs-attr">"Principal"</span>: {
    <span class="hljs-attr">"Federated"</span>: <span class="hljs-string">"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:oidc-provider/api.bitbucket.org/2.0/workspaces/{WORKSPACE}/pipelines-config/identity/oidc"</span>
  },
  <span class="hljs-attr">"Action"</span>: <span class="hljs-string">"sts:AssumeRoleWithWebIdentity"</span>,
  <span class="hljs-attr">"Condition"</span>: {
    <span class="hljs-attr">"StringLike"</span>: {
      <span class="hljs-attr">"api.bitbucket.org/2.0/workspaces/{WORKSPACE}/pipelines-config/identity/oidc:sub"</span>: <span class="hljs-string">"{REPO_UUID}:*"</span>
    },
    <span class="hljs-attr">"IpAddress"</span>: {
      <span class="hljs-attr">"aws:SourceIp"</span>: [
        <span class="hljs-string">"&lt;your-runner-ip&gt;"</span>
      ]
    }
  }
}
</code></pre>
<p><img src="https://images.ctfassets.net/zsv3d0ugroxu/6gHQuuBiKmK1ukfOTJB5x0/8901fef78d97a5010cd29eb2bce9dd91/edit_role_trust_relationship" alt="Highlights editing your role trust relationship to limit tokens with IP ranges sub claim " /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Desta forma, somente seu runner é capaz de acessar, aumentando ainda mais sua segurança.</div>
</div>

<hr />
<h2 id="heading-limites-de-uso">Limites de Uso</h2>
<p>O Self-Hosted Runner tem os seguintes limites de uso:</p>
<ul>
<li><p><code>Máximo de memória disponível</code>: você pode configurar até 32 GB (8x) de memória</p>
</li>
<li><p><code>Número total de runners</code>: você pode configurar até 100 runners por workspace e 100 runners por repositório</p>
</li>
<li><p><code>Tempo de fila dos steps</code>: os steps podem ficar na fila por no máximo 2,5 horas</p>
</li>
</ul>
<hr />
<h2 id="heading-conclusao">Conclusão</h2>
<p>Em resumo, a escolha entre um Shared Runner e um Self-Hosted Runner no Bitbucket Pipelines depende das necessidades específicas do seu projeto. O Shared Runner oferece praticidade para projetos menores, enquanto o Self-Hosted Runner proporciona controle total, personalização e eficiência em ambientes mais complexos.</p>
<p>Vimos em um tutorial prático o passo a passo de como criar um Self-Hosted Runner hospedado na AWS. Também vimos que é possível limitar a segurança para um IP específico para que você tenha certeza de estar usando somente seu runner.</p>
<p>Se você observar bem, todo o processo ainda é manual e você pode repeti-lo quantas vezes precisar. Você ainda pode pensar em uma solução automática para lançar seus runners e escalar eles, mas para a grande maioria esse procedimento manual será suficiente.</p>
<p>Ao entender os benefícios do Self-Hosted Runner, como controle total do ambiente, personalização flexível e integração com recursos internos, você pode tomar decisões mais informadas para otimizar seus processos de CI/CD. Escolha o tipo de Runner que se alinha melhor com os requisitos únicos do seu projeto, garantindo uma implementação eficaz e adaptada ao seu ambiente de desenvolvimento.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se de excluir todos os recursos ao final para não obter cobranças indesejadas e manter sua conta AWS limpa e organizada.</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Espero que as informações tenham sido úteis para você!</div>
</div>]]></content:encoded></item><item><title><![CDATA[Como Criar um Self-Hosted Agent do Azure DevOps]]></title><description><![CDATA[Introdução
Em um cenário de desenvolvimento ágil e integração contínua, a flexibilidade é importante. É nesse contexto que os Self-Hosted Agents do Azure DevOps emergem como uma solução poderosa, oferecendo controle total sobre seu ambiente de build ...]]></description><link>https://simplescloud.com.br/como-criar-um-self-hosted-agent-do-azure-devops</link><guid isPermaLink="true">https://simplescloud.com.br/como-criar-um-self-hosted-agent-do-azure-devops</guid><category><![CDATA[azure devops self hosted agent]]></category><category><![CDATA[azure-devops]]></category><dc:creator><![CDATA[SimplesCloud]]></dc:creator><pubDate>Wed, 10 Jul 2024 13:40:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1708267615287/9a3280c4-7cc1-4074-8296-af37e49b4781.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introducao">Introdução</h2>
<p>Em um cenário de desenvolvimento ágil e integração contínua, a flexibilidade é importante. É nesse contexto que os Self-Hosted Agents do Azure DevOps emergem como uma solução poderosa, oferecendo controle total sobre seu ambiente de build e deploy.</p>
<p>Neste artigo, exploraremos passo a passo como criar seu próprio Agent Auto Hospedado do Azure DevOps. Essa abordagem não apenas amplia a capacidade de personalização do seu pipeline, mas também proporciona maior eficiência ao permitir a execução de builds em um ambiente familiar e sob seu controle direto.</p>
<hr />
<h2 id="heading-tipos-de-agents-do-azure-devops">Tipos de Agents do Azure DevOps</h2>
<p>O Azure DevOps oferece flexibilidade na execução de pipelines de CI/CD através de três tipos de Agents:</p>
<ul>
<li><p><code>Microsoft-Hosted Agents</code></p>
</li>
<li><p><code>Self-Hosted Agents</code></p>
</li>
<li><p><code>Azure Virtual Machine Scale Set Agents</code></p>
</li>
</ul>
<h3 id="heading-microsoft-hosted-agents">Microsoft-Hosted Agents</h3>
<ul>
<li><p><strong>Servidores Gerenciados pela Microsoft:</strong> Os Microsoft-Hosted Agents são servidores de build e deploy totalmente gerenciados e atualizados pela Microsoft e estão pronto para uso sem qualquer configuração adicional.</p>
</li>
<li><p><strong>Limite Gratuito de Minutos por Mês:</strong> no momento da criação deste artigo, existe um limite de 1.800 minutos gratuitos por mês para o uso, oferecendo uma opção econômica para projetos menores.</p>
</li>
<li><p><strong>Solicitação de Liberação de Minutos:</strong> A Microsoft começou a exigir a solicitação através de um formulário para liberar os 1.800 minutos gratuitos para evitar abusos, se você não o fizer receberá um erro parecido com:</p>
</li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">No hosted parallelism has been purchased or granted</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708268602951/0bb57224-d1e3-4bef-b566-bee9d300f70c.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Essa mensagem de erro acontece porque por padrão as novas contas criadas recebem <code>0Microsoft-Hosted</code> :</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708268810729/77f12388-f2e5-4135-9dc1-9d8f6a2f4821.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">E para resolver isso, você pode clicar no link do próprio erro para preencher o formulário de liberação</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708268999597/8445792e-5b48-4069-99bb-35fe69038be3.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708269048611/9ae930f4-c31e-434a-a24e-a3aa83f40f66.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Uma vez preenchido, você receberá por email um retorno dentro de 2 a 3 dias úteis</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708269186272/3af24fa8-b3a9-43bf-bf8e-ac4ca5083339.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">E isso será refletido em sua conta</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708270129731/39765e02-faf5-4a3c-beae-0ad1dc93ea1b.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-self-hosted-agents">Self-Hosted Agents</h3>
<ul>
<li><p><strong>Controle Total:</strong> Você precisa hospedar ou gerenciar o servidor. O self-hosted oferece controle total ao permitir que você configure e mantenha seus próprios agentes de build.</p>
</li>
<li><p><strong>Adaptabilidade ao Ambiente:</strong> Permite a execução de builds em um ambiente que você controla, com a flexibilidade de adaptar recursos conforme necessário.</p>
</li>
<li><p><strong>Adequado para Projetos Complexos:</strong> Ideal para projetos maiores, equipes que requerem ambientes específicos ou aqueles que precisam integrar com recursos internos.</p>
</li>
<li><p><strong>Cobrança:</strong> Você tem a cobrança do seu servidor, mas seus minutos são ilimitados e você não será cobrado pelo limite e preço do Azure DevOps.</p>
</li>
</ul>
<hr />
<h3 id="heading-azure-virtual-machine-scale-set-agents">Azure Virtual Machine Scale Set Agents</h3>
<ul>
<li><p><strong>Elasticidade com Azure Virtual Machine Scale Set:</strong> Os Azure Virtual Machine Scale Set Agents oferecem elasticidade, permitindo a escala automática de máquinas virtuais conforme a demanda de build e deploy.</p>
</li>
<li><p><strong>Integração com Azure DevOps:</strong> Projetados para integração direta com o Azure DevOps, esses agentes fornecem um ambiente escalável e gerenciável para pipelines de CI/CD.</p>
</li>
<li><p><strong>Configuração Sob Demanda:</strong> Permitem a configuração sob demanda de máquinas virtuais, garantindo recursos adequados para lidar com a carga de trabalho, com a flexibilidade de ajustar conforme necessário.</p>
</li>
</ul>
<hr />
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Neste artigo, nos concentraremos no Self-Hosted Agent, ainda há vários tipos de instalação como por exemplo em Windows, Linux e Docker, nos concentraremos também na instalação em Docker para proporcionar maior isolamento e portabilidade.</div>
</div>

<hr />
<h2 id="heading-beneficios-do-self-hosted-agents">Benefícios do Self-Hosted Agents</h2>
<ul>
<li><p><strong>Configurações de build personalizadas:</strong> os agents permitem que você configure seu hardware para diferentes tipos de build. Por exemplo, se seu build tiver que consumir muitos recursos, usar hardware com mais memória pode melhorar o tempo de execução.</p>
</li>
<li><p><strong>Acesse aplicativos ou bancos de dados internos:</strong> ao executar pipelines na infraestrutura do Azure DevOps com Microsoft-Hosted Agents, dificulta o trabalho para poder acessar sistemas internos como banco de dados por exemplo. Se você precisa executar testes de integração em seus bancos de dados ou aplicativos internos, você poderá fazer isso com agents auto hospedados na mesma rede fornecendo acesso necessário aos serviços internos.</p>
</li>
<li><p><strong>Fluxos de trabalho híbridos</strong>: você pode otimizar seus recursos usando agents auto hospedados com configurações personalizadas para builds que exigem isso e usar a infraestrutura do Azure DevOps com Microsoft-Hosted Agents para outros trabalhos.</p>
</li>
</ul>
<hr />
<h2 id="heading-tutorial-pratico-pre-requisitos">Tutorial Prático - Pré-Requisitos</h2>
<p>Para a instalação de um Agent auto hospedado do Azure DevOps, como o nome sugere você precisará de uma máquina, isso pode ser desde seu próprio computador até qualquer VPS de sua preferência.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Para o tutorial deste artigo, usarei uma instância do AWS Lightsail, pois seu pacote de instância + tráfego de rede é ofertado a um preço mais acessível. Mas novamente você pode escolher de acordo com sua preferência como <code>AWS EC2</code>, <code>Google Compute Engine</code>, <code>Digital Ocean</code>, <code>Vultr</code>, <code>Linode</code>, etc.</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Se você já é mais experiente, ou se não deseja usar o Lightsail, você pode ignorar as etapas abaixo de criação de instância, criação de IP fixo e conexão SSH, não importa qual VPS você criou. Você pode pular diretamente para etapa de configuração dentro da instância e encurtar seu caminho deste artigo, mas se você é mais iniciante ou se está um pouco confuso nesse momento, recomendo seguir todos os passos.</div>
</div>

<hr />
<h3 id="heading-criando-uma-instancia-lightsail">Criando uma instância Lightsail</h3>
<p>1- Acesse o console <strong>AWS → Lightsail → Create Instance</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708102124604/20d8b633-3829-489c-bd43-3905a0c2ba6d.png" alt class="image--center mx-auto" /></p>
<p>2- Escolha a <strong>região</strong></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Em nosso exemplo, escolhi a região <code>Norte da Virgínia</code> e a <code>Zona de Disponibilidade A</code></div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708102197827/088a9e8f-9e80-4950-9189-e8e39ebf7bb9.png" alt class="image--center mx-auto" /></p>
<p>3- Escolha o <strong>sistema operacional</strong></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Nem todos os sistemas operacionais são suportados, então escolhi a opção <code>Ubuntu 22.04</code> que é a mais recente no momento da criação deste artigo</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708102303030/f881fb52-174c-46e5-b6fe-e4614fb8fa4b.png" alt class="image--center mx-auto" /></p>
<p>4- Não adicione um <code>script de inicialização</code>, não altere sua <code>chave key-pair</code> e não habilite <code>snapshots automáticos</code>, as opções padrões parecem boas aqui.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708102404328/8c155344-8870-4bf8-93cc-7d9a36ade383.png" alt class="image--center mx-auto" /></p>
<p>5- Escolha <code>Dual Stack</code>, pois ainda há limitações para uso do <code>IPv6</code> e precisamos que nossa <strong>instância tenha IPv4 também</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708102502783/ceb3b2da-e727-43a4-9fa2-837bf2485ed7.png" alt class="image--center mx-auto" /></p>
<p>6- Selecione o <strong>tamanho da instância</strong></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se que essa decisão é muito importante, quanto menor a instância você escolher, mais lentidão e problemas seu pipeline pode ter por conta de falta de memória ou cpu. Para nosso artigo escolhi a opção <code>small de USD 10 com 2GB de memória, 2 vCPU e 3TB de transferência de dados</code>.</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Em minhas experiências, as instâncias abaixo de <code>1GB de memória não chegam a funcionar corretamente</code>, e tenho usado <code>instâncias acima de 4GB de memória em ambientes de produção</code> . Mas para efeitos de tutorial essa parece ser uma escolha boa.</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708102665985/a88dfcb6-207d-4edc-a16b-69430e9cf42d.png" alt class="image--center mx-auto" /></p>
<p>7- Defina um <strong>nome</strong>, opcionalmente você pode inserir <strong>tags</strong> e clique em <strong>criar instância</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708271196101/91ec0f1c-444a-439b-8989-ba9f1ee3738b.png" alt class="image--center mx-auto" /></p>
<p>8- Aguarde até o status <code>Pending</code> mudar para <code>Running</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708271234209/02924998-bba9-4629-abf5-628912afd0ed.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708271303179/bf5e2bf3-d540-4105-8edf-2632703b6a47.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Pronto! Nesse momento, você já tem uma instância criada com sucesso.</div>
</div>

<hr />
<h3 id="heading-criando-um-ip-fixo">Criando um IP Fixo</h3>
<p>Se olharmos bem, a instância Lightsail recebeu um <code>IPv4</code> e <code>IPv6</code> público dinâmicos, isso aconteceu porque selecionamos a opção <code>Dual Stack</code> quando criamos a instância. O dinâmico significa que quando desligarmos essa instância e ligarmos novamente, esses endereços IPs irão mudar, isso pode ser um pouco chato e frustrante de se lembrar, principalmente quando você está tentando se conectar a ela.</p>
<p>Então vamos resolver isso criando um IP Fixo.</p>
<p>1- No console <strong>AWS Lightsail → Networking</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708271357491/c7032e49-2b4f-4768-b70c-ed681bacefba.png" alt class="image--center mx-auto" /></p>
<p>2- Clique em <strong>Create Static IP</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708103734361/c813a5b9-1aff-4353-b094-3f51890f1b31.png" alt class="image--center mx-auto" /></p>
<p>3- Mantenha a <strong>mesma região e zona de disponibilidade da sua instância → escolha a instância recém criada</strong></p>
<p>Em nosso exemplo <code>Norte da Virgínia</code> e <code>Zona de Disponibilidade A</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708271389920/817448cc-5af9-4fba-85b2-b53e211cbb99.png" alt class="image--center mx-auto" /></p>
<p>4- Defina um <strong>nome → Create</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708271446677/4e7e427e-c635-4f0e-a8ae-a1ef400a1e0e.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708271477358/a2a13b9a-ae87-4542-b106-a89ac34b2dfc.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Pronto! Agora já temos um IP Fixo anexado a nossa instância Lightsail</div>
</div>

<hr />
<h3 id="heading-conectando-via-ssh-na-instancia-lightsail">Conectando via SSH na instância Lightsail</h3>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Você pode fazer isso de muitas formas, com qualquer cliente SSH de sua preferência.</div>
</div>

<p>Se você não quiser usar um cliente SSH, pode fazer isso diretamente no console da AWS clicando nesse botão:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708271540590/4d85d6f0-6d7b-4ed3-8ddc-81f4b3884c8c.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">E isso irá abrir uma nova janela com seu acesso com sucesso:</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708271594202/7918e6f1-efb3-47ee-a4f2-6eaa75cebeef.png" alt class="image--center mx-auto" /></p>
<p>Se você estiver usando uma distribuição <code>linux</code>, como por exemplo <code>ubuntu</code>, poderia acessar também através do seu terminal com o comando:</p>
<pre><code class="lang-bash">ssh -i &lt;LightsailDefaultKey.pem&gt; &lt;user&gt;@&lt;public-ip&gt;
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Lembre-se que <code>LightsailDefaultKey.pem</code> é sua chave de acesso baixada do console da AWS, então especifique certinho o caminho da pasta para onde você fez download em sua máquina, também lembre-se que usamos o ubuntu, então mude <code>user</code> para <code>ubuntu</code> e <code>&lt;public-ip&gt;</code> para seu ip fixo criado.</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Para nosso exemplo isso seria:</div>
</div>

<pre><code class="lang-bash"><span class="hljs-comment"># Example</span>
ssh -i LightsailDefaultKey.pem ubuntu@54.160.152.44
</code></pre>
<p>Porém como estou usando em meu computador o sistema operacional Windows, eu poderia fazer isso através do <code>WSL2</code> com <code>Prompt de Comando</code> , <code>Powershell</code> ou <code>Terminal do Windows</code>, o <code>Putty</code> e muitas outras opções de clientes SSH disponíveis.</p>
<p>Mas prefiro usar o cliente gratuito chamado <code>Termius</code>, você pode obtê-lo em sua página de download e talvez seja necessário criar uma conta gratuita, há planos pagos disponíveis, mas o gratuito aqui é suficiente.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Importante ressaltar que a escolha do seu cliente SSH é totalmente opcional.</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708104728047/fd5b37ec-1cf1-46ec-b512-b28332f4efc5.png" alt class="image--center mx-auto" /></p>
<p>Também há opções disponíveis para Mac e Linux no final da página;</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708104779160/b47df59a-d66d-42cc-b834-6707bf38da4b.png" alt class="image--center mx-auto" /></p>
<p>Não importa qual ferramenta SSH você usará, vimos agora que há muitas opções, tudo que você precisa ter em mente aqui é que você precisa se conectar na instância de alguma forma para seguirmos o tutorial.</p>
<hr />
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Como acabamos de ver, vou utilizar o cliente SSH Termius, então nossos prints irão se basear nisso, mas uma vez que você estiver conectado, os comandos serão todos iguais independente de qual ferramenta usou.</div>
</div>

<p>1- Acesse o console <strong>AWS Lightsail → Account → SSH Keys</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708105477034/74dae1d0-e863-4dcd-a92f-c3a60f4f800a.png" alt class="image--center mx-auto" /></p>
<p>2- Procure por <strong>Default Keys → download</strong></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se que estou usando <code>Norte da Virgínia</code>, por isso faço download da chave padrão dessa região.</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708105623262/9eaa27e5-2734-43de-8801-bba602c86908.png" alt class="image--center mx-auto" /></p>
<p>3- Abra o cliente <strong>SSH (em nosso exemplo Termius) → clique no ícone de engrenagem</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708105306882/64124329-09e1-46dd-8992-08233a36715f.png" alt class="image--center mx-auto" /></p>
<p>4- Defina um <strong>nome de sua preferência → mova o arquivo da sua chave keypair que baixou do console AWS</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708105876870/8b909b8a-cb48-44a4-b6da-955173932330.png" alt class="image--center mx-auto" /></p>
<p>5- Clique em <strong>New Host</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708106087597/2c8d677c-e421-48c5-825f-9169b0928a02.png" alt class="image--center mx-auto" /></p>
<p>6- Preencha os campos com:</p>
<ul>
<li><p><code>Address</code>: o IP da instância</p>
</li>
<li><p><code>Label</code>: nome de sua preferência</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708271776575/0834f74b-43ff-4136-b969-587908b27146.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p><code>User</code>: ubuntu</p>
</li>
<li><p>Selecione <code>Key</code></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708108034554/720336fb-5c99-4bba-ae23-98697d426e96.png" alt class="image--center mx-auto" /></p>
<p>Clique em <code>Connect</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708108020163/f56241d8-e94a-4fc9-b9a3-aec063003d40.png" alt class="image--center mx-auto" /></p>
<p>Clique em <code>Continue</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708271863447/5dae1208-2837-4850-be0f-bb3cd0419eb1.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708271888449/faa12c55-6496-4f07-b790-c90f6b5620a0.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Pronto! Você está conectado.</div>
</div>

<hr />
<h3 id="heading-instalando-o-docker-e-docker-compose">Instalando o Docker e Docker Compose</h3>
<p>Uma vez conectado na instância, você precisará instalar o <code>Docker</code> e o <code>Docker Compose</code>, por favor copie o código de instalação que criamos em outro artigo disponível aqui:</p>
<ul>
<li>👉 <a target="_blank" href="https://simplescloud.io/como-instalar-ou-atualizar-o-docker-e-o-docker-compose#heading-instalacao-ou-atualizacao">Como Instalar ou Atualizar o Docker e o Docker Compose</a></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720618391252/99f1a177-30ff-47ae-946a-b18d315ce1fc.png" alt class="image--center mx-auto" /></p>
<p>Cole em seu terminal e pressione <code>Enter</code>.</p>
<p>Aguarde a instalação e ao final você deverá ver algo parecido com:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708272075878/f11cba3e-5867-4c2a-a4bb-2691f5e937d6.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Agora feche e abra seu terminal novamente para que os comandos <code>docker</code> sejam atualizados.</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text"><strong>Essa instalação é muito importante</strong>, pois precisaremos dela mais a frente para a instalação do self-hosted, além disso muito provavelmente seu agent precisará do docker para baixar e construir imagens em seu pipeline através do <code>docker in doker (dind)</code>. <strong>Então certifique-se de concluir essa instalação antes de seguir aos próximos passos.</strong></div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Pronto! Você está com todos os pré-requisitos deste tutorial concluídos.</div>
</div>

<hr />
<h3 id="heading-criando-um-personal-access-token-pat">Criando um Personal Access Token (PAT)</h3>
<p>1- Faça login no console <strong>Azure DevOps → ícone de engrenagem → Personal Access Token</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708274548107/a4e5dee9-8563-449f-8b47-efe8b33c5a56.png" alt class="image--center mx-auto" /></p>
<p>2- Clique em New Token</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708274586899/9b5e0353-40fd-4ea2-bf74-880a4e8a7880.png" alt class="image--center mx-auto" /></p>
<p>3- Defina:</p>
<ul>
<li><p>Um <strong>nome de sua preferência</strong>, por exemplo <code>self-hosted-agent-token</code></p>
</li>
<li><p>Sua organização</p>
</li>
<li><p>Altere o <strong>tempo de expiração de acordo com sua preferência</strong>, por exemplo gosto de definir o tempo máximo de um ano através da seleção no calendário, mas totalmente opcional</p>
</li>
<li><p>Em <code>scope</code>, selecione <code>Custom definied</code> → <code>Show all scopes</code></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708274984955/33c97ebe-0af3-45de-89fb-9cb8ba999e41.png" alt class="image--center mx-auto" /></p>
<p>4- Em <code>Agent Pools</code> → selecione <code>Read &amp; manage</code> → <code>Create</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708275101098/39d70c02-8efc-4d78-9dda-4ecc023e1028.png" alt class="image--center mx-auto" /></p>
<p>5- <strong>Copie e salve</strong> seu token em um local seguro agora</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Isso não será acessível depois</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708275188409/eec059f3-d087-4f54-87e1-b1c9c27fa173.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708275370109/c218bc59-7157-4c54-b373-64a452380c1f.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-instalando-o-self-hosted-agent">Instalando o Self-Hosted Agent</h2>
<p>1- Abra novamente seu terminal → crie o diretório chamado <code>azp-agent-in-docker</code> com o comando:</p>
<pre><code class="lang-bash">mkdir ~/azp-agent-in-docker \
&amp;&amp; <span class="hljs-built_in">cd</span> ~/azp-agent-in-docker
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708275503697/2d06375e-bf03-4284-9611-a2454c0af9fc.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Nós criaremos os arquivos chamados <code>Dockerfile</code> e <code>start.sh</code> nesta pasta nos próximos passos, certifique-se que ambos os arquivos estejam na mesma pasta.</div>
</div>

<p>2- Crie o arquivo <strong>Dockerfile</strong> com o comando:</p>
<pre><code class="lang-bash">touch Dockerfile
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708275662986/dd01dcaf-9ab5-4087-8aa9-3997d76e9041.png" alt class="image--center mx-auto" /></p>
<p>3- Insira o seguinte conteúdo em seu <strong>Dockerfile</strong>:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Você pode fazer através de qualquer editor de texto de sua preferência como por exemplo, <code>VSCode</code>, <code>vim</code>, <code>nano</code>, etc. Para nosso exemplo estamos usando o <code>nano</code> para editar o arquivo.</div>
</div>

<pre><code class="lang-bash">sudo nano Dockerfile
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708275801763/c73fb75a-c733-4448-95ca-3f0fff30b155.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708275821914/9b663117-34db-490a-910a-93b9b08441d2.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">E então eu copio o código abaixo:</div>
</div>

<pre><code class="lang-dockerfile"><span class="hljs-comment"># Use Ubuntu 22.04 as the base image</span>
<span class="hljs-keyword">FROM</span> ubuntu:<span class="hljs-number">22.04</span>

<span class="hljs-comment"># Update package information and upgrade installed packages</span>
<span class="hljs-keyword">RUN</span><span class="bash"> apt update &amp;&amp; \
    apt upgrade -y</span>

<span class="hljs-comment"># Install dependencies and capabilities</span>
<span class="hljs-keyword">RUN</span><span class="bash"> apt install -y \
    curl \
    git \
    jq \
    libicu70</span>

<span class="hljs-comment"># Set the target architecture (e.g., "linux-x64", "linux-arm", "linux-arm64")</span>
<span class="hljs-keyword">ENV</span> TARGETARCH=<span class="hljs-string">"linux-x64"</span>

<span class="hljs-comment"># Set the working directory inside the container</span>
<span class="hljs-keyword">WORKDIR</span><span class="bash"> /azp/</span>

<span class="hljs-comment"># Copy the start script to the working directory</span>
<span class="hljs-keyword">COPY</span><span class="bash"> ./start.sh ./</span>

<span class="hljs-comment"># Make the start script executable</span>
<span class="hljs-keyword">RUN</span><span class="bash"> chmod +x ./start.sh</span>

<span class="hljs-comment"># Create a user 'agent' and set ownership of the working directory</span>
<span class="hljs-keyword">RUN</span><span class="bash"> useradd agent &amp;&amp; \
    chown agent ./</span>

<span class="hljs-comment"># Switch to the 'agent' user</span>
<span class="hljs-keyword">USER</span> agent

<span class="hljs-comment"># Another option is to run the agent as root.</span>
<span class="hljs-comment"># ENV AGENT_ALLOW_RUNASROOT="true"</span>

<span class="hljs-comment"># Define the entry point for the container to execute the start script</span>
<span class="hljs-keyword">ENTRYPOINT</span><span class="bash"> ./start.sh</span>
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">E colo no terminal com o botão direito do mouse</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708276149007/188de3fe-b3d0-48e0-8d61-257a225fa07f.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Depois pressiono <code>Ctrl + X</code> + <code>Y</code> (para sim) + <code>Enter</code> para salvar</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">E podemos ver o arquivo criado com o comando:</div>
</div>

<pre><code class="lang-bash">cat Dockerfile
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708276258126/b14c621e-d657-4b46-a5f4-1cdd6a975415.png" alt class="image--center mx-auto" /></p>
<p>4- Agora crio o arquivo chamado <code>start.sh</code> com o comando:</p>
<pre><code class="lang-bash">touch start.sh
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708276460499/44b39808-5d2d-4707-a133-d751cea432a1.png" alt class="image--center mx-auto" /></p>
<p>5- Insira o seguinte conteúdo em seu <code>start.sh</code>:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Você pode fazer através de qualquer editor de texto de sua preferência como por exemplo, <code>VSCode</code>, <code>vim</code>, <code>nano</code>, etc. Para nosso exemplo estamos usando o <code>nano</code> para editar o arquivo.</div>
</div>

<pre><code class="lang-bash">sudo nano start.sh
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708276529754/92a25f66-f5ea-48c6-a972-208ff1590cb7.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708276544726/483c802d-798e-47d5-9be6-7ce9a1a61f8c.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">E então eu copio o código abaixo:</div>
</div>

<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>
<span class="hljs-built_in">set</span> -e

<span class="hljs-keyword">if</span> [ -z <span class="hljs-string">"<span class="hljs-variable">${AZP_URL}</span>"</span> ]; <span class="hljs-keyword">then</span>
  <span class="hljs-built_in">echo</span> 1&gt;&amp;2 <span class="hljs-string">"error: missing AZP_URL environment variable"</span>
  <span class="hljs-built_in">exit</span> 1
<span class="hljs-keyword">fi</span>

<span class="hljs-keyword">if</span> [ -z <span class="hljs-string">"<span class="hljs-variable">${AZP_TOKEN_FILE}</span>"</span> ]; <span class="hljs-keyword">then</span>
  <span class="hljs-keyword">if</span> [ -z <span class="hljs-string">"<span class="hljs-variable">${AZP_TOKEN}</span>"</span> ]; <span class="hljs-keyword">then</span>
    <span class="hljs-built_in">echo</span> 1&gt;&amp;2 <span class="hljs-string">"error: missing AZP_TOKEN environment variable"</span>
    <span class="hljs-built_in">exit</span> 1
  <span class="hljs-keyword">fi</span>

  AZP_TOKEN_FILE=<span class="hljs-string">"/azp/.token"</span>
  <span class="hljs-built_in">echo</span> -n <span class="hljs-string">"<span class="hljs-variable">${AZP_TOKEN}</span>"</span> &gt; <span class="hljs-string">"<span class="hljs-variable">${AZP_TOKEN_FILE}</span>"</span>
<span class="hljs-keyword">fi</span>

<span class="hljs-built_in">unset</span> AZP_TOKEN

<span class="hljs-keyword">if</span> [ -n <span class="hljs-string">"<span class="hljs-variable">${AZP_WORK}</span>"</span> ]; <span class="hljs-keyword">then</span>
  mkdir -p <span class="hljs-string">"<span class="hljs-variable">${AZP_WORK}</span>"</span>
<span class="hljs-keyword">fi</span>

<span class="hljs-function"><span class="hljs-title">cleanup</span></span>() {
  <span class="hljs-built_in">trap</span> <span class="hljs-string">""</span> EXIT

  <span class="hljs-keyword">if</span> [ -e ./config.sh ]; <span class="hljs-keyword">then</span>
    print_header <span class="hljs-string">"Cleanup. Removing Azure Pipelines agent..."</span>

    <span class="hljs-comment"># If the agent has some running jobs, the configuration removal process will fail.</span>
    <span class="hljs-comment"># So, give it some time to finish the job.</span>
    <span class="hljs-keyword">while</span> <span class="hljs-literal">true</span>; <span class="hljs-keyword">do</span>
      ./config.sh remove --unattended --auth <span class="hljs-string">"PAT"</span> --token $(cat <span class="hljs-string">"<span class="hljs-variable">${AZP_TOKEN_FILE}</span>"</span>) &amp;&amp; <span class="hljs-built_in">break</span>

      <span class="hljs-built_in">echo</span> <span class="hljs-string">"Retrying in 30 seconds..."</span>
      sleep 30
    <span class="hljs-keyword">done</span>
  <span class="hljs-keyword">fi</span>
}

<span class="hljs-function"><span class="hljs-title">print_header</span></span>() {
  lightcyan=<span class="hljs-string">"\033[1;36m"</span>
  nocolor=<span class="hljs-string">"\033[0m"</span>
  <span class="hljs-built_in">echo</span> -e <span class="hljs-string">"\n<span class="hljs-variable">${lightcyan}</span><span class="hljs-variable">$1</span><span class="hljs-variable">${nocolor}</span>\n"</span>
}

<span class="hljs-comment"># Let the agent ignore the token env variables</span>
<span class="hljs-built_in">export</span> VSO_AGENT_IGNORE=<span class="hljs-string">"AZP_TOKEN,AZP_TOKEN_FILE"</span>

print_header <span class="hljs-string">"1. Determining matching Azure Pipelines agent..."</span>

AZP_AGENT_PACKAGES=$(curl -LsS \
    -u user:$(cat <span class="hljs-string">"<span class="hljs-variable">${AZP_TOKEN_FILE}</span>"</span>) \
    -H <span class="hljs-string">"Accept:application/json;"</span> \
    <span class="hljs-string">"<span class="hljs-variable">${AZP_URL}</span>/_apis/distributedtask/packages/agent?platform=<span class="hljs-variable">${TARGETARCH}</span>&amp;top=1"</span>)

AZP_AGENT_PACKAGE_LATEST_URL=$(<span class="hljs-built_in">echo</span> <span class="hljs-string">"<span class="hljs-variable">${AZP_AGENT_PACKAGES}</span>"</span> | jq -r <span class="hljs-string">".value[0].downloadUrl"</span>)

<span class="hljs-keyword">if</span> [ -z <span class="hljs-string">"<span class="hljs-variable">${AZP_AGENT_PACKAGE_LATEST_URL}</span>"</span> -o <span class="hljs-string">"<span class="hljs-variable">${AZP_AGENT_PACKAGE_LATEST_URL}</span>"</span> == <span class="hljs-string">"null"</span> ]; <span class="hljs-keyword">then</span>
  <span class="hljs-built_in">echo</span> 1&gt;&amp;2 <span class="hljs-string">"error: could not determine a matching Azure Pipelines agent"</span>
  <span class="hljs-built_in">echo</span> 1&gt;&amp;2 <span class="hljs-string">"check that account "</span><span class="hljs-variable">${AZP_URL}</span><span class="hljs-string">" is correct and the token is valid for that account"</span>
  <span class="hljs-built_in">exit</span> 1
<span class="hljs-keyword">fi</span>

print_header <span class="hljs-string">"2. Downloading and extracting Azure Pipelines agent..."</span>

curl -LsS <span class="hljs-string">"<span class="hljs-variable">${AZP_AGENT_PACKAGE_LATEST_URL}</span>"</span> | tar -xz &amp; <span class="hljs-built_in">wait</span> $!

<span class="hljs-built_in">source</span> ./env.sh

<span class="hljs-built_in">trap</span> <span class="hljs-string">"cleanup; exit 0"</span> EXIT
<span class="hljs-built_in">trap</span> <span class="hljs-string">"cleanup; exit 130"</span> INT
<span class="hljs-built_in">trap</span> <span class="hljs-string">"cleanup; exit 143"</span> TERM

print_header <span class="hljs-string">"3. Configuring Azure Pipelines agent..."</span>

./config.sh --unattended \
  --agent <span class="hljs-string">"<span class="hljs-variable">${AZP_AGENT_NAME:-$(hostname)}</span>"</span> \
  --url <span class="hljs-string">"<span class="hljs-variable">${AZP_URL}</span>"</span> \
  --auth <span class="hljs-string">"PAT"</span> \
  --token $(cat <span class="hljs-string">"<span class="hljs-variable">${AZP_TOKEN_FILE}</span>"</span>) \
  --pool <span class="hljs-string">"<span class="hljs-variable">${AZP_POOL:-Default}</span>"</span> \
  --work <span class="hljs-string">"<span class="hljs-variable">${AZP_WORK:-_work}</span>"</span> \
  --replace \
  --acceptTeeEula &amp; <span class="hljs-built_in">wait</span> $!

print_header <span class="hljs-string">"4. Running Azure Pipelines agent..."</span>

chmod +x ./run.sh

<span class="hljs-comment"># To be aware of TERM and INT signals call ./run.sh</span>
<span class="hljs-comment"># Running it with the --once flag at the end will shut down the agent after the build is executed</span>
./run.sh <span class="hljs-string">"<span class="hljs-variable">$@</span>"</span> &amp; <span class="hljs-built_in">wait</span> $!
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">E colo no terminal com o botão direito do mouse</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708276687384/f0534fd7-6dc2-4c1b-8219-367590fa411f.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Depois pressiono <code>Ctrl + X</code> + <code>Y</code> (para sim) + <code>Enter</code> para salvar</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">E podemos ver o arquivo criado com o comando:</div>
</div>

<pre><code class="lang-bash">cat start.sh
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708276762481/6562245b-a3ed-42ea-b477-790c7731aeea.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Agora podemos ver a criação dos dois arquivos <code>Dockerfile</code> e <code>start.sh</code> criados na mesma pasta <code>azp-agent-in-docker</code> com o comando:</div>
</div>

<pre><code class="lang-bash">ls -1
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708276839453/1085d818-d27d-4bd4-a782-5086a676633a.png" alt class="image--center mx-auto" /></p>
<p>6- Agora construo a imagem com o comando:</p>
<pre><code class="lang-bash">docker build -t <span class="hljs-string">"azp-agent:linux"</span> -f Dockerfile .
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708278082586/60fcaac7-4194-46c7-90f6-d3fb80fdf26a.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">E podemos confirmar a imagem docker criada com sucesso com o comando:</div>
</div>

<pre><code class="lang-bash">docker image ls --format <span class="hljs-string">"table {{.ID}}\t{{.Repository}}"</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708278138869/c5098ebd-a3fe-49d7-9b31-51decaafb40a.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Pronto! Já temos nossa imagem pronta para uso.</div>
</div>

<hr />
<p>7- Agora vamos <strong>precisar de três informações</strong> para poder iniciar nosso container:</p>
<ul>
<li><p><code>AZP_URL</code>:</p>
<p>  Você pode obtê-la olhando para a barra de endereço do seu navegador:</p>
  <div data-node-type="callout">
  <div data-node-type="callout-emoji">🔗</div>
  <div data-node-type="callout-text">https://dev.azure.com/<code>&lt;your-organization&gt;</code></div>
  </div>

<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708289504114/f8fe1b62-c1f8-4575-9721-50814d852328.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><code>AZP_POOL</code>:</p>
  <div data-node-type="callout">
  <div data-node-type="callout-emoji">ℹ</div>
  <div data-node-type="callout-text">Você precisa criar um novo em<strong> Organization Settings → Agent Pools → Add Pool</strong></div>
  </div>

<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708289553968/e4cd223e-e7eb-4fae-a474-b00527e9924d.png" alt class="image--center mx-auto" /></p>
  <div data-node-type="callout">
  <div data-node-type="callout-emoji">ℹ</div>
  <div data-node-type="callout-text">Selecionar o tipo <code>Self-Hosted</code></div>
  </div>

<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708278848571/dfd1211d-6705-4537-ab26-2f8a4dbc532e.png" alt class="image--center mx-auto" /></p>
  <div data-node-type="callout">
  <div data-node-type="callout-emoji">ℹ</div>
  <div data-node-type="callout-text">Definir um nome de sua preferência, por exemplo <code>AWS-Lightsail-Self-Hosted-Linux-Docker</code> → manter a opção <code>Auto-provision this agent pool in all projects</code> marcado → <code>Create</code></div>
  </div>

<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708279002740/cecf79df-2928-4ed4-8385-1ec2f841f6b5.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><code>AZP_TOKEN</code>:</p>
<p>  Este é o <code>Personal Access Token (PAT)</code> que criamos e copiamos para um local seguro antes.</p>
</li>
</ul>
<hr />
<p>8- Com essas três informações em mãos, vamos iniciar o container com o seguinte comando:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se de substituir os valores para seus dados reais</div>
</div>

<pre><code class="lang-bash">docker run \
  -e AZP_URL=<span class="hljs-string">"&lt;Your Azure DevOps instance&gt;"</span> \
  -e AZP_TOKEN=<span class="hljs-string">"&lt;Your Personal Access Token&gt;"</span> \
  -e AZP_POOL=<span class="hljs-string">"&lt;Your Agent Pool Name&gt;"</span> \
  -e AZP_AGENT_NAME=<span class="hljs-string">"AWS Lightsail Docker Agent 1"</span> \
  --name <span class="hljs-string">"azp-agent-1"</span> \
  azp-agent:linux
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708285553922/4c5a384c-0e66-4f9f-9e20-6b609e7289f1.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708285892104/48ebf28a-2078-4414-a153-3d925b01bdbd.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Pronto! Podemos ver o Agent pronto para uso</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708289600401/9d18ec06-e3f6-4c6a-9876-65aa5b10b16e.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">E podemos verificar os <code>capabilities</code> com as ferramentas úteis que foram listadas no Dockerfile</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708289645083/e4c2caf5-7b00-458d-9f2e-d22cd29a64f6.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Por padrão, o container não irá iniciar automaticamente se sua instância for desligada ou reiniciada. Então vamos garantir que o container sempre se inicie com o <code>restart policy</code> deste container do agent</div>
</div>

<p>9- Digite o comando abaixo para atualizar o <code>restart policy</code> deste container:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se de alterar <code>&lt;your-container-id&gt;</code> para o ID de seu container obtido com o comando <code>docker ps -a</code> por exemplo</div>
</div>

<pre><code class="lang-bash">docker update --restart always &lt;your-container-id&gt;
</code></pre>
<p>10- Verifique a inspeção de container com o novo <code>restart policy</code> definido:</p>
<pre><code class="lang-bash">docker inspect -f <span class="hljs-string">'{{ json .HostConfig.RestartPolicy }}'</span> &lt;your-container-id&gt;
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Pronto! Seu agent auto hospedado já está online e pronto para uso.</div>
</div>

<hr />
<h2 id="heading-usando-o-self-hosted-agent">Usando o Self-Hosted Agent</h2>
<p>Se você estiver usando o arquivo <code>azure-pipelines.yml</code> você pode definir seu Self-Hosted Agent no trecho <code>pool</code>, por exemplo:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">trigger:</span>
<span class="hljs-bullet">-</span> <span class="hljs-string">main</span>

<span class="hljs-attr">pool:</span>
  <span class="hljs-comment"># Name of your agent pool</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">'AWS-Lightsail-Self-Hosted-Linux-Docker'</span>  

<span class="hljs-attr">jobs:</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">job:</span> <span class="hljs-string">RunOnSelfHostedAgent</span>
  <span class="hljs-attr">displayName:</span> <span class="hljs-string">'Run on AWS Lightsail Docker Agent'</span>
  <span class="hljs-attr">steps:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">script:</span> <span class="hljs-string">echo</span> <span class="hljs-string">"Hi, I'm running on AWS Lightsail Docker Agent 1"</span>
    <span class="hljs-attr">displayName:</span> <span class="hljs-string">'Print Message'</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708287345193/d52a886d-786d-4577-9cdc-3680c7dd53b8.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">E executando o pipeline, podemos visualizar em <code>Initialize Job</code> o agente self-hosted agent que criamos sendo usado.</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708287525837/800602b0-bce0-4d1b-a32b-d224004f9839.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Se voltarmos para nosso terminal, podemos ver exatamente o nome do container igual ao apresentado acima com o comando:</div>
</div>

<pre><code class="lang-bash">docker ps --format <span class="hljs-string">"table {{.ID}}\t{{.Names}}"</span> --all
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708287728349/3a2ac737-a2a3-4f69-ba48-ac33ea5264e8.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708287759469/24388508-9753-4775-b590-16081e32b706.png" alt class="image--center mx-auto" /></p>
<hr />
<p>Se você estiver usando o editor <code>classic</code> , poderá fazer isso selecionando o <code>pool</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708288030007/136d3039-7d3e-47c1-83b0-6917fbc69e15.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708288133667/c40fc8f6-7674-47f0-829f-3e67e4975d41.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708288152713/f3413722-c159-4e8f-bdbd-368817094086.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-bonus-atualizacao-dos-agents">Bônus - Atualização dos Agents</h2>
<p>A qualquer momento, você pode atualizar seus agents em <strong>Organization Settings → Agent Pools → More Options (três pontinhos) → Update Agent</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708288347371/60e14928-99c6-4173-a3d8-5c8783221b5c.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708288368147/a45cddc8-e02c-4e22-9f0f-e186dd20305b.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-conclusao">Conclusão</h2>
<p>Em meio ao dinâmico cenário da automação e integração contínua, o Self-Hosted Agent do Azure DevOps emerge como uma ferramenta poderosa para capacitar equipes de desenvolvimento. Neste artigo, exploramos os diferentes tipos de agents disponíveis, destacando a versatilidade e flexibilidade do Self-Hosted Agent.</p>
<p>Ao conduzir um passo a passo prático, mergulhamos na criação de um Self-Hosted Agent utilizando o Docker. Essa abordagem não apenas oferece controle total sobre o ambiente de execução, mas também demonstra a escalabilidade e eficiência proporcionadas pelo uso de containers.</p>
<p>Vimos que os passos são manuais e você pode repeti-los quantas vezes for necessário. Também pode ainda pensar em uma forma de automatizar e escalar a criação de seus Self-Hosted Agents, mas para a maioria das pessoas isso será o suficiente.</p>
<p>Ao concluir esta jornada, espero que você esteja equipado com os conhecimentos necessários para aproveitar ao máximo o potencial do Self-Hosted Agent no Azure DevOps. A capacidade de personalizar, escalar e integrar-se perfeitamente ao seu ambiente torna esse recurso essencial para otimizar seus fluxos de trabalho de CI/CD.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se de excluir todos os recursos ao final para não obter cobranças indesejadas e manter sua conta AWS limpa e organizada.</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Espero que as informações tenham sido úteis para você!</div>
</div>]]></content:encoded></item><item><title><![CDATA[Como Instalar ou Atualizar o Docker e o Docker Compose]]></title><description><![CDATA[https://youtu.be/FIITx7u7XYw
 

Introdução
Explorar as possibilidades da tecnologia de containers é uma jornada emocionante para desenvolvedores e profissionais de DevOps. O Docker e o Docker Compose são ferramentas importantes e suas instalações pod...]]></description><link>https://simplescloud.com.br/como-instalar-ou-atualizar-o-docker-e-o-docker-compose</link><guid isPermaLink="true">https://simplescloud.com.br/como-instalar-ou-atualizar-o-docker-e-o-docker-compose</guid><category><![CDATA[docker-compose-install]]></category><category><![CDATA[docker-wsl2]]></category><category><![CDATA[Docker]]></category><category><![CDATA[docker install ]]></category><category><![CDATA[Docker compose]]></category><category><![CDATA[docker windows]]></category><dc:creator><![CDATA[SimplesCloud]]></dc:creator><pubDate>Fri, 26 Apr 2024 17:44:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1713192706438/eedcbd3a-9a37-49da-8b8c-3b7c60821573.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<hr />
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/FIITx7u7XYw">https://youtu.be/FIITx7u7XYw</a></div>
<p> </p>
<hr />
<h2 id="heading-introducao">Introdução</h2>
<p>Explorar as possibilidades da tecnologia de containers é uma jornada emocionante para desenvolvedores e profissionais de DevOps. O Docker e o Docker Compose são ferramentas importantes e suas instalações podem ser uma experiência única e empolgante, especialmente ao explorar novos caminhos para otimizar o ambiente de desenvolvimento.</p>
<p>Existem duas versões do Docker:</p>
<ul>
<li><p><code>Docker CE (Community Edition)</code>: é uma versão gratuita e de código aberto do Docker, adequada para uso pessoal e em pequenas e médias empresas. O suporte é principalmente fornecido pela comunidade e pode ser mais limitado em comparação com o Docker EE.</p>
</li>
<li><p><code>Docker EE (Enterprise Edition)</code>: é uma versão paga do Docker, projetada para uso em ambientes corporativos e em grande escala. Ela oferece suporte comercial, SLAs (Service Level Agreements) e recursos adicionais voltados para segurança, conformidade e integração.</p>
</li>
</ul>
<p>Neste artigo, compartilho como tenho feito a instalação ou atualização do Docker CE (Community Edition) e do Docker Compose que são gratuitos. Além disso, vou detalhar como essa instalação pode ser realizada de forma eficiente no contexto do Windows, aproveitando o WSL2 (<code>Windows Subsystem for Linux 2</code>) e dispensando a necessidade do aplicativo Docker Desktop.</p>
<hr />
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Para uma melhor compreensão do processo de instalação do Docker no Windows, é importante destacar algumas considerações específicas para esse sistema operacional. No entanto, se você já estiver familiarizado com o ambiente Linux, pode pular diretamente para as instruções de instalação. Por outro lado, se você estiver utilizando o Windows, recomendo que leia esta seção inicial para obter um contexto mais abrangente antes de prosseguir com o tutorial de instalação.</div>
</div>

<hr />
<h2 id="heading-para-usuarios-do-windows">Para Usuários do Windows</h2>
<p>Se você usa o Windows, não se preocupe, poderá fazer a instalação deste artigo sem problemas, mas antes de seguirmos em frente, é interessante que você saiba que há duas formas de instalar o Docker no Windows:</p>
<h3 id="heading-opcao-1-aplicativo-docker-desktop">Opção 1 - Aplicativo Docker Desktop</h3>
<p>Não há muitas novidades aqui, você pode fazer essa instalação:</p>
<p>1- Acesse o site oficial:</p>
<ul>
<li>👉 <a target="_blank" href="https://www.docker.com/products/docker-desktop/">https://www.docker.com/products/docker-desktop/</a></li>
</ul>
<p>2- Clique em <code>Download for Windows</code>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713207054337/47313ae9-d6d1-4f0f-8b5b-927a52c9b6e4.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Para concluir a instalação, basta seguir as etapas padrão, semelhantes a qualquer outro aplicativo no Windows, clicando em <code>Next → Next → Finish</code>.</div>
</div>

<p>Ao final, você pode obter um resultado semelhante:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713207948885/1299ae77-9a08-4333-b101-8318b5bdb2e9.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-opcao-2-sugerida-wsl2">Opção 2 (Sugerida) - WSL2</h3>
<p>WSL2 significa (<code>Windows Subsystem for Linux 2</code>) e possibilita ter um Linux nativo dentro do Windows, então a ideia aqui é instalar o Docker diretamente no Linux nativo do Windows. Entrarei em mais detalhes sobre algumas vantagens e desvantagens sobre isso, de qualquer forma essa opção exige que seu Windows tenha um WSL2 instalado e configurado, para isso talvez você ache interessante ler este outro artigo com um passo a passo de como atingir esse requisito:</p>
<ul>
<li>👉 <a target="_blank" href="https://simplescloud.io/wsl2">WSL2 - Instalação e Configuração</a></li>
</ul>
<hr />
<h3 id="heading-vantagens-e-desvantagens">Vantagens e Desvantagens</h3>
<p>Até agora mencionei que há duas opções de instalação do Docker no Windows, mas como você pode decidir qual é a melhor opção para você? Para responder essa pergunta, vou detalhar um pouco mais algumas coisas que aprendi para ajudar você a tomar essa decisão.</p>
<p>Ao instalar o aplicativo Docker Desktop no Windows, no background ele usará o WSL2, mas de uma forma um pouco diferente. Quando a instalação for concluída, será criado duas distribuições adicionais do WSL2 em seu dispositivo:</p>
<ul>
<li><p><code>docker-desktop</code>: responsável por executar o <code>docker deamon</code> e sua infraestrutura ao redor para seu funcionamento.</p>
</li>
<li><p><code>docker-desktop-data</code>: responsável por armazenar as imagens e configurações do docker.</p>
</li>
</ul>
<pre><code class="lang-plaintext">NAME                     STATE           VERSION
* Ubuntu-22.04           Running         2
  docker-desktop         Running         2
  docker-desktop-data    Running         2
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713209500735/37fbd5e3-caae-4f09-aadd-a176d2813a75.png" alt class="image--center mx-auto" /></p>
<p>Como você pode perceber, você precisará de mais recursos como <code>memória</code>, <code>cpu</code>, <code>disco</code>, etc para executar todas as distribuições ao mesmo tempo. Então a grande <strong>desvantagem</strong> aqui é a performance e a lentidão.</p>
<p>Eu particularmente não gosto dessa abordagem, por dois motivos:</p>
<ul>
<li><p>Para aprender docker, eu prefiro executar o comandos docker ao invés de depender de uma interface gráfica</p>
</li>
<li><p>Quando estou na minha <code>distribuição linux nativo com o WSL2</code> e executo um comando docker, na verdade não estou usando o docker diretamente nele, mas estou usando a outra distribuição <code>docker-desktop</code>, então eu acho que isso é uma etapa a mais desnecessária e que pode causar erros e lentidões.</p>
</li>
</ul>
<p>Em contrapartida, uma grande <strong>vantagem</strong> é que o Docker estará compartilhado e disponível em qualquer ambiente ou ferramenta que você usar, por ele estar em uma distribuição dedicada à isso (distro <code>docker-desktop</code>), todos os comandos docker funcionarão no <code>windows terminal</code>, no <code>powershell</code>, no <code>cmd</code>, etc.</p>
<p>Embora eu não ache isso muito útil, pois na maioria das vezes uso apenas minha <code>distribuição linux nativa do WSL2</code>, então raramente eu preciso do docker no <code>powershell</code> ou <code>cmd</code> por exemplo. Mas entendo se este não for o seu caso.</p>
<p>Uma grande <strong>desvantagem</strong> da instalação no WSL2 é que ela é individual, ou seja, se você tiver várias distribuições, deverá instalar o docker em cada uma delas, pois diferente da instalação do Docker Desktop, os comandos não ficam compartilhados entre as distribuições, felizmente vou compartilhar um único comando rápido e fácil que ajudará essa repetição ser bem menos tediosa.</p>
<p>Em resumo, você pode tomar sua decisão agora baseando-se em:</p>
<ul>
<li><p><strong>Aplicativo Docker Desktop</strong>: se você deseja ter uma interface gráfica ou executar comandos docker em qualquer lugar como <code>powershell</code>, <code>cmd</code> ou <code>windows terminal</code>, essa opção pode ser a mais adequada para você.</p>
</li>
<li><p><strong>Docker no WSL2</strong>: se você está mais interessado em aprender os comandos docker, não precisa de uma interface gráfica, precisa do docker somente na sua distribuição linux e está mais interessado em performance, essa opção pode ser a mais adequada para você.</p>
</li>
</ul>
<hr />
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Eu prefiro a instalação do Docker diretamente no meu WSL2 ao invés do aplicativo Docker Desktop, como mencionei, essa instalação é em uma distribuição nativa do linux, então se você optou por essa abordagem também, continue para o próximo passo abaixo.</div>
</div>

<hr />
<h2 id="heading-instalacao-ou-atualizacao">Instalação ou Atualização</h2>
<p>1- Abra seu aplicativo de terminal preferido:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713210858132/f5828bdb-5d69-466b-afb6-876a8f07a122.png" alt class="image--center mx-auto" /></p>
<p>2- Insira o comando:</p>
<blockquote>
<p>Embora o site oficial do Docker mencione um mínimo de 4GB de RAM necessários, na maioria das vezes 2 GB de RAM poderá ser o suficiente para muitas cargas de trabalhos, esse script funcionou bem para:</p>
<ul>
<li><p><code>Mínimo de 512 MB RAM</code></p>
</li>
<li><p><code>Mínimo de 2vCPU (core)</code></p>
</li>
<li><p><code>Mínimo de 20 GB SSD</code></p>
</li>
</ul>
</blockquote>
<pre><code class="lang-bash"><span class="hljs-comment"># Install latest Docker Version</span>
curl -fsSL https://get.docker.com/ | sh &amp;&amp; \

<span class="hljs-comment"># Get latest Docker Compose version</span>
COMPOSE_VERSION=$(curl -s https://api.github.com/repos/docker/compose/releases/latest \
| grep <span class="hljs-string">'tag_name'</span> \
| cut -d<span class="hljs-string">'"'</span> -f4) &amp;&amp; \

<span class="hljs-comment"># Download latest Docker Compose</span>
sudo curl \
-L <span class="hljs-string">"https://github.com/docker/compose/releases/download/<span class="hljs-variable">$COMPOSE_VERSION</span>/docker-compose-<span class="hljs-subst">$(uname -s)</span>-<span class="hljs-subst">$(uname -m)</span>"</span> \
-o /usr/<span class="hljs-built_in">local</span>/bin/docker-compose &amp;&amp; \

<span class="hljs-comment"># Make Docker Compose executable</span>
sudo chmod +x /usr/<span class="hljs-built_in">local</span>/bin/docker-compose &amp;&amp; \

<span class="hljs-comment"># Add current user to "docker" group</span>
sudo usermod -aG docker <span class="hljs-variable">$USER</span> &amp;&amp; \

<span class="hljs-comment"># Show Docker and Docker Compose versions</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"============================================"</span> &amp;&amp; \
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Docker and Docker Compose Versions Installed"</span> &amp;&amp; \
docker --version &amp;&amp; \
docker-compose --version &amp;&amp; \
<span class="hljs-built_in">echo</span> <span class="hljs-string">"============================================"</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713211366840/eb966b5e-d274-47e6-995d-e6e41f73a884.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Você deve fechar e abrir novamente seu terminal para que as permissões sejam atualizadas e os comandos docker sem sudo funcionarem.</div>
</div>

<hr />
<p>Agora todos os comandos <code>Docker</code> já estarão disponíveis:</p>
<pre><code class="lang-bash">docker --<span class="hljs-built_in">help</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713370799756/a93abdee-1f14-4a89-b913-5415af7ab2c2.png" alt class="image--center mx-auto" /></p>
<p>Também estará disponível os comandos <code>Docker Swarm</code>:</p>
<pre><code class="lang-bash">docker swarm --<span class="hljs-built_in">help</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713371011523/2f5032dd-51ad-4f60-8538-f97a897ffba1.png" alt class="image--center mx-auto" /></p>
<p>Também os comandos <code>Docker Stack</code>:</p>
<pre><code class="lang-bash">docker stack --<span class="hljs-built_in">help</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713371086562/93bcd0d8-cfbf-4303-90b1-7379f86a1b47.png" alt class="image--center mx-auto" /></p>
<p>E por fim os comandos do <code>Docker-Compose</code>:</p>
<pre><code class="lang-bash">docker-compose --<span class="hljs-built_in">help</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713371234772/7e9fcdf3-c21c-4d54-94c4-da06c75c1344.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Pronto! Isso é o suficiente para a instalação ou atualização das versões mais atuais do Docker e Docker Compose!</div>
</div>

<hr />
<h2 id="heading-explicando-o-comando">Explicando o Comando</h2>
<p>Se você estiver curioso em descobrir o que cada etapa do comando está fazendo, para um melhor entendimento, vou quebrar o comando acima em várias partes e ir explicando passo a passo:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Install latest Docker Version</span>
curl -fsSL https://get.docker.com/ | sh &amp;&amp; \
</code></pre>
<p>Este comando utiliza o <code>curl</code> para baixar o script de instalação oficial do Docker a partir da URL fornecida. O pipe <code>|</code> envia o conteúdo baixado pelo <code>curl</code> para o comando <code>sh</code>, que executa o script.</p>
<p>Em outras palavras, estamos acessando o script oficial disponível em:</p>
<ul>
<li>👉 <a target="_blank" href="https://get.docker.com/">https://get.docker.com</a></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713211900036/a6dca02f-0f3a-4b11-a033-21a31b08fcf1.png" alt class="image--center mx-auto" /></p>
<p>E executando com o <code>bash</code> este script, que então irá verificar a arquitetura do seu dispositivo se é <code>x86_64</code> ou <code>arm64</code> por exemplo, também irá verificar a sua distribuição se é <code>ubuntu</code>, <code>debian</code>, <code>centos</code>, etc. E fará a instalação ou atualização.</p>
<hr />
<pre><code class="lang-bash"><span class="hljs-comment"># Get latest Docker Compose version</span>
COMPOSE_VERSION=$(curl -s https://api.github.com/repos/docker/compose/releases/latest \
| grep <span class="hljs-string">'tag_name'</span> \
| cut -d<span class="hljs-string">'"'</span> -f4) &amp;&amp; \
</code></pre>
<p>Obtém a versão mais recente do Docker Compose disponível no repositório do GitHub, analisando a resposta para obter a versão mais recente e armazenando na variável de ambiente <code>COMPOSE_VERSION</code>.</p>
<hr />
<pre><code class="lang-bash"><span class="hljs-comment"># Download latest Docker Compose</span>
sudo curl \
-L <span class="hljs-string">"https://github.com/docker/compose/releases/download/<span class="hljs-variable">$COMPOSE_VERSION</span>/docker-compose-<span class="hljs-subst">$(uname -s)</span>-<span class="hljs-subst">$(uname -m)</span>"</span> \
-o /usr/<span class="hljs-built_in">local</span>/bin/docker-compose &amp;&amp; \
</code></pre>
<p>Baixa a versão mais recente do Docker Compose e salva no diretório <code>/usr/local/bin/</code></p>
<hr />
<pre><code class="lang-bash"><span class="hljs-comment"># Make Docker Compose executable</span>
sudo chmod +x /usr/<span class="hljs-built_in">local</span>/bin/docker-compose &amp;&amp; \
</code></pre>
<p>Torna o arquivo <code>docker-compose</code> baixado executável.</p>
<hr />
<pre><code class="lang-bash"><span class="hljs-comment"># Add current user to "docker" group</span>
sudo usermod -aG docker <span class="hljs-variable">$USER</span> &amp;&amp; \
</code></pre>
<p>Adiciona o usuário atual ao grupo <code>docker</code> para poder executar comandos Docker sem usar <code>sudo</code> .</p>
<hr />
<pre><code class="lang-bash"><span class="hljs-comment"># Show Docker and Docker Compose versions</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"============================================"</span> &amp;&amp; \
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Docker and Docker Compose Versions Installed"</span> &amp;&amp; \
docker --version &amp;&amp; \
docker-compose --version &amp;&amp; \
<span class="hljs-built_in">echo</span> <span class="hljs-string">"============================================"</span>
</code></pre>
<p>Mostra as versões do Docker e Docker Compose instaladas ou atualizadas.</p>
<hr />
<h2 id="heading-bonus-para-quem-usar-wsl2">Bônus - Para quem usar WSL2</h2>
<p>Você pode configurar o docker para iniciar automaticamente junto com seu WSL2:</p>
<p>1- Crie o arquivo em <code>/etc/wsl.conf</code></p>
<p>2- Insira esse conteúdo com seu editor preferido:</p>
<pre><code class="lang-plaintext">[boot]
systemd=true
[boot] command = service docker start
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713212743896/2d932b7a-2b1f-454d-ae91-aea4890aee8f.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-conclusao">Conclusão</h2>
<p>Neste artigo, compartilhei como tenho feito a instalação ou atualização do Docker e Docker Compose, também demonstrei para usuários Windows duas opções de instalação, ainda demonstrei qual poderia ser a opção mais adequada e informei a que eu uso e os motivos para isso.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Espero que essas informações tenham sido úteis para você!</div>
</div>]]></content:encoded></item><item><title><![CDATA[Como configurar a Autenticação entre Bitbucket e AWS com OpenID Connect (OIDC)]]></title><description><![CDATA[ℹ
Este é um artigo completo e extenso, mostrarei um passo a passo de um exemplo prático. Se preferir você pode pular as informações iniciais e ir diretamente para a prática, embora recomendo a leitura completa para obter um melhor contexto e uma melh...]]></description><link>https://simplescloud.com.br/como-configurar-a-autenticacao-entre-bitbucket-e-aws-com-openid-connect-oidc</link><guid isPermaLink="true">https://simplescloud.com.br/como-configurar-a-autenticacao-entre-bitbucket-e-aws-com-openid-connect-oidc</guid><category><![CDATA[bitbucket-openid-connect-aws]]></category><category><![CDATA[bitbucket-oidc-aws]]></category><category><![CDATA[Bitbucket]]></category><category><![CDATA[AWS]]></category><dc:creator><![CDATA[SimplesCloud]]></dc:creator><pubDate>Tue, 30 Jan 2024 01:00:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1706556588742/48e9bfee-e5bd-4983-acd2-3f4d0b50284c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Este é um artigo completo e extenso, mostrarei um passo a passo de um exemplo prático. Se preferir você pode pular as informações iniciais e ir diretamente para a prática, embora recomendo a leitura completa para obter um melhor contexto e uma melhor compreensão.</div>
</div>

<hr />
<h2 id="heading-introducao">Introdução</h2>
<p>No cenário atual de desenvolvimento de software, a integração entre diferentes plataformas é crucial para promover eficiência e colaboração. Nesse contexto, o <code>OpenID Connect (OIDC)</code> emerge como um protocolo de autenticação poderoso e amplamente utilizado, desempenhando um papel fundamental na segurança e na interoperabilidade entre sistemas.</p>
<p>A automatização de todos os processos de <code>test</code>, <code>build</code> e <code>deploy</code> garante que os produtos que são desenvolvidos sejam produzidos mais rapidamente, com melhor qualidade e menos erros. Há várias ferramentas disponíveis para automatizar esses processos manuais. Mas quando você automatiza tudo, não se esqueça de uma coisa: <strong>Segurança!</strong></p>
<p>Então você criou um app incrível e chegou a hora de fazer o deploy para AWS, você configura um pipeline de CI/CD para automatizar muitas coisas, nesse momento você percebe que precisa realizar a autenticação do seu pipeline com sua conta AWS e começa a se preocupar com a segurança em torno disso. Se você chegou até aqui procurando uma solução para essa sua preocupação e necessidade, eu também já a tive e compartilho como cobri esse tema e o que tem funcionado para mim.</p>
<hr />
<h2 id="heading-o-que-e-openid-connect-oidc">O que é OpenID Connect (OIDC)</h2>
<p>O OIDC é uma extensão do OAuth 2.0, focado na autenticação de identidades. Sua principal finalidade é permitir que aplicativos e serviços validem a identidade de usuários de maneira segura e eficiente. Ao fornecer uma camada adicional sobre o OAuth 2.0, o OIDC adiciona recursos específicos para autenticação, possibilitando a obtenção de informações sobre o usuário autenticado de maneira padronizada.</p>
<p>O funcionamento do OIDC baseia-se em um fluxo de comunicação seguro entre partes envolvidas, conhecidas como provedor de identidade (IdP) e cliente. No contexto do nosso artigo, o Bitbucket atuará como cliente, enquanto a AWS será configurada como o provedor de identidade.</p>
<p>O processo começa com o cliente (Bitbucket) solicitando a autenticação ao provedor de identidade (AWS). O provedor de identidade (AWS), por sua vez, autentica o usuário, retornando um token de identificação ao cliente (Bitbucket), que pode ser usado para acessar informações sobre o usuário autenticado.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706553053724/f70b641a-cf2a-4a7d-ab1d-515fece8f918.png" alt class="image--center mx-auto" /></p>
<p>Ao configurar o OpenID Connect (OIDC) entre o Bitbucket e a AWS, estaremos estabelecendo uma ponte segura para a autenticação de usuários, fortalecendo a segurança e simplificando a gestão de identidades em ambientes interconectados.</p>
<p>Nos próximos passos deste artigo, exploraremos detalhadamente como realizar essa configuração, garantindo uma integração eficiente e confiável entre essas duas poderosas plataformas.</p>
<hr />
<h2 id="heading-escopo-do-tutorial">Escopo do Tutorial</h2>
<p>Antes de começarmos, vamos definir o escopo das ferramentas mencionadas neste artigo. Em primeiro lugar, devemos considerar:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">O conceito do OpenID Connect (OIDC) é sempre o mesmo para diferentes ferramentas, mas ela pode ter configurações diferentes para ferramentas como GitLab, Azure Pipelines, GitHub, etc. <strong>Este artigo tem o escopo de explicar somente a configuração do OIDC entre o Bitbucket e AWS.</strong></div>
</div>

<ul>
<li><p><strong>Bitbucket da Atlassian:</strong> uma potente solução Git que agiliza os fluxos de trabalho de implantação e reforça as medidas de segurança focadas em equipes de desenvolvimento profissionais. Porém, neste caso específico, estamos mais interessados ​​no Bitbucket Pipelines.</p>
</li>
<li><p><strong>Bitbucket Pipelines:</strong> é uma solução de integração contínua e entrega contínua (CI/CD) fornecida pela plataforma Bitbucket. Ele permite que os desenvolvedores automatizem os processos de teste, build e deploy de seus códigos diretamente com o repositório Bitbucket. Com a integração Bitbucket CI/CD, você pode implantar perfeitamente sua infraestrutura e aplicativos na nuvem AWS.</p>
</li>
</ul>
<hr />
<h2 id="heading-visao-geral-e-vantagens">Visão Geral e Vantagens</h2>
<p>Se quisermos fazer o deploy de um aplicativo na AWS, ela nos permite criar credenciais de segurança (chaves de acesso programáticas) mais conhecidas como <code>Access Key</code> e <code>Secret Access Key</code> e passá-las para o pipeline de implantação por meio de variáveis ​​de ambiente, por exemplo:</p>
<p><img src="https://intelligentpathways.com.au/wp-content/uploads/2022/01/pipelines_secrets.png" alt="Deploying to AWS Using Bitbucket Pipelines - Intelligent Pathways" /></p>
<p>Este tipo de processo de implantação é muito mais comum do que deveria, mas existem vários potenciais problemas nesta abordagem, destacando:</p>
<ul>
<li><p>Quando há erros de script, há risco de vazamento das chaves de acesso no código</p>
</li>
<li><p>Quando as chaves de acesso mudam ou precisam ser alternados, você deve atualizá-los manualmente no Bitbucket</p>
</li>
<li><p>Você deve garantir que eles não foram expostos acidentalmente</p>
</li>
<li><p>Você deve mantê-los com segurança</p>
</li>
<li><p>Pode ser um problema de conformidade em setores altamente regulamentados</p>
</li>
</ul>
<p>Nesses casos, o OpenID Connect (OIDC) vem em nossa ajuda. Embora a maioria dos desenvolvedores que enfrentam a necessidade de implantar na AWS com Bitbucket usem a chave de acesso secreta, o OIDC pode nos ajudar a evitar o uso de chaves e simplificar significativamente implantações futuras.</p>
<p>Além disso, existem vários motivos pelos quais o uso do OIDC é melhor para os desenvolvedores em comparação ao uso de chaves de acesso:</p>
<ul>
<li><p><strong>Mais seguro:</strong> se suas chaves secretas vazarem, usuários não autorizados poderão usar suas chaves de acesso para obter acesso aos seus recursos da AWS. OpenID depende de seu <code>Role ARN</code> da AWS que, mesmo se vazado, não dá acesso aos seus recursos da AWS, as credenciais também são temporárias e expiram limitando o uso indesejado.</p>
</li>
<li><p><strong>Mais fácil de gerenciar:</strong> para gerenciar o risco de segurança, quando os administradores de nuvem geram chaves secretas para os usuários, eles concedem permissões granulares com base nas necessidades do usuário. Isso significa ter que criar muitos pares de chaves de usuário. As permissões baseadas em funções no OpenID ainda se beneficiam de permissões granulares, mas são menos restritivas. Os administradores têm menos níveis de permissão para gerenciar.</p>
</li>
<li><p><strong>Não são necessárias atualizações:</strong> quando você precisa alterar sua chave secreta ou quando a AWS desabilita uma chave devido à inatividade, você não precisa atualizar suas chaves em seus aplicativos ou no Bitbucket porque o OpenID não depende de chaves de acesso.</p>
</li>
</ul>
<hr />
<h2 id="heading-pre-requisitos">Pré-Requisitos</h2>
<p>Para usar o OpenID Connect (OIDC) em Bitbucket Pipelines relacionados à AWS, você precisa configurar o Bitbucket Pipelines como um provedor de identidade da web (IdP) na AWS e criar uma função AWS Identity and Access Management (IAM).</p>
<p>Então como premissa você precisa ter uma conta do Bitbucket e outra da AWS, como nosso exemplo prático será um site estático com domínio personalizado, assumimos como premissa também que você já tenha seu domínio no Route 53 da AWS, pois não abordaremos essa configuração para não deixar o artigo mais extenso do que já é.</p>
<hr />
<h2 id="heading-tutorial">Tutorial</h2>
<h3 id="heading-cenario">Cenário</h3>
<p>Para demonstrar melhor todas as configurações, vamos criar um site estático no Bucket S3 com domínio personalizado, configurar o OIDC entre o repositório do Bitbucket e AWS e realizar um deploy automático alterando o número da versão da página deste site.</p>
<hr />
<h3 id="heading-etapa-1-criando-o-bucket-s3">Etapa 1 - Criando o Bucket S3</h3>
<p>1- Acesse o console <strong>AWS → S3 → Create Bucket</strong></p>
<p>2-</p>
<ul>
<li><p>Escolha a região</p>
</li>
<li><p>Selecione a opção <strong>General Purpose</strong></p>
</li>
<li><p>Defina um nome (no nosso exemplo o nome é:</p>
<p>  <code>tutorial-bitbucket-oidc-aws.simplescloud.io</code></p>
</li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">O importante aqui é o nome do seu bucket S3 ser um domínio totalmente qualificado <code>(FQDN)</code>, por exemplo se seu domínio é <code>example.com</code> - crie seu bucket como <code>mytutorial.example.com</code> ao invés de somente <code>mytutorial</code></div>
</div>

<ul>
<li><p>Desabilite o ACLs</p>
</li>
<li><p>Desabilite o bloqueio público</p>
</li>
<li><p>Desabilite o versionamento</p>
</li>
<li><p>Deixe todas as outras opções padrões</p>
</li>
<li><p>Clique em criar seu bucket S3</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706535449930/df756d6f-6190-4d07-80e7-857e90c71761.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706535472137/b6cdd00e-a43e-4c7d-a9fd-6230c888070f.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706535567601/ff2bc752-c273-4b8c-b249-89e78ab7d6ca.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706535578252/f2aa0fe3-702c-40ec-ae4e-4bede50e4579.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-etapa-2-fazendo-upload-do-indexhtml-no-bucket-s3">Etapa 2 - Fazendo Upload do index.html no Bucket S3</h3>
<p>1- Em seu computador, abra seu editor de texto predileto e crie um arquivo chamado <code>index.html</code>, cole este conteúdo e salve o arquivo:</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Tutorial OpenID Connect (OIDC)<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.googleapis.com/css2?family=Nunito:wght@400;700&amp;display=swap"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
        <span class="hljs-selector-tag">body</span> {
            <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Nunito'</span>, sans-serif;
            <span class="hljs-attribute">background</span>: <span class="hljs-built_in">linear-gradient</span>(<span class="hljs-number">45deg</span>, #<span class="hljs-number">3498</span>db, #<span class="hljs-number">2</span>c3e50);
            <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
            <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
            <span class="hljs-attribute">display</span>: flex;
            <span class="hljs-attribute">flex-direction</span>: column;
            <span class="hljs-attribute">align-items</span>: center;
            <span class="hljs-attribute">justify-content</span>: center;
            <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
            <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
        }

        <span class="hljs-selector-tag">h1</span>, <span class="hljs-selector-tag">h2</span> {
            <span class="hljs-attribute">text-align</span>: center;
            <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
            <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
        }

        <span class="hljs-selector-tag">h1</span> {
            <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2.5rem</span>;
            <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">20px</span>;
        }

        <span class="hljs-selector-tag">h2</span> {
            <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.8rem</span>;
            <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">400</span>;
        }
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Tutorial OpenID Connect (OIDC)<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Between Bitbucket and AWS<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Version 1<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>2- Agora arraste para o <strong>bucket S3</strong> ou clique no botão <strong>Upload</strong>, ao final você deve ver uma tela parecida com:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706535802730/05662f62-aa78-47a7-8d28-74b24a54cda2.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-etapa-3-habilitando-o-site-estatico-no-bucket-s3">Etapa 3 - Habilitando o Site Estático no Bucket S3</h3>
<p>1- No console <strong>AWS</strong> → <strong>Bucket S3</strong> → acesse o bucket recém criado e navegue até a aba <strong>Properties</strong> → role a página para baixo até encontrar a opção <strong>Static Website Hosting</strong> → clique em <strong>Editar</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706536120297/3989bc4f-9d3c-43db-9991-0923d084e8ac.png" alt class="image--center mx-auto" /></p>
<p>2-</p>
<ul>
<li><p>Clique em <strong>Enable</strong></p>
</li>
<li><p>Escolha a opção <strong>Host a static website</strong></p>
</li>
<li><p>Defina o nome do documento como <strong>index.html</strong></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706536185621/a154ec70-c355-4b1e-9ae9-0f41f823d79a.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-etapa-4-tornando-o-site-publico">Etapa 4 - Tornando o Site Público</h3>
<p>1- Agora alterne para a aba <strong>Permissions</strong> → em <strong>Bucket Policy</strong> clique no botão <strong>Edit</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706536361330/85b7bec1-e0b2-41f7-82e5-39172b813681.png" alt class="image--center mx-auto" /></p>
<p>2- Insira a política abaixo e salve</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se de alterar <code>&lt;your-bucket-name&gt;</code> pelo nome real do bucket S3 que você criou.</div>
</div>

<pre><code class="lang-json">{
    <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
    <span class="hljs-attr">"Statement"</span>: [
        {
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Principal"</span>: <span class="hljs-string">"*"</span>,
            <span class="hljs-attr">"Action"</span>: <span class="hljs-string">"s3:GetObject"</span>,
            <span class="hljs-attr">"Resource"</span>: <span class="hljs-string">"arn:aws:s3:::&lt;your-bucket-name&gt;/*"</span>
        }
    ]
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706536492152/1d788e56-8982-4209-ae37-94c05aa9704e.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-etapa-5-criando-o-registro-dns-no-route-53">Etapa 5 - Criando o Registro DNS no Route 53</h3>
<p>1- Acesse o console <strong>AWS</strong> → <strong>Route 53</strong> → <strong>Hosted Zone</strong> → Crie um novo registro DNS:</p>
<ul>
<li><p>Nome <strong>igual</strong> ao do bucket S3</p>
</li>
<li><p>Tipo <strong>A</strong></p>
</li>
<li><p><strong>Alias</strong> habilitado</p>
</li>
<li><p>Selecione o bucket S3</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706536646495/6db4acb1-ace3-418d-b737-a401fed6fae7.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-etapa-6-verificando-o-site-funcionando">Etapa 6 - Verificando o Site Funcionando</h3>
<p>1- Abra seu navegador → acesse o domínio personalizado que criou, em nosso exemplo isso é <code>tutorial-bitbucket-oidc-aws.simplescloud.io</code>, mas obviamente lembre-se de trocar para o valor real que você utilizou</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706536783475/2df5caf8-3c10-4e34-834a-7f62a6a6b4ea.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-etapa-7-criando-um-identity-provider-idp-na-aws">Etapa 7 - Criando um Identity Provider (IdP) na AWS</h3>
<p>1- Acesse sua conta <strong>Bitbucket</strong> → <strong>configurações do repositório</strong> → <strong>OpenID Connect</strong> → copie e anote:</p>
<ul>
<li><p>Identity Provider URL</p>
</li>
<li><p>Audience</p>
</li>
<li><p>Repository UUID</p>
</li>
</ul>
<p>Que nós vamos precisar dessas informações mais para frente.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706537057617/3c1695e8-7e04-4344-bbff-7a41922ea98c.png" alt class="image--center mx-auto" /></p>
<p>2- Agora acesse o console <strong>AWS</strong> → <strong>IAM</strong> → <strong>Identity Providers</strong> → <strong>Create Identity Provider</strong>:</p>
<ul>
<li><p>Selecione a opção <strong>OpenID Connect</strong></p>
</li>
<li><p>No campo <strong>Provider URL</strong> cole o que você copiou do campo <strong>Identity Provider URL</strong> do Bitbucket</p>
</li>
<li><p>No campo <strong>Audience</strong> cole o que você copiou do campo <strong>Audience</strong> do Bitbucket</p>
</li>
<li><p>Clique no botão <strong>Get thumbprint</strong></p>
</li>
<li><p>Por fim, clique no botão <strong>Add Provider</strong></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706537232376/b487ce09-fa51-491f-b2d1-768af4093cd2.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-etapa-8-criando-politica-de-acesso-para-o-bucket-s3">Etapa 8 - Criando Política de Acesso para o Bucket S3</h3>
<p>1- Acesse o console <strong>AWS</strong> → <strong>IAM</strong> → <strong>Policies</strong> → <strong>Create Policy</strong> → cole o conteúdo</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se de alterar <code>&lt;your-bucket-name&gt;</code> para o nome real do bucket S3 que você criou.</div>
</div>

<pre><code class="lang-json">{
    <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
    <span class="hljs-attr">"Statement"</span>: [
        {
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Action"</span>: [
                <span class="hljs-string">"s3:GetBucketLocation"</span>,
                <span class="hljs-string">"s3:ListAllMyBuckets"</span>
            ],
            <span class="hljs-attr">"Resource"</span>: <span class="hljs-string">"arn:aws:s3:::*"</span>
        },
        {
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Action"</span>: <span class="hljs-string">"s3:*"</span>,
            <span class="hljs-attr">"Resource"</span>: [
                <span class="hljs-string">"arn:aws:s3:::&lt;your-bucket-name&gt;"</span>,
                <span class="hljs-string">"arn:aws:s3:::&lt;your-bucket-name&gt;/*"</span>
            ]
        }
    ]
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706537514807/242e8407-3ed5-4e23-9d27-9386b12c00e1.png" alt class="image--center mx-auto" /></p>
<p>2- Defina um nome e descrição de sua preferência, por exemplo:</p>
<ul>
<li><p><strong>Nome:</strong><code>s3-bucket-tutorial-bitbucket-oidc-aws.simplescloud.io-policy</code></p>
</li>
<li><p><strong>Descrição:</strong><code>Policy with permissions required to access the bucket named tutorial-bitbucket-oidc-aws.simplescloud.io</code></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706537621345/297a4773-12c1-47b1-a495-e67d93a6cf3a.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-etapa-9-criando-politica-de-conexao">Etapa 9 - Criando Política de Conexão</h3>
<p>Repita os passos da Etapa 8, mas agora defina um outro nome e descrição de sua preferência, por exemplo:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
    <span class="hljs-attr">"Statement"</span>: [
        {
            <span class="hljs-attr">"Sid"</span>: <span class="hljs-string">"VisualEditor0"</span>,
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Action"</span>: [
                <span class="hljs-string">"sts:AssumeRole"</span>,
                <span class="hljs-string">"sts:GetCallerIdentity"</span>
            ],
            <span class="hljs-attr">"Resource"</span>: <span class="hljs-string">"*"</span>
        }
    ]
}
</code></pre>
<ul>
<li><p><strong>Nome:</strong><code>oidc_bitbucket_policy</code></p>
</li>
<li><p><strong>Descrição:</strong><code>Policy that allows OpenID Connect between Atlassian Bitbucket and AWS</code></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706537748045/4a2a338f-298c-442c-a087-9dbef0fb9680.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-etapa-10-criando-uma-role-de-permissao">Etapa 10 - Criando uma Role de Permissão</h3>
<p>1- Acesse o console <strong>AWS</strong> → <strong>IAM</strong> → <strong>Role</strong> → <strong>Create Role</strong></p>
<ul>
<li><p>Selecione a opção <strong>Web Identity</strong></p>
</li>
<li><p>Selecione em <strong>Identity Provider</strong> a identidade de provedor que criamos anteriormente</p>
</li>
<li><p>Selecione em <strong>Audience</strong> a audiência de provedor que criamos anteriormente</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706538120940/ff1d82f9-5208-4288-a4f9-0c3c2afd7b01.png" alt class="image--center mx-auto" /></p>
<p>2- Defina um nome e descrição de sua preferência, por exemplo:</p>
<ul>
<li><p><strong>Nome:</strong><code>deploy-tutorial-bitbucket-oidc-aws.simplescloud.io-role-prod</code></p>
</li>
<li><p><strong>Descrição:</strong><code>Role with necessary permissions to deploy to the bucket called tutorial-bitbucket-oidc-aws.simplescloud.io in the production environment</code></p>
</li>
<li><p>Observe a estrutura da política de confiança, nós vamos altera-la em breve, por enquanto apenas clique em <strong>Next</strong></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706538286889/263c9bcc-c530-4cf0-8cbc-ea5f4e91670e.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706538307047/d383faa5-eab5-4734-b3c7-b88e6593fe0f.png" alt class="image--center mx-auto" /></p>
<p>3- Depois de criado → selecione a aba <strong>Trust Relationships</strong> → <strong>Edit</strong> → e altere para a política abaixo:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se de alterar <code>&lt;your-account-id&gt;</code> pelo número de ID real da sua conta AWS (você pode obter ela clicando no seu nome no menu superior direito), também lembre-se de alterar <code>&lt;your-bitbucket-workspace&gt;</code> pelo nome real do seu workspace do Bitbucket e por fim lembre-se de alterar <code>&lt;your-bitbucket-repo-uuid&gt;</code> pelo código que você copiou em uma das etapas anteriores.</div>
</div>

<pre><code class="lang-json">{
    <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
    <span class="hljs-attr">"Statement"</span>: [
        {
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Principal"</span>: {
                <span class="hljs-attr">"Federated"</span>: <span class="hljs-string">"arn:aws:iam::&lt;your-account-id&gt;:oidc-provider/api.bitbucket.org/2.0/workspaces/&lt;your-bitbucket-workspace&gt;/pipelines-config/identity/oidc"</span>
            },
            <span class="hljs-attr">"Action"</span>: <span class="hljs-string">"sts:AssumeRoleWithWebIdentity"</span>,
            <span class="hljs-attr">"Condition"</span>: {
                <span class="hljs-attr">"StringLike"</span>: {
                    <span class="hljs-attr">"api.bitbucket.org/2.0/workspaces/&lt;your-bitbucket-workspace&gt;/pipelines-config/identity/oidc:sub"</span>: <span class="hljs-string">"{&lt;your-bitbucket-repo-uuid&gt;}:*"</span>
                }
            }
        }
    ]
}
</code></pre>
<p>É uma mudança sútil entre a política padrão para essa que editamos, em resumo as alterações são:</p>
<ul>
<li><p>Mudamos de <code>StringEquals</code> para <code>StringLike</code></p>
</li>
<li><p>Mudamos <code>aud</code> para <code>sub</code></p>
</li>
<li><p>Adicionamos um <code>wildcard (*)</code> ao final do endpoint do repositório</p>
</li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text"><strong>Esse passo é muito importante, pois mudamos a política de relação de confiança limitando o acesso para apenas este repositório como uma boa prática de segurança. Em resumo o OIDC irá gerar tokens temporários e de qualquer forma ele poderá se conectar somente para este repositório tornando um nível maior de segurança.</strong></div>
</div>

<p>4- Agora sua Role de Permissão deve estar devidamente criada e configurada, ela deve se parecer com isso, e não se esqueça de copiar o <strong>ARN</strong>, pois usaremos essa informação mais para frente</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706539231794/3b9ec54b-4d85-4dbb-a1d4-c0f7617c47e8.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-etapa-11-configurando-seu-computador">Etapa 11 - Configurando seu Computador</h3>
<p>1- Em seu computador crie um pasta de sua preferência, por exemplo estou usando:</p>
<p><code>~/home/projects/bitbucket-openid-connect-aws</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706541022175/9a6c0f71-ea12-41d6-838c-917c11568d48.png" alt class="image--center mx-auto" /></p>
<p>2- Crie novamente o arquivo <code>index.html</code> das etapas iniciais dentro dessa pasta</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706540112469/c14372d4-20b4-475b-97e1-fc1ce90e52be.png" alt class="image--center mx-auto" /></p>
<p>3- Agora crie um outro arquivo chamado <code>bitbucket-pipelines.yml</code> → cole este conteúdo:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Não se preocupe ainda se o arquivo abaixo se parecer confuso ou até mesmo se você não entendê-lo. O objetivo deste artigo não é explicar como criar um Pipeline em si, é apenas usar um Pipeline para demonstrar o uso do OIDC. Então novamente não se preocupe, a única coisa que você precisa olhar com atenção é a parte <code>oidc: true</code> que está habilitando o uso do OpenID Connect.</div>
</div>

<pre><code class="lang-yaml"><span class="hljs-comment"># Deploy to S3 Bucket</span>

<span class="hljs-attr">definitions:</span>

  <span class="hljs-attr">build_step:</span> <span class="hljs-meta">&amp;build_step</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">Artifact</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">atlassian/default-image:4</span>
    <span class="hljs-attr">script:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">mkdir</span> <span class="hljs-string">artifact</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">cp</span> <span class="hljs-string">index.html</span> <span class="hljs-string">artifact/</span>
    <span class="hljs-attr">artifacts:</span>
         <span class="hljs-bullet">-</span> <span class="hljs-string">artifact/**</span>

  <span class="hljs-attr">deploy_step:</span> <span class="hljs-meta">&amp;deploy_step</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">AWS</span> <span class="hljs-string">S3</span>
    <span class="hljs-attr">oidc:</span> <span class="hljs-literal">true</span>
    <span class="hljs-attr">script:</span>
      <span class="hljs-comment"># Upload to S3 Bucket   </span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">pipe:</span> <span class="hljs-string">atlassian/aws-s3-deploy:1.6.0</span>
        <span class="hljs-attr">variables:</span>
          <span class="hljs-attr">AWS_OIDC_ROLE_ARN:</span> <span class="hljs-string">$AWS_OIDC_ROLE_ARN</span>
          <span class="hljs-attr">AWS_DEFAULT_REGION:</span> <span class="hljs-string">$AWS_DEFAULT_REGION</span>
          <span class="hljs-attr">S3_BUCKET:</span> <span class="hljs-string">$S3_BUCKET</span>
          <span class="hljs-attr">LOCAL_PATH:</span> <span class="hljs-string">"artifact"</span>
          <span class="hljs-attr">ACL:</span> <span class="hljs-string">"bucket-owner-full-control"</span>
          <span class="hljs-attr">DELETE_FLAG:</span> <span class="hljs-string">"true"</span>

<span class="hljs-attr">pipelines:</span>

  <span class="hljs-attr">branches:</span>

    <span class="hljs-string">feature/*:</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">stage:</span>
         <span class="hljs-attr">name:</span> <span class="hljs-string">Dev</span> 
         <span class="hljs-attr">deployment:</span> <span class="hljs-string">dev</span>
         <span class="hljs-attr">steps:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">step:</span> <span class="hljs-meta">*build_step</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">step:</span> <span class="hljs-meta">*deploy_step</span>

    <span class="hljs-string">bugfix/*:</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">stage:</span>
         <span class="hljs-attr">name:</span> <span class="hljs-string">Dev</span>
         <span class="hljs-attr">deployment:</span> <span class="hljs-string">dev</span>
         <span class="hljs-attr">steps:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">step:</span> <span class="hljs-meta">*build_step</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">step:</span> <span class="hljs-meta">*deploy_step</span>

    <span class="hljs-string">release/*:</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">stage:</span>
         <span class="hljs-attr">name:</span> <span class="hljs-string">Staging</span>
         <span class="hljs-attr">deployment:</span> <span class="hljs-string">staging</span>
         <span class="hljs-attr">steps:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">step:</span> <span class="hljs-meta">*build_step</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">step:</span> <span class="hljs-meta">*deploy_step</span>

    <span class="hljs-comment"># =======================================================</span>
    <span class="hljs-comment"># Write-protected main branch, </span>
    <span class="hljs-comment"># pipeline runs only on merge of a pull request approved</span>
    <span class="hljs-comment"># by specific people</span>
    <span class="hljs-comment"># -------------------------------------------------------</span>
    <span class="hljs-comment"># Branch restrictions</span>
    <span class="hljs-comment"># Write Access: none</span>
    <span class="hljs-comment"># Merge via pull requests: specific people</span>
    <span class="hljs-comment"># =======================================================</span>

    <span class="hljs-comment"># main:</span>
    <span class="hljs-attr">main:</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">stage:</span>
         <span class="hljs-attr">name:</span> <span class="hljs-string">Production</span> 
         <span class="hljs-attr">deployment:</span> <span class="hljs-string">production</span>
         <span class="hljs-attr">steps:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">step:</span> <span class="hljs-meta">*build_step</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">step:</span> <span class="hljs-meta">*deploy_step</span>
</code></pre>
<p>Então ao final, você deve ter uma pasta com dois arquivos:</p>
<ul>
<li><p><code>index.html</code></p>
</li>
<li><p><code>bitbucket-pipelines.yml</code></p>
</li>
</ul>
<p>No meu exemplo, isso se parece com:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706540409931/45b66bcf-b502-4425-9c64-b8556d7d7d26.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-etapa-12-habilitando-o-pipelines-no-bitbucket">Etapa 12 - Habilitando o Pipelines no Bitbucket</h3>
<p>1- Acesse o <strong>Bitbucket</strong> → <strong>Repositório</strong> → <strong>Configurações do Repositório</strong> → <strong>Settings</strong> → <strong>Enable Pipelines</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706540506895/85d8b90d-7a7a-4041-ad80-0b0a3a2bd325.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-etapa-13-criando-variaveis-de-ambiente-no-bitbucket">Etapa 13 - Criando Variáveis de Ambiente no Bitbucket</h3>
<p>1- Acesse o <strong>Bitbucket</strong> → <strong>Repositório</strong> → <strong>Configurações do Repositório</strong> → <strong>Deployments</strong> → crie as seguintes variáveis de ambiente em <code>Production</code>:</p>
<ul>
<li><p><code>AWS_OIDC_ROLE_ARN</code>: cole o ARN da Role que você criou em uma das etapas anteriores. Certifique-se de deixar <strong>Secured</strong> marcado para isso</p>
</li>
<li><p><code>AWS_DEFAULT_REGION</code>: insira a região que seu bucket S3 foi criado, no nosso exemplo foi em Norte da Virgínia, então essa região é <code>us-east-1</code>. Você pode ver todos os nomes das regiões clicando no menu superior direito do console AWS</p>
</li>
<li><p><code>S3_BUCKET</code>: insira o nome do bucket que criou</p>
</li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Atente-se para criar os nomes das variáveis com todas as letras maiúsculas</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">☑</div>
<div data-node-type="callout-text">E observe que em nenhum momento estamos inserindo as chaves de acesso</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706540852124/d7a6db85-8218-4c62-98b1-32cdf0353553.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-etapa-14-fazendo-comandos-git">Etapa 14 - Fazendo comandos Git</h3>
<p>1- Acesse o terminal do seu computador e acesse a pasta que contém os 2 arquivos (<code>index.html</code> e <code>bitbucket-pipelines.yml</code>) das etapas anteriores</p>
<p>2- Inicie o Git nessa pasta</p>
<pre><code class="lang-bash">git init
</code></pre>
<p>3- Configure o git com o email da sua conta Bitbucket:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se de alterar <code>&lt;your-bitbucket-email&gt;</code> para o valor real que você usa.</div>
</div>

<pre><code class="lang-bash">git config user.email <span class="hljs-string">"&lt;your-bitbucket-email&gt;"</span>
</code></pre>
<p>4- Configure o git com o nome de usuário da sua conta Bitbucket:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se de alterar <code>&lt;your-bitbucket-username&gt;</code> para o valor real que você usa.</div>
</div>

<pre><code class="lang-bash">git config user.name <span class="hljs-string">"&lt;your-bitbucket-username&gt;"</span>
</code></pre>
<p>5- Adicione o repositório remoto nessa pasta:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se de alterar <code>&lt;your-bitbucket-git&gt;</code> para o valor real que você usa.</div>
</div>

<pre><code class="lang-bash">git remote add origin git@&lt;your-bitbucket-git&gt;
</code></pre>
<p>6- Crie uma branch chamada local:</p>
<pre><code class="lang-bash">git checkout -b <span class="hljs-built_in">local</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706541414270/97bca142-1495-4400-9bcd-18e9ef82a981.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-etapa-15-verificando-o-funcionamento-do-pipeline">Etapa 15 - Verificando o Funcionamento do Pipeline</h3>
<p>1- Envie um push local para o Bitbucket:</p>
<pre><code class="lang-bash">git add . &amp;&amp; \
git commit -m <span class="hljs-string">"Deploy Pipeline with Open ID Connect on AWS"</span> &amp;&amp; \
git push origin <span class="hljs-built_in">local</span>:main
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706542031066/8c2336d8-0e37-41ee-a35d-2e60c5ac64a9.png" alt class="image--center mx-auto" /></p>
<p>2- Verifique o <strong>Bitbucket</strong> → <strong>Pipelines</strong> e deve ter agora um pipeline em andamento</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706541679131/c7cc3e8a-8719-45a3-9871-7d402adca10b.png" alt class="image--center mx-auto" /></p>
<p>3- Aguarde sua conclusão e abra os detalhes do pipeline</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text"><strong>Esse é o objetivo principal deste artigo, observe que a autenticação entre Bitbucket com a AWS através do OpenID Connect (OIDC) aconteceu com sucesso, lembre-se que nós não definimos em nenhum momento as chaves de acesso, somente o ARN da Role que tem uma relação de confiança e as políticas com permissões necessárias para esse deploy.</strong></div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706541749160/50584d56-9b4a-4cf4-8f07-e94c8af55843.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text"><strong>Pronto! Podemos verificar que o Bitbucket foi capaz de se autenticar na AWS com tokens temporários do OpenID Connect. Novamente reforço para você observar que em nenhum momento definimos as chaves de acesso e não expomos essas informações, aumentando assim a segurança.</strong></div>
</div>

<p>4- Volte para seu editor de texto novamente e altere agora o número da versão de <code>1</code> para <code>2</code> do arquivo <code>index.html</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706541891813/10bea709-0374-49b7-97f6-e3f5fc717304.png" alt class="image--center mx-auto" /></p>
<p>5- Envie um novo push local para o Bitbucket:</p>
<pre><code class="lang-bash">git add . &amp;&amp; \
git commit -m <span class="hljs-string">"Change index.html version"</span> &amp;&amp; \
git push origin <span class="hljs-built_in">local</span>:main
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706541952430/b75f4461-10f1-40b6-a1be-e86061c54530.png" alt class="image--center mx-auto" /></p>
<p>6- Aguarde o Pipeline funcionar novamente, <strong>lembrando que ele está se autenticando com OpenID Connect corretamente entre Bitbucket e AWS</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706542124105/20abe090-105a-456c-a3b9-95df9e2983f8.png" alt class="image--center mx-auto" /></p>
<p>E pronto! Acessando novamente o bucket S3 através do seu domínio customizado, vemos o deploy realizado com sucesso.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706542188981/4eb0044a-f4d0-459a-b916-c171a78b2ab9.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-bonus">Bônus</h2>
<h3 id="heading-restricao-por-codigo-de-repositorio">Restrição por Código de Repositório</h3>
<p>Sim, nós já aplicamos isso no nosso passo a passo quando editamos a política de relação de confiança, mas inseri novamente aqui para reforçar a estrutura para você.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706907725554/5e3f8c8f-3b67-4b07-99a2-d54fe888a04d.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-restricao-por-endereco-ip">Restrição por Endereço IP</h3>
<p>Para aumentar a segurança, podemos restringir um pouco mais o acesso à função permitindo apenas endereços IP do Bitbucket Pipelines e determinados UUIDs de repositório. Desta forma, outros repositórios não podem acessar essa função, exceto os repositórios especificados dos IPs descritos:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706907706355/5c8f2571-8338-4b29-8d43-496a1f19ccbf.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-melhore-suas-permissoes-com-assume-role">Melhore suas permissões com Assume Role</h3>
<p>Vimos até aqui tudo funcionando, mas se observamos com um pouco mais de atenção, vamos notar que as permissões estão anexadas diretamente a Role OIDC que criamos:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706907652639/18762351-489e-48d3-bb08-f5b3dcac7ce5.png" alt class="image--center mx-auto" /></p>
<p>Em nosso exemplo prático isso significa que as políticas:</p>
<ul>
<li><p><code>oidc_bitbucket_policy</code></p>
</li>
<li><p><code>s3-bucket-tutorial-bitbucket-oidc-aws.simplescloud.io-policy</code></p>
</li>
</ul>
<p>Foram anexadas diretamente na role</p>
<ul>
<li><code>deploy-tutorial-bitbucket-oidc-aws.simplescloud.io-role-prod</code></li>
</ul>
<p>O fluxo se parece com:</p>
<ol>
<li><p>Bitbucket se comunica com o provedor de identidade AWS através da Role OIDC</p>
</li>
<li><p>A AWS retorna as credenciais temporárias para o Bitbucket</p>
</li>
<li><p>O Bitbucket Pipelines agora obtém as permissões das políticas anexadas diretamente da Role OIDC e pode acessar seus respectivos recursos</p>
</li>
</ol>
<p>Embora isso já seja uma grande melhoria, ainda há uma boa prática de segurança que seria não anexar as políticas de permissões diretamente em um usuário ou em uma role, mas sim criar uma role para o ambiente de deploy do aplicativo e anexar as permissões nessa role, então quando for de fato fazer essa implantação, acontecerá o seguinte fluxo:</p>
<ol>
<li><p>Bitbucket se comunica com o provedor de identidade AWS através da Role OIDC</p>
</li>
<li><p>AWS retorna as credenciais temporárias para o Bitbucket</p>
</li>
<li><p>O Bitbucket Pipelines agora não tem as permissões para acessar os respectivos recursos, pois nenhuma política foi anexada diretamente nesta Role OIDC</p>
</li>
<li><p>Mas esta Role OIDC tem permissão para assumir uma segunda role de deploy que contém as permissões de acesso aos respectivos recursos</p>
</li>
<li><p>A Role OIDC assume a Role de deploy e obtém as permissões para os respectivos recursos</p>
</li>
</ol>
<p>Desta forma, note que foi criada uma camada adicional de segurança, pois as permissões estão em uma segunda role assumida.</p>
<p>Não vou me estender mais nesse assunto para não tornar o artigo maior do que já é, mas se tiver dúvidas, talvez seja interessante dar uma olhada em nesta explicação aqui:</p>
<ul>
<li>👉 <a target="_blank" href="https://simplescloud.io/aws-cli-instalacao-e-configuracao#heading-assume-role-assumindo-permissoes">Assume Role - Assumindo Permissões</a></li>
</ul>
<p>Com isso compreendido, imagine agora que não estamos mais fazendo um deploy para um site estático no bucket S3 como nosso exemplo prático, mas imagine então que agora queremos fazer um deploy para um container do Lightsail, para aplicar isso então poderíamos ter <strong>por exemplo</strong>:</p>
<ul>
<li><p>Uma Role para o OpenID Connect (OIDC) chamada <code>oidc-bitbucket-role</code></p>
<ul>
<li><p>E anexar a política <code>oidc_bitbucket_policy</code></p>
</li>
<li><pre><code class="lang-json">        {
            <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
            <span class="hljs-attr">"Statement"</span>: [
                {
                    <span class="hljs-attr">"Sid"</span>: <span class="hljs-string">"VisualEditor0"</span>,
                    <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
                    <span class="hljs-attr">"Action"</span>: [
                        <span class="hljs-string">"sts:AssumeRole"</span>,
                        <span class="hljs-string">"sts:GetCallerIdentity"</span>,
                        <span class="hljs-string">"sts:AssumeRoleWithWebIdentity"</span>
                    ],
                    <span class="hljs-attr">"Resource"</span>: <span class="hljs-string">"*"</span>
                }
            ]
        }
</code></pre>
<p>  E lembrando novamente para editar a aba <code>Trust Relationships</code> com seus valores reais da sua conta AWS e Bitbucket</p>
</li>
<li><pre><code class="lang-json">        {
            <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
            <span class="hljs-attr">"Statement"</span>: [
                {
                    <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
                    <span class="hljs-attr">"Principal"</span>: {
                        <span class="hljs-attr">"Federated"</span>: <span class="hljs-string">"arn:aws:iam::&lt;your-account-id&gt;:oidc-provider/api.bitbucket.org/2.0/workspaces/&lt;your-bitbucket-workspace&gt;/pipelines-config/identity/oidc"</span>
                    },
                    <span class="hljs-attr">"Action"</span>: <span class="hljs-string">"sts:AssumeRoleWithWebIdentity"</span>,
                    <span class="hljs-attr">"Condition"</span>: {
                        <span class="hljs-attr">"StringLike"</span>: {
                            <span class="hljs-attr">"api.bitbucket.org/2.0/workspaces/&lt;your-bitbucket-workspace&gt;/pipelines-config/identity/oidc:sub"</span>: <span class="hljs-string">"{&lt;your-bitbucket-repo-uuid&gt;}:*"</span>
                        }
                    }
                }
            ]
        }
</code></pre>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706904995294/2f59dcf7-cb54-46a9-9e4e-9066250e468e.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
</li>
<li><p>Criar uma outra Role para o Deploy chamada <code>myapp-deploy-prod-role</code></p>
<ul>
<li><p>E anexar a política com acesso ao respectivo recurso, por exemplo uma política que permite ações no Lightsail</p>
</li>
<li><p>A dica aqui é editar a aba <code>Trust Relationships</code> permitindo a Role OIDC a assumir essa Role e obter as permissões anexadas a ela, no nosso exemplo permissões para o Lightsail. (Lembre-se de alterar para os valores reais da sua conta AWS)</p>
</li>
<li><pre><code class="lang-json">        {
            <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
            <span class="hljs-attr">"Statement"</span>: [
                {
                    <span class="hljs-attr">"Sid"</span>: <span class="hljs-string">""</span>,
                    <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
                    <span class="hljs-attr">"Principal"</span>: {
                        <span class="hljs-attr">"AWS"</span>: <span class="hljs-string">"arn:aws:iam::&lt;your-account-id&gt;:role/oidc-bitbucket-role"</span>
                    },
                    <span class="hljs-attr">"Action"</span>: <span class="hljs-string">"sts:AssumeRole"</span>
                }
            ]
        }
</code></pre>
</li>
</ul>
</li>
</ul>
<p>Pronto! Agora poderíamos criar um arquivo <code>bitbucket-pipelines.yml</code> que faz deploy com o processo do OpenID Connect e do Assume Role, veja como ficaria isso com esse trecho abaixo:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">definitions:</span>

  <span class="hljs-attr">scripts:</span>

    <span class="hljs-comment"># Commands to install AWS CLI V2</span>
    <span class="hljs-attr">install_aws_cli:</span> <span class="hljs-meta">&amp;install_aws_cli</span>
      <span class="hljs-string">echo</span> <span class="hljs-string">"========== Install AWS CLI V2 =========="</span> <span class="hljs-string">&amp;&amp;</span>
      <span class="hljs-string">curl</span> <span class="hljs-string">"https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip"</span> <span class="hljs-string">-o</span> <span class="hljs-string">"awscliv2.zip"</span> <span class="hljs-string">&amp;&amp;</span>
      <span class="hljs-string">unzip</span> <span class="hljs-string">awscliv2.zip</span> <span class="hljs-string">&amp;&amp;</span>
      <span class="hljs-string">./aws/install</span> <span class="hljs-string">&amp;&amp;</span>
      <span class="hljs-string">aws</span> <span class="hljs-string">--version</span>

    <span class="hljs-comment"># Commands to install the Lightsail plugin in AWS CLI V2</span>
    <span class="hljs-attr">install_lightsail_cli_plugin:</span> <span class="hljs-meta">&amp;install_lightsail_cli_plugin</span>
      <span class="hljs-string">echo</span> <span class="hljs-string">"===== Install AWS Lightsail CLI Plugin ====="</span> <span class="hljs-string">&amp;&amp;</span>
      <span class="hljs-string">curl</span> <span class="hljs-string">https://s3.us-west-2.amazonaws.com/lightsailctl/latest/linux-amd64/lightsailctl</span> <span class="hljs-string">-o</span> <span class="hljs-string">/usr/local/bin/lightsailctl</span> <span class="hljs-string">&amp;&amp;</span>
      <span class="hljs-string">chmod</span> <span class="hljs-string">+x</span> <span class="hljs-string">/usr/local/bin/lightsailctl</span>

    <span class="hljs-comment"># Commands to obtain temporary access keys for the </span>
    <span class="hljs-comment"># aws role that authenticates through OpenID Connect</span>
    <span class="hljs-attr">auth_oidc:</span> <span class="hljs-meta">&amp;auth_oidc</span>
      <span class="hljs-string">echo</span> <span class="hljs-string">"========== Bitbucket OIDC Assume Role =========="</span> <span class="hljs-string">&amp;&amp;</span> 
      <span class="hljs-string">export</span> <span class="hljs-string">$(printf</span> <span class="hljs-string">"AWS_ACCESS_KEY_ID=%s AWS_SECRET_ACCESS_KEY=%s AWS_SESSION_TOKEN=%s"</span> <span class="hljs-string">$(aws</span> <span class="hljs-string">sts</span> <span class="hljs-string">assume-role-with-web-identity</span> <span class="hljs-string">--role-arn</span> <span class="hljs-string">"$AWS_OIDC_ROLE_ARN"</span> <span class="hljs-string">--role-session-name</span> <span class="hljs-string">"Bitbucket-OIDC-$BITBUCKET_DEPLOYMENT_ENVIRONMENT-$BITBUCKET_BUILD_NUMBER"</span> <span class="hljs-string">--web-identity-token</span> <span class="hljs-string">"$BITBUCKET_STEP_OIDC_TOKEN"</span> <span class="hljs-string">--query</span> <span class="hljs-string">'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]'</span> <span class="hljs-string">--output</span> <span class="hljs-string">text))</span>

    <span class="hljs-comment"># Commands to assume another deploy role with </span>
    <span class="hljs-comment"># permissions and obtain your temporary credentials</span>
    <span class="hljs-attr">aws_sts_assume_role:</span> <span class="hljs-meta">&amp;aws_sts_assume_role</span>
      <span class="hljs-string">echo</span> <span class="hljs-string">"========== AWS CLI Assume Role =========="</span> <span class="hljs-string">&amp;&amp;</span>
      <span class="hljs-string">STS_TEMP_CREDS=$(aws</span> <span class="hljs-string">sts</span> <span class="hljs-string">assume-role</span> <span class="hljs-string">--region</span> <span class="hljs-string">"$AWS_REGION"</span> <span class="hljs-string">--role-arn</span> <span class="hljs-string">"$AWS_DEPLOY_ROLE_ARN"</span> <span class="hljs-string">--role-session-name</span> <span class="hljs-string">"Bitbucket-Deploy-$BITBUCKET_DEPLOYMENT_ENVIRONMENT-$BITBUCKET_BUILD_NUMBER"</span><span class="hljs-string">)</span> <span class="hljs-string">&amp;&amp;</span>
      <span class="hljs-string">export</span> <span class="hljs-string">AWS_ACCESS_KEY_ID=$(echo</span> <span class="hljs-string">$STS_TEMP_CREDS</span> <span class="hljs-string">|</span> <span class="hljs-string">jq</span> <span class="hljs-string">-r</span> <span class="hljs-string">.Credentials.AccessKeyId)</span> <span class="hljs-string">&amp;&amp;</span>
      <span class="hljs-string">export</span> <span class="hljs-string">AWS_SECRET_ACCESS_KEY=$(echo</span> <span class="hljs-string">$STS_TEMP_CREDS</span> <span class="hljs-string">|</span> <span class="hljs-string">jq</span> <span class="hljs-string">-r</span> <span class="hljs-string">.Credentials.SecretAccessKey)</span> <span class="hljs-string">&amp;&amp;</span>
      <span class="hljs-string">export</span> <span class="hljs-string">AWS_SESSION_TOKEN=$(echo</span> <span class="hljs-string">$STS_TEMP_CREDS</span> <span class="hljs-string">|</span> <span class="hljs-string">jq</span> <span class="hljs-string">-r</span> <span class="hljs-string">.Credentials.SessionToken)</span> <span class="hljs-string">&amp;&amp;</span>
      <span class="hljs-string">export</span> <span class="hljs-string">AWS_SESSION_EXPIRATION=$(echo</span> <span class="hljs-string">$STS_TEMP_CREDS</span> <span class="hljs-string">|</span> <span class="hljs-string">jq</span> <span class="hljs-string">-r</span> <span class="hljs-string">.Credentials.Expiration)</span> <span class="hljs-string">&amp;&amp;</span>
      <span class="hljs-string">aws</span> <span class="hljs-string">sts</span> <span class="hljs-string">get-caller-identity</span>
</code></pre>
<p>Novamente não se preocupe senão entender esse arquivo ou os comandos, esse não é o foco deste artigo, a única coisa importante para observar é que há duas variáveis de ambiente importantes:</p>
<ul>
<li><p><code>AWS_OIDC_ROLE_ARN</code>: esse é o ARN da Role OpenID Connect (OIDC) que criamos, ou seja em nosso exemplo seria o ARN de <code>oidc-bitbucket-role</code> que não possui nenhuma política anexada além de <code>oidc_bitbucket_policy</code></p>
</li>
<li><p><code>AWS_DEPLOY_ROLE_ARN</code>: esse é o ARN da Role de Deploy que criamos, ou seja em nosso exemplo seria o ARN de <code>myapp-deploy-prod-role</code> e este sim possui a política que permite acesso aos recursos do Lightsail no nosso exemplo</p>
</li>
</ul>
<p>Então o fluxo que está acontecendo é:</p>
<ol>
<li><p>O primeiro trecho <code>auth_oidc</code> está solicitando ao provedor de identidade AWS através do OpenID Connect (OIDC), retornando as credenciais de acesso temporário para o Bitbucket e exportando esses valores em variáveis de ambiente</p>
</li>
<li><p>O segundo trecho <code>aws_sts_assume_role</code> está assumindo a Role <code>myapp-deploy-prod-role</code> e obtendo suas próprias credenciais de acesso temporário</p>
</li>
</ol>
<p>E voltando os olhos para o Bitbucket Pipelines, podemos verificar ele executado com sucesso:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706906979660/b731df57-a9b8-4537-a94e-f2789b743c01.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-conclusao">Conclusão</h2>
<p>Vimos neste artigo um tutorial completo sobre OpenID Connect (OIDC) entre o Bitbucket e AWS, passamos pelas vantagens e demonstramos um exemplo prático.</p>
<p>O exemplo passou por várias etapas, em resumo nós criamos um provedor de identidade (IdP) na AWS para o Bitbucket, depois nós criamos políticas de permissões restritas aos recursos que usamos, então criamos uma role e anexamos essas políticas, ainda em roles editamos a relação de confiança para o número de id do repositório do Bitbucket, em geral essas são as etapas principais e em resumo o OIDC é configurado mesmo entre as etapas 7 a 10, porém todas as outras etapas foram escritas para exemplificar melhor.</p>
<p>O exemplo prático apresentado ainda pode ter muitas melhorias, como por exemplo adicionar uma distribuição Cloudfront para obter um HTTPS e adicionar no pipeline uma invalidação de cache por exemplo, embora os passos envolvam muitas coisas como comandos do git e arquivos de configuração de pipeline, o objetivo não era explicar isso, mas sim sobre o OIDC exclusivamente.</p>
<p>Uma vez que esse conceito e essa lógica foi entendida, o provedor de identidade (IdP) criado, a configuração do OIDC foi feita e a única coisa que você precisa fazer dai em diante é criar políticas e roles novas com a relação de confiança editada para o repositório, <strong>você não precisa criar um provedor de identidade (IdP) para cada projeto.</strong></p>
<p>Por exemplo se você criar um novo repositório e quer fazer o deploy em um container do Fargate, você só precisaria criar uma política com permissões para o ECR e o ECS, por fim criar uma nova role com a relação de confiança editada para o UUID do repositório e com essas permissões anexadas, mas não precisaria criar novamente o provedor de identidade (IdP), pois ela já foi criada e precisa ser criada uma única vez.</p>
<p>Desta forma o Bitbucket poderá acessar sua variável de ambiente com o ARN da role criada e ela poderá obter chaves temporárias de acesso com sucesso com as permissões adequadas anexadas a ela.</p>
<p>Se preferir avançar ainda mais, você viu que é possível criar uma segunda role para o deploy e anexar as permissões nela, fazendo com que a role OIDC assuma as permissões da segunda role.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se de excluir após o tutorial o Bucket S3, o registro DNS no Route 53, as políticas e a role para não obter cobranças indesejadas e manter sua conta AWS limpa e organizada.</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Espero que essas informações tenham sido úteis para você.</div>
</div>]]></content:encoded></item><item><title><![CDATA[Como fazer um acesso SSH no AWS Fargate]]></title><description><![CDATA[Introdução
Se você utiliza o AWS Fargate como carga de trabalho para as suas aplicações, mais cedo ou mais tarde sentirá a necessidade de realizar um acesso SSH nos conteiners do Fargate para solucionar algum problema, fazer alguma depuração ou simpl...]]></description><link>https://simplescloud.com.br/como-fazer-um-acesso-ssh-no-aws-fargate</link><guid isPermaLink="true">https://simplescloud.com.br/como-fazer-um-acesso-ssh-no-aws-fargate</guid><category><![CDATA[fargate-ssh]]></category><category><![CDATA[aws-fargate-ssh]]></category><category><![CDATA[aws-fargate]]></category><category><![CDATA[AWS]]></category><dc:creator><![CDATA[SimplesCloud]]></dc:creator><pubDate>Sat, 27 Jan 2024 18:00:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1706297655692/82a01ba9-0f33-41e6-b571-65d345cdd62d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introducao">Introdução</h2>
<p>Se você utiliza o AWS Fargate como carga de trabalho para as suas aplicações, mais cedo ou mais tarde sentirá a necessidade de realizar um acesso SSH nos conteiners do Fargate para solucionar algum problema, fazer alguma depuração ou simplesmente testar algumas conexões e verificar alguns arquivos de configuração.</p>
<p>Se você usa o Lightsail Container, infelizmente descobrirá que não é possível fazer um acesso SSH nele, e por um tempo no Fargate também não era, porém agora é possível e vou descrever o passo a passo de como fiz isso.</p>
<p>Então se você está nessa situação e chegou até este artigo, ele é feito para você.</p>
<hr />
<h2 id="heading-etapa-1-instalar-o-aws-cli">Etapa 1 - Instalar o AWS CLI</h2>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text"><strong>Se você já possui o AWS CLI instalado e configurado, pode ignorar essa etapa!</strong></div>
</div>

<p>O primeiro passo é você instalar e configurar o <code>AWS CLI V2</code> em sua máquina, se você estiver usando o <code>Linux x86</code> por exemplo, pode instalar com o comando:</p>
<pre><code class="lang-bash">curl <span class="hljs-string">"https://awscli.amazonaws.com/awscli-exe-linux-aarch64.zip"</span> -o <span class="hljs-string">"awscliv2.zip"</span>
unzip awscliv2.zip
sudo ./aws/install
</code></pre>
<p>Se houver dúvidas sobre essa instalação e configuração, você pode consultar nosso outro artigo que explica por completo como fazer isso:</p>
<ul>
<li>👉 <a target="_blank" href="https://simplescloud.io/aws-cli-instalacao-e-configuracao">AWS CLI - Instalação e Configuração</a></li>
</ul>
<p>Ou ainda pode verificar diretamente na documentação da AWS se estiver usando um Sistema Operacional diferente:</p>
<ul>
<li>👉 <a target="_blank" href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html#getting-started-install-instructions">AWS CLI - Documentação Oficial</a></li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">☑</div>
<div data-node-type="callout-text">Uma vez que isso esteja pronto, podemos seguir para a próxima etapa.</div>
</div>

<hr />
<h2 id="heading-etapa-2-instalar-o-session-manager-plugin">Etapa 2 - Instalar o <strong>Session Manager Plugin</strong></h2>
<p>Se você estiver usando o <code>Linux x86</code> por exemplo, execute este comando:</p>
<pre><code class="lang-bash">curl <span class="hljs-string">"https://s3.amazonaws.com/session-manager-downloads/plugin/latest/linux_64bit/session-manager-plugin.rpm"</span> -o <span class="hljs-string">"session-manager-plugin.rpm"</span>
sudo yum install -y session-manager-plugin.rpm
</code></pre>
<p>Se houver dúvidas ou se estiver usando um outro Sistema Operacional, verifique a documentação oficial da AWS:</p>
<ul>
<li>👉 <a target="_blank" href="https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html">Session Manager plugin para AWS CLI</a></li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">☑</div>
<div data-node-type="callout-text">Uma vez que isso esteja pronto, podemos seguir para a próxima etapa</div>
</div>

<hr />
<h2 id="heading-etapa-3-configure-as-permissoes">Etapa 3 - Configure as Permissões</h2>
<h3 id="heading-crie-uma-politica-iam">Crie uma Política IAM</h3>
<p>1- Acesse o console <strong>AWS → IAM → Policies → Create Policy</strong> e defina o nome como por exemplo <strong>ECSFargateAllowExecuteCommand</strong> → insira o código <code>json</code> em sua política:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"Statement"</span>: [
        {
            <span class="hljs-attr">"Action"</span>: [
                <span class="hljs-string">"ssmmessages:CreateControlChannel"</span>,
                <span class="hljs-string">"ssmmessages:CreateDataChannel"</span>,
                <span class="hljs-string">"ssmmessages:OpenControlChannel"</span>,
                <span class="hljs-string">"ssmmessages:OpenDataChannel"</span>
            ],
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Resource"</span>: <span class="hljs-string">"*"</span>
        }
    ],
    <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>
}
</code></pre>
<hr />
<h3 id="heading-anexe-a-role-adequada">Anexe a Role Adequada</h3>
<p>1- Ainda no console <strong>AWS → IAM</strong> alterne de <strong>Policies</strong> para <strong>Roles</strong> e pesquise por <strong>ecsTaskExecutionRole</strong> → ao final, você deve obter uma tela parecida com:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706305163616/54e141ce-fd7d-4c72-966f-4cf331ba1a9f.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706302201827/3a9dc971-eef2-423d-b29c-f0ea3f0002f6.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-etapa-4-colete-informacoes-para-o-acesso">Etapa 4 - Colete Informações para o Acesso</h2>
<p>O comando AWS CLI <code>ecs execute-command</code> requer 3 parâmetros:</p>
<ul>
<li><p>O nome do cluster do ECS</p>
</li>
<li><p>O ID da tarefa do ECS</p>
</li>
<li><p>O nome do container</p>
</li>
</ul>
<p>Então acesse o console <strong>AWS → ECS</strong> e anote as informações, por exemplo:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706302717405/bff92c78-a3d5-4acb-9459-e3a14eee5a5f.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-etapa-5-faca-o-acesso-ssh-no-container-do-fargate">Etapa 5 - Faça o Acesso SSH no Container do Fargate</h2>
<p>1- Execute o comando:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se de alterar os valores de <code>region</code>, <code>cluster name</code>, <code>task id</code> e <code>container name</code> para os valores reais que você está usando</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Se a imagem do seu container for baseado em <code>debian</code>, utilize <code>/bin/bash</code>. Se a imagem do seu container for baseado em <code>alpine</code>, utilize <code>/bin/sh</code></div>
</div>

<pre><code class="lang-bash">aws ecs execute-command \
--region &lt;your-region&gt; \
--cluster &lt;your-ecs-cluster-name&gt; \
--task &lt;your-task-id&gt; \
--container &lt;your-container-name&gt; \
--<span class="hljs-built_in">command</span> <span class="hljs-string">"/bin/bash"</span> \
--interactive
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:700/0*WGZ4-m83b837AA-W.png" alt /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">☑</div>
<div data-node-type="callout-text">Pronto! Você já conseguiu acessar o container do Fargate através do SSH!</div>
</div>

<hr />
<h2 id="heading-etapa-6-opcional-bonus">Etapa 6 (Opcional) - Bônus</h2>
<h3 id="heading-habilite-o-servico-do-fargate-para-acesso-ssh">Habilite o Serviço do Fargate para Acesso SSH</h3>
<p>Se você estiver tentando acessar por SSH um ID de tarefa que está sendo gerenciada por um serviço do Fargate, poderá receber a seguinte mensagem de erro:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">❌</div>
<div data-node-type="callout-text"><code>An error occurred (invalidparameterexception) when calling the executecommand operation: the execute command failed because execute command was not enabled when the task was run or the execute command agent isn’t running. wait and try again or run a new task</code></div>
</div>

<p>Isso acontece porque antes precisamos habilitar o serviço do Fargate para que suas tasks permitam o acesso SSH, então digite o comando:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se de alterar <code>cluster name</code>, <code>service name</code> e <code>region</code> para os valores reais que você está usando</div>
</div>

<pre><code class="lang-bash">aws ecs update-service \
--cluster &lt;your-ecs-cluster-name&gt; \
--service &lt;your-ecs-service-name&gt; \
--region &lt;your-region&gt; \
--enable-execute-command \
--force-new-deployment
</code></pre>
<p>Após isso é só repetir o mesmo comando da <code>Etapa 5</code> e realizar o acesso SSH.</p>
<hr />
<h2 id="heading-conclusao">Conclusão</h2>
<p>Vimos passo a passo como acessar através de SSH uma task do AWS Fargate, isso pode ser muito útil para soluções de problemas, por exemplo você pode querer testar a conexão da task do Fargate com o banco de dados RDS para garantir que não há problemas de conexão:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706303610584/2dce5b6a-36f3-4a66-92a0-848ce1354702.png" alt class="image--center mx-auto" /></p>
<p>Ou imagine ainda que o deploy de um aplicativo construído em <code>.Net Core</code> nos containers do Fargate são realizados através de um pipeline CI/CD, e que o arquivo <code>appsettings.json</code> possui variáveis de ambiente por questões de segurança e muda os valores de acordo com o ambiente que está sendo implantado como <code>production</code>, <code>qa</code>, etc. Então você quer verificar se esses valores foram alterados corretamente:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706303899360/890aa092-3059-4a67-9bd1-7c3cf19dca0c.png" alt class="image--center mx-auto" /></p>
<p>Por fim, isso pode ser muito útil no seu dia a dia.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se de excluir todos os recursos ao final para não obter cobranças indesejadas e manter sua conta AWS limpa e organizada.</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Espero que as informações tenham sido úteis para você.</div>
</div>]]></content:encoded></item><item><title><![CDATA[Como melhorar a administração e organização dos Grupos de Segurança da AWS com o VPC Prefix List]]></title><description><![CDATA[Introdução
Quando comecei a usar mais a AWS, é comum criar cada vez mais grupos de segurança e com o tempo manter todos eles organizados acaba sendo tedioso, pois você observará que precisará atualizar com uma certa frequência cada grupo de segurança...]]></description><link>https://simplescloud.com.br/como-melhorar-a-administracao-e-organizacao-dos-grupos-de-seguranca-da-aws-com-o-vpc-prefix-list</link><guid isPermaLink="true">https://simplescloud.com.br/como-melhorar-a-administracao-e-organizacao-dos-grupos-de-seguranca-da-aws-com-o-vpc-prefix-list</guid><category><![CDATA[aws vpc prefix list]]></category><category><![CDATA[AWS VPC]]></category><category><![CDATA[AWS]]></category><category><![CDATA[AWS Security Group]]></category><dc:creator><![CDATA[SimplesCloud]]></dc:creator><pubDate>Fri, 26 Jan 2024 17:58:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1706276000858/c41ec8c2-8c42-4e5c-a484-592f1c7af645.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introducao">Introdução</h2>
<p>Quando comecei a usar mais a AWS, é comum criar cada vez mais grupos de segurança e com o tempo manter todos eles organizados acaba sendo tedioso, pois você observará que precisará atualizar com uma certa frequência cada grupo de segurança.</p>
<p>Para contextualizar melhor, imagine o seguinte cenário de exemplo:</p>
<ul>
<li><p>Uma equipe de desenvolvedores solicita para você a criação de um novo servidor web no Windows com IIS instalado, então você prontamente cria uma instância EC2 com um novo grupo de segurança chamado "<code>SG-web-app1</code>".</p>
</li>
<li><p>Agora a mesma equipe de desenvolvedores solicita para você a criação de um outro servidor Windows com um novo serviço do Windows instalado, então você prontamente cria uma outra instância EC2 e prefere não utilizar o mesmo grupo de segurança, pois você é organizado e prefere criar um outro grupo de segurança com nome diferente que distingue melhor "<code>SG-services-app1</code>"</p>
</li>
<li><p>Então em cada grupo de segurança você adiciona o IP de cada desenvolvedor para o protocolo RDP e permite que eles possam acessar remotamente cada instância, isso se pareceria por exemplo com:</p>
</li>
</ul>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Nome</td><td>Protocolo</td><td>Porta</td><td>IP do Desenvolvedor</td></tr>
</thead>
<tbody>
<tr>
<td>SG-web-app1</td><td>RDP</td><td>3389</td><td>1.2.3.4</td></tr>
<tr>
<td>SG-web-app1</td><td>RDP</td><td>3389</td><td>5.6.7.8</td></tr>
<tr>
<td>SG-services-app1</td><td>RDP</td><td>3389</td><td>1.2.3.4</td></tr>
<tr>
<td>SG-services-app1</td><td>RDP</td><td>3389</td><td>5.6.7.8</td></tr>
</tbody>
</table>
</div><p>Observe na tabela que você tem 2 IPs diferentes de 2 desenvolvedores diferentes em 2 grupos de seguranças diferentes e aí que todo o problema começa.</p>
<p>Cada desenvolvedor possui um IP dinâmico e não fixo, isso na prática significa que o IP que eles recebem do provedor de internet deles mudam frequentemente.</p>
<p>Então eles começam a enviar para você que perderam o acesso remoto, isso acontece porque o IP real e atual deles não é o mesmo que você liberou no grupo de segurança inicialmente.</p>
<p>Você então solicita o novo IP para eles e então atualiza cada grupo de segurança e o problema é resolvido.</p>
<p>Mas será que está resolvido mesmo? A resposta curta é sim. Mas comece a multiplicar essa situação para mais pessoas na equipe e para mais grupos de segurança e você passará muito tempo lembrando, organizando e atualizando esses grupos de segurança.</p>
<p>Se você está em uma situação semelhante, compartilho a solução que encontrei para reduzir essa complexidade usando o <code>VPC Prefix List</code>.</p>
<hr />
<h2 id="heading-vpc-prefix-list">VPC Prefix List</h2>
<p>A lista de prefixo da AWS é um recurso que existe já algum tempo e existem 2 tipos:</p>
<ol>
<li><p><strong>Lista de prefixos gerenciadas pela AWS:</strong></p>
<p> Como o nome indica, essas listas são gerenciadas pela AWS e são usadas para manter um conjunto de intervalos de endereços IP para serviços da AWS como o <code>S3</code>, <code>DynamoDB</code> e <code>CloudFront</code>.</p>
</li>
<li><p><strong>Listas de prefixos gerenciadas pelo cliente:</strong></p>
<p> São criadas e mantidas por qualquer pessoa que tenha acesso ao Console AWS, as APIs da AWS ou aos SDKs da AWS. É nisso que nos concentraremos.</p>
</li>
</ol>
<p>A lista de prefixo gerenciados pelo cliente da AWS VPC é uma ótima ferramenta disponível, pois fornece a capacidade de rastrear e manter uma lista de valores de bloco CIDR, que podem então ser referenciados por outros componentes de rede da AWS em suas regras.</p>
<hr />
<h3 id="heading-como-criar-um-vpc-prefix-list">Como criar um VPC Prefix List</h3>
<p>1- Acesse a console <code>AWS</code> → <code>VPC</code> → <code>Managed Prefix Lists</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706278311599/46b05868-3688-41e0-9ceb-7a68a2a4b6f4.png" alt class="image--center mx-auto" /></p>
<p>2- Clique em <code>Create Prefix List</code></p>
<p>Para isso, atente-se as seguintes regras:</p>
<ul>
<li><p>Você deve escolher o tipo de família como IPv4 ou IPv6 e a quantidade máxima de IPs que poderá ter essa lista. <strong><mark>E esses valores não podem ser alterados depois</mark></strong><mark>.</mark></p>
</li>
<li><p>Um <strong>grupo de segurança</strong> possui um <strong><mark>limite de 60 regras</mark></strong></p>
<ul>
<li><p>Cada entrada da sua lista consumirá uma regra do grupo de segurança</p>
</li>
<li><p>Por exemplo se sua lista de prefixo tiver 20 endereços IPs, isso consumirá 20 das 60 regras que o grupo de segurança pode ter</p>
</li>
<li><p>Então obviamente você não pode adicionar mais do que 60 IPs nessa lista, pois atingirá a cota limite do grupo de segurança e não dará certo</p>
</li>
</ul>
</li>
<li><p>Na prática isso significa, que ao adicionar no grupo de segurança uma lista de prefixo, mesmo que seja uma regra, na verdade a lista expandirá pela quantidade de IPs da lista e consumirá do seu limite no grupo de segurança</p>
</li>
<li><p>A única exceção é que digamos que você tenha uma lista de prefixo IPv4 com 60 IPs e outra lista de prefixo IPv6 com outros 60 IPs, então você adiciona essas duas regras no grupo de segurança e irá ter então 120 IPs como total, isso iria funcionar porque a cota do grupo de segurança é imposta separadamente para IPv4 e IPv6</p>
</li>
<li><p>O mesmo não se aplica por exemplo se você adicionar no grupo de segurança 2 listas de prefixos IPv4 com 60 IPs cada, isso daria um total de 120 IPs IPv4 e ultrapassaria a cota de 60 regras do grupo de segurança</p>
</li>
<li><p>Para nosso exemplo, defini um limite de 20 entradas, isso dá uma margem para usar outras regras no grupo de segurança no futuro se for necessário</p>
</li>
<li><p>E lembre-se de adicionar <code>/32</code> ao final do IP que algum desenvolvedor te passar, pois esse é o formato correto do CIDR aqui.</p>
</li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Então planeje bem e se atente a este detalhe do limite e cota no grupo de segurança</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706278632304/6b7d2fb9-90e5-46d8-a866-0cb579412436.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-como-configurar-o-grupo-de-seguranca">Como configurar o Grupo de Segurança</h3>
<p>1- Uma vez criado, você verá ela juntamente com as listas de prefixos gerenciados pela AWS:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712616331041/1cf73770-aa98-4aaa-a44a-bac78fa30870.png" alt class="image--center mx-auto" /></p>
<p>2- Agora acesse o grupo de segurança e adicione a regra de entrada com o <code>ID</code> da lista de prefixo</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706279972535/1aaf5a97-3f00-49fc-9ad3-37e0df786983.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">☑</div>
<div data-node-type="callout-text">Pronto!</div>
</div>

<hr />
<p>Para manter ainda mais organizado, costumo criar o grupo de segurança com o nome <code>SG-&lt;name&gt;-team-rdp-&lt;env&gt;</code>, por exemplo <code>SG-simplescloud-team-rdp-qa</code> e sua regra de entrada ficaria parecido com a imagem acima.</p>
<p>Então o que está acontecendo na prática é que:</p>
<ul>
<li>As instâncias EC2 <code>web-app1</code> e <code>services-app1</code> do nosso exemplo, agora terão esse grupo de segurança adicional <code>SG-&lt;name&gt;-team-rdp-&lt;env&gt;</code> anexados nas instâncias e permitirá o acesso remoto para os IPs que serão consultados na lista de prefixo criada. Por exemplo a instância "<code>web-app1</code>" teria dois grupos de segurança anexados:</li>
</ul>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Instância</td><td>Grupo de Segurança 1</td><td>Grupo de Segurança 2</td></tr>
</thead>
<tbody>
<tr>
<td>web-app1</td><td>SG-http-https</td><td>SG-simplescloud-team-rdp-qa</td></tr>
<tr>
<td></td><td>Porta 80 e 443</td><td>Porta 3389</td></tr>
</tbody>
</table>
</div><ul>
<li><p>Desta forma, sua instância terá grupos de segurança dedicados pelos protocolos que as regras permitem, evitando aqueles grupos de segurança "<code>launch-wizard</code>" que possui todas regras misturadas de <code>HTTP</code>, <code>HTTPS</code>, <code>RDP</code>, <code>MSSQL</code>, etc. Facilitando assim a administração a longo prazo</p>
</li>
<li><p>Desta forma ainda, os desenvolvedores ainda sim precisarão fornecer para você seus respectivos IPs dinâmicos atualizados, a grande diferença agora é que você não precisará mais entrar em cada grupo de segurança e ir atualizando, atualizará apenas a lista de prefixo em um único lugar e isso será replicado para todos os grupos de segurança que fizer referência a ela</p>
</li>
<li><p>Diminuindo muito então a sobrecarga de administração e organização dos grupos de segurança.</p>
</li>
</ul>
<hr />
<p>Se ainda não estiver convencido dos benefícios, passamos por mais um exemplo:</p>
<p>Imagine que você tenha os IPs repetidos nos grupos de segurança <code>X</code>, <code>Y</code> e <code>Z</code>:</p>
<p><img src="https://miro.medium.com/v2/resize:fit:700/0*Wd1hR3VtsdkyCCvG.png" alt /></p>
<p>Aplicando essa solução, isso poderia ser modificado por:</p>
<p><img src="https://miro.medium.com/v2/resize:fit:700/0*nUIIVo1SWt-4joPr.png" alt /></p>
<p>Observe então que não será mais necessário entrar em cada grupo de segurança para atualizar, uma vez que você atualizar a lista de prefixo centralmente, isso será aplicado automaticamente para todos os grupos de segurança que fazem referência para essa lista de prefixo em suas regras.</p>
<hr />
<h2 id="heading-conclusao">Conclusão</h2>
<p>Administrar e organizar os grupos de segurança da AWS é uma tarefa importante relacionada a segurança, porém ela pode ser tediosa e trabalhosa ao longo do tempo. Seu tempo é valioso demais para ficar perdendo tempo com esse tipo de tarefa, então compartilhei uma solução com <code>VPC Prefix List</code> para reduzir drasticamente as atualizações diretamente nos grupos de segurança e então manter as coisas organizadas com o menor esforço possível.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Espero que essas informações tenham sido úteis para você!</div>
</div>]]></content:encoded></item><item><title><![CDATA[Compartilhar um convite de usuário no AWS QuickSight - Solução Alternativa]]></title><description><![CDATA[Problema
Um cliente utiliza o AWS QuickSight como seu dashboard para apresentar visualmente alguns dados e informações através de gráficos. Então é comum enviarem um email de convite de acesso para este dashboard através do console AWS, porém o probl...]]></description><link>https://simplescloud.com.br/solucao-alternativa-para-compartilhar-um-convite-de-usuario-no-aws-quicksight</link><guid isPermaLink="true">https://simplescloud.com.br/solucao-alternativa-para-compartilhar-um-convite-de-usuario-no-aws-quicksight</guid><category><![CDATA[aws quicksight]]></category><category><![CDATA[AWS]]></category><dc:creator><![CDATA[SimplesCloud]]></dc:creator><pubDate>Thu, 25 Jan 2024 20:02:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1706124600546/fc801fe7-7f88-4133-93e7-7d59d07f47e2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-problema">Problema</h2>
<p>Um cliente utiliza o AWS QuickSight como seu dashboard para apresentar visualmente alguns dados e informações através de gráficos. Então é comum enviarem um email de convite de acesso para este dashboard através do console AWS, porém o problema está nesta etapa, esses emails de convite do AWS QuickSight demoram para chegar ou nem sempre são recebidos pelo destinatário e é importante dizer que o problema não está no envio por parte da AWS, pois possuem uma taxa de entrega confiável.</p>
<p>Há várias possíveis causas para isso, mas o mais provável é que os servidores de emails das empresas que recebem esses convites, por acaso, estejam bloqueando o recebimento deste email por alguma política interna de segurança ou de spam.</p>
<p>Este fluxo se parece desta forma:</p>
<ul>
<li><p>No console do <code>AWS QuickSigh</code> → clique no botão <code>Convidar Usuários</code></p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706209411893/f9f3308c-3383-4016-8e8e-474c6297f367.png" alt class="image--center mx-auto" /></p>
<p>  Insira os emails que deseja convidar → clique no botão <code>+</code></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706209485262/79ecbc12-cdc7-43da-8d9f-1d468efe5739.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Defina o nível de acesso, no caso como <code>Leitor</code> → clique em <code>Convidar</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706210145064/94801085-8146-402f-908f-77acbfa9151a.png" alt class="image--center mx-auto" /></p>
<p>Isso parece ser muito fácil (e realmente é), além disso funciona quase que toda vez, mas este artigo é para demonstrar uma alternativa para se você estiver na mesma situação que me encontrei, ou seja, mesmo fazendo isso o destinatário reporta que não recebe os emails de convite enviados pela AWS.</p>
<p>Se você chegou até aqui e está nessa situação, este artigo é para você, compartilho abaixo uma alternativa para cobrir isso.</p>
<hr />
<h2 id="heading-solucao">Solução</h2>
<p>1- Faça login no console <code>AWS</code> → clique no botão <code>Cloudshell</code></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text"><strong>Atenção:</strong> O usuário que você fizer login precisa ter permissões para o QuickSight, se você está fazendo login como usuário root da conta, já possui essa permissão, se está fazendo login com um usuário IAM, seu usuário precisa ter essas permissões:</div>
</div>

<pre><code class="lang-json">{
    <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
    <span class="hljs-attr">"Statement"</span>: [
        {
            <span class="hljs-attr">"Sid"</span>: <span class="hljs-string">"VisualEditor0"</span>,
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Action"</span>: [
                <span class="hljs-string">"quicksight:CreateReader"</span>,
                <span class="hljs-string">"cloudshell:*"</span>,
                <span class="hljs-string">"quicksight:CreateUser"</span>,
                <span class="hljs-string">"quicksight:DeleteUser"</span>,
                <span class="hljs-string">"quicksight:ListUserGroups"</span>,
                <span class="hljs-string">"quicksight:DescribeUser"</span>,
                <span class="hljs-string">"quicksight:CreateAdmin"</span>,
                <span class="hljs-string">"quicksight:ListUsers"</span>,
                <span class="hljs-string">"quicksight:UpdateUser"</span>,
                <span class="hljs-string">"quicksight:RegisterUser"</span>,
                <span class="hljs-string">"quicksight:SearchUsers"</span>
            ],
            <span class="hljs-attr">"Resource"</span>: <span class="hljs-string">"*"</span>
        }
    ]
}
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Você pode por exemplo criar uma política IAM chamada <code>QuickSighRegisterUser</code> com o conteúdo acima e anexar ao seu usuário</div>
</div>

<p>Uma vez que você tenha feito login no console <code>AWS</code>, clicado no <code>Cloudshell</code> e seu usuário já possui as permissões discutidas acima, você deve estar vendo uma tela parecida com esta e pronto para seguirmos ao próximo passo:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706210939755/1668e1a6-a8c9-4784-a30f-8b06c6e28b2d.png" alt class="image--center mx-auto" /></p>
<p>2- Digite o comando:</p>
<pre><code class="lang-bash">aws quicksight register-user \
--aws-account-id &lt;your-id&gt; \
--identity-type QUICKSIGHT \
--email &lt;recipient-email&gt; \
--user-role READER \
--namespace default \
--user-name &lt;recipient-email&gt;
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se de alterar <code>&lt;your-id&gt;</code> pelo ID da sua conta AWS e <code>&lt;recipient-email&gt;</code> pelo email do destinatário que deseja convidar</div>
</div>

<p>Por exemplo:</p>
<pre><code class="lang-bash">aws quicksight register-user \
--aws-account-id 111111111111 \
--identity-type QUICKSIGHT \
--email user1-test@simplescloud.io \
--user-role READER \
--namespace default \
--user-name user1-test@simplescloud.io
</code></pre>
<p>Se você fez isso, deverá obter uma resposta do seu comando parecido com essa tela:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706211301029/86a3a541-88e5-46c3-9c12-8567a999483f.png" alt class="image--center mx-auto" /></p>
<p>Por questões de confidencialidade, ocultamos algumas informações do print acima, mas o que importa para nós é a parte final com o link, copie este link.</p>
<p>E isso é tudo, você agora pode compartilhar esse link com o destinatário da forma que achar melhor, sem depender do recebimento do email que enviaria esse mesmo link (que é a origem do problema que discutimos no início).</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">☑</div>
<div data-node-type="callout-text">Pronto! 😁👍</div>
</div>

<hr />
<p>Apenas para demonstrar, o destinatário então veria algo parecido com isso ao acessar o link que você compartilhou com ele:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Algumas informações foram ocultadas dos prints por causa de confidencialidade</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706211712641/60f8ea41-9ee8-4906-81c6-b7f626f014f8.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706211730762/4aa2126d-a0eb-48bc-be6d-52b8459db55e.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706211777681/54f54439-12c8-4369-aaff-9dd847199239.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706211789913/73bd7a16-20c9-4e0e-8f75-2cd11a0727ed.png" alt class="image--center mx-auto" /></p>
<hr />
<h1 id="heading-conclusao">Conclusão</h1>
<p>AWS QuickSight é uma excelente ferramenta para dashboards e convidar usuários para acessarem é relativamente fácil e simples, porém em alguns momentos isso pode ser frustrante se os convites nunca chegarem no email do destinatário.</p>
<p>Então compartilhei uma solução alternativa criando uma política IAM com permissões granulares necessárias para convidar um usuário sem acesso total ao QuickSight, demonstramos ainda como executar um comando no Cloudshell e gerar o link para compartilhar ao destinatário de outras formas.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Espero que essas informações tenham sido úteis para você.</div>
</div>]]></content:encoded></item><item><title><![CDATA[Aprenda a Reiniciar sua instância EC2 com Agendamento Automático]]></title><description><![CDATA[INTRODUÇÃO
Recentemente recebi um projeto para reiniciar uma instância EC2 todos os dias em um horário específico automaticamente. Havia uma premissa de não ter a necessidade de acesso ssh para configurações de scripts e crontab para minimizar um pos...]]></description><link>https://simplescloud.com.br/aprenda-a-reiniciar-sua-instancia-ec2-com-agendamento-automatico</link><guid isPermaLink="true">https://simplescloud.com.br/aprenda-a-reiniciar-sua-instancia-ec2-com-agendamento-automatico</guid><category><![CDATA[aws ec2]]></category><category><![CDATA[aws ec2 auto reboot]]></category><category><![CDATA[AWS]]></category><dc:creator><![CDATA[SimplesCloud]]></dc:creator><pubDate>Fri, 16 Jun 2023 18:57:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730672197255/e75158a2-1cd2-4c3b-8892-f9a59484f614.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introducao">INTRODUÇÃO</h2>
<p>Recentemente recebi um projeto para reiniciar uma instância EC2 todos os dias em um horário específico automaticamente. Havia uma premissa de não ter a necessidade de acesso <code>ssh</code> para configurações de <code>scripts</code> e <code>crontab</code> para minimizar um possível erro ou esquecimento no futuro.</p>
<p>Então aqui está o passo a passo que fiz para atingir esse objetivo, vamos lá!</p>
<hr />
<h2 id="heading-etapa-1-permissoes">ETAPA 1 - Permissões</h2>
<p>1- Acesse o <strong>IAM</strong> → <strong>Policy</strong> → alterne para a aba <strong>JSON</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686772542873/0b093e4f-4ee0-4eb3-9d1b-a25eaa39676e.png" alt class="image--center mx-auto" /></p>
<p>Defina o nome como <strong>“ec2_reboot_instances_policy”</strong> → altere no bloco <strong>“Resource”</strong> para os IDs das instâncias reais para seu cenário</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Lembre-se de alterar a região, número da conta e id da instância do código de exemplo abaixo para seus valores reais</div>
</div>

<pre><code class="lang-json">{
    <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
    <span class="hljs-attr">"Statement"</span>: [
        {
            <span class="hljs-attr">"Sid"</span>: <span class="hljs-string">"VisualEditor0"</span>,
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Action"</span>: [
                <span class="hljs-string">"ec2:RebootInstances"</span>,
                <span class="hljs-string">"ec2:TerminateInstances"</span>,
                <span class="hljs-string">"ec2:StopInstances"</span>
            ],
            <span class="hljs-attr">"Resource"</span>: [
                <span class="hljs-string">"arn:aws:ec2:us-east-1:xxxxxxxxxxxx:instance/i-xxxxxxxxxxxx"</span>,
                <span class="hljs-string">"arn:aws:ec2:us-east-1:xxxxxxxxxxxx:instance/i-xxxxxxxxxxxx"</span>
            ]
        }
    ]
}
</code></pre>
<p>2- Acesse o <strong>IAM</strong> → <strong>Role</strong> → selecione <strong>AWS Service</strong> → em <strong>Use cases for other AWS services</strong> → selecione <strong>CloudWatch Events</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686772600667/d34c10c9-df65-4f5e-a7c9-7728dc35d4ed.png" alt class="image--center mx-auto" /></p>
<p>Defina o nome como <strong>“ec2_reboot_instances_role”</strong> → adicione a política criada no passo anterior → clique na aba <strong>Trust Relationships</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686772636650/b029b084-f0ca-4632-a54c-abe9f5a8d1fc.png" alt class="image--center mx-auto" /></p>
<p>Verifique se está igual o código abaixo:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
    <span class="hljs-attr">"Statement"</span>: [
        {
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Principal"</span>: {
                <span class="hljs-attr">"Service"</span>: <span class="hljs-string">"events.amazonaws.com"</span>
            },
            <span class="hljs-attr">"Action"</span>: <span class="hljs-string">"sts:AssumeRole"</span>
        }
    ]
}
</code></pre>
<hr />
<h2 id="heading-etapa-2-cloudwatch-events">ETAPA 2 - CloudWatch Events</h2>
<p>1- Acesse o <strong>CloudWatch</strong> → <strong>Events</strong> → <strong>Rules</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686772760066/815afd35-8c31-494b-8fbd-50cfc4a538dd.png" alt class="image--center mx-auto" /></p>
<p>2- Clique em <strong>Create Rule</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686772795384/3bfcb868-1597-40f4-9b0d-d69684e17ffd.png" alt class="image--center mx-auto" /></p>
<p>3- Defina o nome da regra como <strong>“EC2_instance_reboot”</strong> por exemplo → alterne para <strong>Schedule</strong> → clique em <strong>Continue to create rule</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686772833835/d7dbb43c-9b55-4311-89fd-4046c3f7dcd3.png" alt class="image--center mx-auto" /></p>
<p>4- Defina sua <strong>expressão cron</strong> como por exemplo <code>0 7 * * ? *</code> (isso irá definir o cron para todos os dias as 7 horas UTC ou 4 horas em Brasília)</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Você pode criar a expressão cron da forma que desejar, outro exemplo poderia ser <code>50 16 ? MON-FRI *</code> e isso iria funcionar de segunda a sexta as 16 horas e 50 minutos UTC (ou 13 horas e 50 minutos horário de Brasília)</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686772874548/723f6ab6-5cc4-419b-bf48-66f4d980046b.png" alt class="image--center mx-auto" /></p>
<p>5- Selecione em <strong>Target</strong> a opção <strong>EC2 RebootInstances API Call</strong> → insira o ID da instância EC2 que deseja reiniciar → escolha <strong>Use execution role criada no primeiro passo</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686772907546/5672026a-ebc0-447b-b9f9-7eb63aa75f74.png" alt class="image--center mx-auto" /></p>
<p>6- <strong>Repita</strong> o passo anterior para mais instâncias que precisar clicando no botão <strong>Add Another Target</strong></p>
<hr />
<h2 id="heading-conclusao">CONCLUSÃO</h2>
<p>Criamos uma solução para reiniciar automaticamente instâncias EC2 sem a necessidade de acessar <code>ssh</code> ou fazer qualquer configuração dentro da instância, minimizando qualquer problema, desta forma nosso CloudWatch Events possui um agendamento, e então no momento definido invocará a API necessária para reiniciar a instância EC2. Além disso essa é uma solução barata.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Espero que essas informações tenham sido úteis para você!</div>
</div>]]></content:encoded></item><item><title><![CDATA[Aprenda a Reiniciar sua Instância Lightsail com Agendamento Automático]]></title><description><![CDATA[INTRODUÇÃO
Recentemente recebi um projeto para reiniciar uma instância Lightsail todos os dias em um horário específico automaticamente. Essa instância Lightsail era uma pilha otimizada de WordPress de um site que recebia um alto tráfego de visitas, ...]]></description><link>https://simplescloud.com.br/aprenda-a-reiniciar-sua-instancia-lightsail-com-agendamento-automatico</link><guid isPermaLink="true">https://simplescloud.com.br/aprenda-a-reiniciar-sua-instancia-lightsail-com-agendamento-automatico</guid><category><![CDATA[lightsail-auto-reboot]]></category><category><![CDATA[aws lightsail]]></category><category><![CDATA[AWS]]></category><category><![CDATA[#Lightsail]]></category><dc:creator><![CDATA[SimplesCloud]]></dc:creator><pubDate>Fri, 16 Jun 2023 18:55:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730671932141/ff2f2530-2239-4d0c-a6bc-b74f6caa0056.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introducao">INTRODUÇÃO</h2>
<p>Recentemente recebi um projeto para reiniciar uma instância Lightsail todos os dias em um horário específico automaticamente. Essa instância Lightsail era uma pilha otimizada de WordPress de um site que recebia um alto tráfego de visitas, e por um motivo não relevante para este artigo, quando essa instância ficava muito tempo ligada, alguns problemas e lentidões aconteciam, porém um simples clique no botão <code>reboot</code> resolvia todos os problemas.</p>
<p>Embora haja outras abordagens que poderiam resolver esse problema, esse cliente em específico gostaria de manter as coisas simples, tão simples como apenas reiniciar essa instância Lightsail, nada além disso, isso era o suficiente, porém deveria ser de forma automática. Ainda esse projeto exigia como premissa não termos que acessar a instância através de <code>ssh</code> e realizar configurações como <code>scripts</code> ou <code>crontab</code>, preferencialmente deveríamos criar uma solução fora da caixa para que isso fosse feito sem qualquer acesso na instância.</p>
<p>Então aqui está o passo a passo que fiz para atingir esse objetivo, note que citei esse caso de uso real do site WordPress, mas isso pode ser aplicado para toda e qualquer instância Lightsail que você deseja reiniciar automaticamente, independentemente dos seus motivos.</p>
<p>Então vamos lá!</p>
<hr />
<h2 id="heading-etapa-1-permissoes">ETAPA 1 - Permissões</h2>
<p>1- Acesse o <strong>IAM</strong> → <strong>Policy</strong> → alterne para a aba <strong>JSON</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686768697835/6d946e1f-d600-4f3c-8b5e-8fb4b25a9cf3.png" alt class="image--center mx-auto" /></p>
<p>Defina o nome como <strong>“lightsail_reboot_policy”</strong></p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
    <span class="hljs-attr">"Statement"</span>: [
        {
            <span class="hljs-attr">"Sid"</span>: <span class="hljs-string">"VisualEditor0"</span>,
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Action"</span>: <span class="hljs-string">"lightsail:RebootInstance"</span>,
            <span class="hljs-attr">"Resource"</span>: <span class="hljs-string">"*"</span>
        }
    ]
}
</code></pre>
<p>2- Acesse o <strong>IAM</strong> → <strong>Role</strong> → selecione <strong>AWS Service</strong> e <strong>Lambda</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686768799583/b850ad89-435e-4dde-96d5-033a9b200600.png" alt class="image--center mx-auto" /></p>
<p>Defina o nome como <strong>“lightsail_reboot_role”</strong> → adicione a política criada no passo anterior → clique na aba <strong>Trust Relationships</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686768844100/914bcdb7-5b3f-45a2-a5a1-95dc545f9630.png" alt class="image--center mx-auto" /></p>
<p>Verifique se está igual o código abaixo:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
    <span class="hljs-attr">"Statement"</span>: [
        {
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Principal"</span>: {
                <span class="hljs-attr">"Service"</span>: <span class="hljs-string">"lambda.amazonaws.com"</span>
            },
            <span class="hljs-attr">"Action"</span>: <span class="hljs-string">"sts:AssumeRole"</span>
        }
    ]
}
</code></pre>
<hr />
<h2 id="heading-etapa-2-funcao-lambda">ETAPA 2 - Função Lambda</h2>
<p>1- Acesse o <strong>Lambda (author from scratch)</strong> → crie uma função com:</p>
<ul>
<li><p><strong>Function Name:</strong><code>lightsail_reboot</code></p>
</li>
<li><p><strong>Runtime:</strong><code>Pyhton 3.9</code></p>
</li>
<li><p><strong>Architecture:</strong><code>x86_64</code></p>
</li>
<li><p>Expanda a opção <strong>“Change default execution role”</strong> → <strong>Use existing role</strong> → selecione a role criada no passo anterior</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686768930476/5cf1fa9c-8420-40e3-9546-7d39fab9bb3c.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Em <strong>Code</strong> (lembre-se de mudar <code>instanceName</code> e <code>region_name</code> pelos valores reais do seu cenário</div>
</div>

<pre><code class="lang-python"><span class="hljs-keyword">import</span> json
<span class="hljs-keyword">import</span> boto3

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">lambda_handler</span>(<span class="hljs-params">event, context</span>):</span>
    client = boto3.client(<span class="hljs-string">"lightsail"</span>, region_name=<span class="hljs-string">"us-east-1"</span>)
    response = client.reboot_instance(instanceName=<span class="hljs-string">"EXAMPLE"</span>)

    <span class="hljs-keyword">return</span> {
        <span class="hljs-string">"statusCode"</span>: <span class="hljs-number">200</span>,
        <span class="hljs-string">"body"</span>: json.dumps({
            <span class="hljs-string">"message"</span>: <span class="hljs-string">"Lightsail instance restarted successfully!"</span>
        })
    }
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686769330136/343282c3-99b5-4e40-aa2c-7f9463b91137.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-etapa-3-cloudwatch-events-rules">ETAPA 3 - CloudWatch Events Rules</h2>
<p>1- Acesse o <strong>Cloudwatch</strong> → <strong>Events</strong> → <strong>Rules</strong> → <strong>Create Rule</strong> → defina o nome <strong>“Site_Reboot”</strong> por exemplo ou qualquer outro nome que faça sentido para você</p>
<p>Defina sua expressão <code>cron</code>, por exemplo:</p>
<p><strong>Cron express:</strong><code>0 7 * * ? *</code> → expressão cron diária as 7 horas UTC e 4 horas no horário de Brasília.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Você pode usar a expressão cron que for melhor para seu cenário, por exemplo <code>50 16 ? MON-FRI *</code> funcionaria de segunda a sexta as 16 horas e 50 minutos UTC (ou 13 horas e 50 minutos no horário de Brasília)</div>
</div>

<p>Ou qualquer horário de sua preferência e que faça sentido para seu cenário</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686769625784/11d28448-9b92-4794-a7ed-5cad77528b4d.png" alt class="image--center mx-auto" /></p>
<p>2- Em <strong>Target</strong> → selecione a função Lambda criada anteriormente</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686769699068/5bfc7a37-c34f-4971-8ed4-8864893e0b6c.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-bonus">Bônus</h2>
<p>As vezes em seu cenário pode ser que as instâncias Lightsail possuem um prefixo no nome, ou seja você em algum momento adotou um padrão de nomenclatura e suas instâncias começam sempre com um prefixo, por exemplo por <code>SC-instance1</code>, <code>SC-instance2</code>, etc.</p>
<p>Se esse for o caso, tudo que vimos acima ainda funcionará para você, mas se você está se perguntando se terá que criar uma função e uma regra para cada uma então a resposta curta é não.</p>
<hr />
<h3 id="heading-opcao-1-use-prefixos-e-reinicie-varias-instancias-ao-mesmo-tempo">Opção 1 - Use prefixos e reinicie várias instâncias ao mesmo tempo</h3>
<p>Para esse cenário, mude o código da sua função Lambda para:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se de alterar a <code>region_name</code> e o <code>prefix</code> para os valores reais que você está usando.</div>
</div>

<pre><code class="lang-python"><span class="hljs-keyword">import</span> json
<span class="hljs-keyword">import</span> boto3

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">lambda_handler</span>(<span class="hljs-params">event, context</span>):</span>
    <span class="hljs-comment"># Lightsail Configuration</span>
    lightsail_client = boto3.client(<span class="hljs-string">"lightsail"</span>, region_name=<span class="hljs-string">"us-west-2"</span>)

    <span class="hljs-comment"># Prefix to search for instances</span>
    prefix = <span class="hljs-string">'your-prefix'</span>

    <span class="hljs-comment"># List all instances</span>
    response = lightsail_client.get_instances()

    <span class="hljs-comment"># List of instance names to be restarted</span>
    instance_names = []

    <span class="hljs-comment"># Filter and add instances that begin with the prefix to the list</span>
    <span class="hljs-keyword">for</span> instance <span class="hljs-keyword">in</span> response[<span class="hljs-string">"instances"</span>]:
        <span class="hljs-keyword">if</span> instance[<span class="hljs-string">"name"</span>].startswith(prefix):
            instance_names.append(instance[<span class="hljs-string">"name"</span>])

    responses = {}  <span class="hljs-comment"># Dictionary to store restart responses</span>

    <span class="hljs-comment"># Loop through the list of names and restart each instance</span>
    <span class="hljs-keyword">for</span> instance_name <span class="hljs-keyword">in</span> instance_names:
        response = lightsail_client.reboot_instance(
            instanceName=instance_name
        )
        responses[instance_name] = response

    <span class="hljs-keyword">return</span> {
        <span class="hljs-string">"statusCode"</span>: <span class="hljs-number">200</span>,
        <span class="hljs-string">"body"</span>: json.dumps({
            <span class="hljs-string">"message"</span>: <span class="hljs-string">"Successfully restarted instances"</span>
        })
    }
</code></pre>
<hr />
<h3 id="heading-opcao-2-envie-um-email-tambem-com-aws-ses">Opção 2 - Envie um email também com AWS SES</h3>
<p>Para esse cenário, mude o código da sua função Lambda para:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Lembre-se de alterar os valores da <code>region_name</code>, o <code>email do remetente e destinatário</code>, além do <code>prefix</code> que você utiliza. Também seu <code>AWS SES</code> precisa estar devidamente configurado e verificado com o domínio ou email que você utilizará aqui.</div>
</div>

<pre><code class="lang-python"><span class="hljs-keyword">import</span> json
<span class="hljs-keyword">import</span> boto3

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">send_email</span>(<span class="hljs-params">subject, body, recipient</span>):</span>
    ses = boto3.client(<span class="hljs-string">'ses'</span>, region_name=<span class="hljs-string">'us-west-2'</span>)
    response = ses.send_email(
        Source=<span class="hljs-string">'your-email@example.com    '</span>, 
        Destination={
            <span class="hljs-string">'ToAddresses'</span>: [recipient]
        },
        Message={
            <span class="hljs-string">'Subject'</span>: {
                <span class="hljs-string">'Data'</span>: subject
            },
            <span class="hljs-string">'Body'</span>: {
                <span class="hljs-string">'Text'</span>: {
                    <span class="hljs-string">'Data'</span>: body
                }
            }
        }
    )

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">lambda_handler</span>(<span class="hljs-params">event, context</span>):</span>
    <span class="hljs-comment"># Lightsail Configuration</span>
    lightsail_client = boto3.client(<span class="hljs-string">"lightsail"</span>, region_name=<span class="hljs-string">"us-west-2"</span>)

    <span class="hljs-comment"># Prefix to search for instances</span>
    prefix = <span class="hljs-string">'your-prefix'</span>

    <span class="hljs-comment"># List all instances</span>
    response = lightsail_client.get_instances()

    <span class="hljs-comment"># List of instance names to be restarted</span>
    instance_names = []

    <span class="hljs-comment"># Filter and add instances that begin with the prefix to the list</span>
    <span class="hljs-keyword">for</span> instance <span class="hljs-keyword">in</span> response[<span class="hljs-string">"instances"</span>]:
        <span class="hljs-keyword">if</span> instance[<span class="hljs-string">"name"</span>].startswith(prefix):
            instance_names.append(instance[<span class="hljs-string">"name"</span>])

    responses = {}  <span class="hljs-comment"># Dictionary to store restart responses</span>

    <span class="hljs-comment"># Loop through the list of names and restart each instance</span>
    <span class="hljs-keyword">for</span> instance_name <span class="hljs-keyword">in</span> instance_names:
        response = lightsail_client.reboot_instance(
            instanceName=instance_name
        )
        responses[instance_name] = response

    <span class="hljs-comment"># Send notification email</span>
    subject = <span class="hljs-string">'Lightsail - Restarted Instances'</span>
    body = <span class="hljs-string">'Lightsail instances were successfully restarted by lambda.'</span>
    recipient = <span class="hljs-string">'other-email@example.com'</span>

   send_email(subject, body, recipient)

    <span class="hljs-keyword">return</span> {
        <span class="hljs-string">"statusCode"</span>: <span class="hljs-number">200</span>,
        <span class="hljs-string">"body"</span>: json.dumps({
            <span class="hljs-string">"message"</span>: <span class="hljs-string">"Instances restarted and email sent successfully"</span>
        })
    }
</code></pre>
<hr />
<h2 id="heading-conclusao">CONCLUSÃO</h2>
<p>Criamos uma solução para reiniciar automaticamente instâncias Lightsail sem a necessidade de acessar <code>ssh</code> ou fazer qualquer configuração dentro da instância, minimizando qualquer problema, desta forma nosso Cloudwatch Event Rules possui um agendamento, e então no momento definido invocará nossa função lambda que possui permissões necessárias para reiniciar a instância Lightsail.</p>
<p>Além disso essa é uma solução barata, pois Cloudwatch Event Rules e Lambda possuem bons níveis gratuitos, por exemplo o Lambda possui até um milhão de requisições gratuitas por mês.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Espero que essas informações tenham sido úteis para você!</div>
</div>]]></content:encoded></item><item><title><![CDATA[SimplesCloud - Séries]]></title><description><![CDATA[DevOps • SRE


AWS]]></description><link>https://simplescloud.com.br/series</link><guid isPermaLink="true">https://simplescloud.com.br/series</guid><dc:creator><![CDATA[SimplesCloud]]></dc:creator><pubDate>Wed, 21 Sep 2022 18:27:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1663784234441/TjW8lsqOt.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-devops-sre">DevOps • SRE</h2>
<p><a target="_blank" href="https://simplescloud.io/devops-sre"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706908888445/65422ddd-b753-4518-aa6f-a278256157c2.png" alt class="image--center mx-auto" /></a></p>
<hr />
<h2 id="heading-aws">AWS</h2>
<p><a target="_blank" href="https://simplescloud.io/aws"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686942159994/24c232b8-63fa-43dd-9d33-8f04a3cca3d8.png" alt class="image--center mx-auto" /></a></p>
]]></content:encoded></item><item><title><![CDATA[VSCode - Instalação e Configuração]]></title><description><![CDATA[Introdução
Personalizar seu ambiente de desenvolvimento é uma jornada única para cada pessoa. É aquele toque especial que torna as longas horas de código mais agradáveis e produtivas. E é exatamente sobre isso que vamos conversar hoje!
Vou guiá-lo at...]]></description><link>https://simplescloud.com.br/vscode-instalacao-configuracao</link><guid isPermaLink="true">https://simplescloud.com.br/vscode-instalacao-configuracao</guid><category><![CDATA[vscode]]></category><dc:creator><![CDATA[SimplesCloud]]></dc:creator><pubDate>Wed, 14 Sep 2022 20:50:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730759383850/10b93cb6-af21-4278-8a16-611937a39b8b.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<hr />
<h2 id="heading-introducao">Introdução</h2>
<p>Personalizar seu ambiente de desenvolvimento é uma jornada única para cada pessoa. É aquele toque especial que torna as longas horas de código mais agradáveis e produtivas. E é exatamente sobre isso que vamos conversar hoje!</p>
<p>Vou guiá-lo através da minha experiência pessoal de customização do VSCode, compartilhando cada passo e configuração que implementei para criar um ambiente que funciona perfeitamente para mim. Mas lembre-se: isso é apenas um ponto de partida, um mapa que você pode usar para explorar suas próprias preferências.</p>
<p>Afinal, não existe certo ou errado quando falamos de personalização - o que importa é criar um ambiente que reflita seu estilo e otimize seu fluxo de trabalho. Seja nas escolhas de temas, extensões, atalhos de teclado ou configurações do editor, você terá total liberdade para adaptar essas sugestões ao seu gosto.</p>
<p>E para facilitar ainda mais sua jornada, ao final deste artigo, compartilharei meus arquivos de configuração completos do VSCode, incluindo minhas extensões favoritas e seus ajustes. Assim, você poderá usá-los como referência ou ponto de partida para criar seu próprio ambiente de desenvolvimento único e personalizado.</p>
<p>Vamos começar?</p>
<hr />
<h2 id="heading-o-que-e-vscode">O que é VSCode?</h2>
<p>O Visual Studio Code (VSCode) é um editor de código aberto desenvolvido pela Microsoft, atualmente ele é um dos editores de código mais utilizados no mundo.</p>
<hr />
<h2 id="heading-nao-confunda-vscode-com-o-visual-studio">Não confunda VSCode com o Visual Studio</h2>
<p>O Visual Studio é uma IDE desenvolvida pela Microsoft, dedicada ao <code>.NET Framework</code> e a linguagens como <code>C</code>, <code>C++</code>, <code>C#</code> e <code>F#</code>. Por ser uma solução completa, é uma ferramenta bem mais pesada. Já o <code>VSCode</code> é um editor de código poderoso com vários plugins disponíveis.</p>
<hr />
<h2 id="heading-instalando-o-vscode">Instalando o VSCode</h2>
<p>1- Faça o download do <code>Visual Studio Code</code> no site oficial da Microsoft:</p>
<ul>
<li>👉 <a target="_blank" href="https://code.visualstudio.com/download">https://code.visualstudio.com/download</a></li>
</ul>
<p>E siga com a instalação <code>Próximo</code> → <code>Próximo</code> → <code>Concluir</code> para essa pasta criada</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text"><strong>ATENÇÃO:</strong> Instale no <code>Windows</code> e certifique-se que a opção <code>ADICIONAR AO PATH</code> esteja marcada</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662933227106/wnPmdCtOS.png" alt="image.png" class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-instalando-plugins-locais">Instalando Plugins Locais</h2>
<h3 id="heading-remote-development">Remote Development</h3>
<p>Pacote que acompanha três plugins:</p>
<ul>
<li><p><code>Remote WSL</code></p>
</li>
<li><p><code>Remote SSH</code></p>
</li>
<li><p><code>Remote Container</code></p>
</li>
</ul>
<p>Útil e obrigatório para permitir que você use um ambiente de desenvolvimento completo com containers e WSL2.</p>
<p>1- Em seu <code>VSCode</code> → clique em <code>Extensões</code> → digite <code>remote development</code> → clique em <code>Instalar</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662933590461/QYGeTyPav.png" alt="image.png" class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-material-icon">Material Icon</h3>
<p>Útil para tornar os ícones em geral mais agradáveis.</p>
<p>1- Em seu <code>VSCode</code> → clique em <code>Extensões</code> → digite <code>material icon</code> → clique em <code>Instalar</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662934583286/Wr0teXkA_.png" alt="image.png" class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-instalando-o-vscode-no-wsl2">Instalando o VSCode no WSL2</h2>
<p>1- Abra seu <code>VSCode</code> → clique no ícone verde <code>&gt;&lt;</code> (canto inferior esquerdo) → escolha a opção <code>Usando um distro existente</code> → selecione a distro e aguarde a instalação ser concluída</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662933860636/T7V_IB_39.png" alt="image.png" class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong>Dica:</strong> Caso o passo acima não ocorra, abra o terminal do linux → vá até a pasta que preferir instalar o <code>VSCode</code> → digite <code>code .</code> (com espaço e ponto mesmo). Ao fazer isso pela primeira vez, você deve ver os componentes de busca do VSCode necessários para executar no WSL2. Isso deve demorar um pouco e é necessário apenas uma vez.</div>
</div>

<hr />
<h2 id="heading-instalando-plugins-no-wsl2">Instalando Plugins no WSL2</h2>
<h3 id="heading-docker">Docker</h3>
<p>Útil para criar e gerenciar imagens e containers Docker, também pode ajudar a criar o Dockerfile.</p>
<p>1- Em seu <code>VSCode</code> → clique em <code>Extensões</code> → digite <code>docker</code> → clique em <code>Instalar</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662933712304/95j9MQbhp.png" alt="image.png" class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-hashicorp-terraform">Hashicorp Terraform</h3>
<p>Hashicorp Terraform é uma ferramenta incrível de Infra As Code, esse plugin ajudará em sua sintaxe.</p>
<p>1- Em seu <code>VSCode</code> → clique em <code>Extensões</code> → digite <code>hashicorp terraform</code> → clique em <code>Instalar</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662934327966/sWLPl10BV.png" alt="image.png" class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-opentofu">OpenTofu</h3>
<p>OpenTofu é uma ferramenta incrível de Infra As Code, baseado e inspirado no Terraform, é um fork do Terraform desde sua mudança de licenciamento, tornando-o um projeto open source. Esse plugin ajudará em sua sintaxe.</p>
<p>1- Em seu <code>VSCode</code> → clique em <code>Extensões</code> → digite <code>opentofu</code> → clique em <code>Instalar</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730493512983/cbbe4f95-c2c8-4d70-b718-400be060de96.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-kubernetes">Kubernetes</h3>
<p>Útil para criar e gerenciar containers com Kubernetes, também pode ajudar nas sintaxes dos arquivos de configurações.</p>
<p>1- Em seu <code>VSCode</code> → clique em <code>Extensões</code> → digite <code>kubernetes</code> → clique em <code>Instalar</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712611634225/1ace45e4-3181-4b77-ae31-49a83e3a5511.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-yaml">YAML</h3>
<p>Útil para verificar as sintaxes deste tipo de arquivo.</p>
<p>1- Em seu <code>VSCode</code> → clique em <code>Extensões</code> → digite <code>yaml</code> → clique em <code>Instalar</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712611705211/4ff292bf-708a-43c0-bf35-f93eb23929d8.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-instalando-tema">Instalando Tema</h2>
<h3 id="heading-codestackr-theme">codeSTACKr Theme</h3>
<p>Há muitos temas por aí, mas particularmente me adaptei bem com esse excelente tema criado, suas cores padrões já fazem todo o trabalho, apenas fiz poucos ajustes nas cores que compartilho em meu arquivo <code>settings.json</code> no final deste artigo.</p>
<p>1- Em seu <code>VSCode</code> → clique em <code>Extensões</code> → digite <code>codestack</code> → clique em <code>Instalar</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662934869283/k0sUeiyXF.png" alt="image.png" class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-night-owl-theme"><strong>Night Owl</strong> Theme</h3>
<p>Outro tema que gosto bastante de usar é o Night Owl, suas cores padrões já fazem todo o trabalho, apenas fiz poucos ajustes nas cores que compartilho em meu arquivo <code>settings.json</code> no final deste artigo.</p>
<p>1- Em seu <code>VSCode</code> → clique em <code>Extensões</code> → digite <code>Night Owl</code> → clique em <code>Instalar</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730493309680/2846e76f-1b7f-4895-8e22-627c9a86d344.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-meu-arquivo-settingsjson">Meu arquivo <code>settings.json</code></h2>
<p>Compartilho meu arquivo <code>settings.json</code> para se por acaso você queira usar o VSCode exatamente como eu, basta copiar e colar. Além de ser uma forma que posso consultar aqui para sempre restaurar quando eu precisar.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730494138670/47d67101-ba38-40ce-9ad6-1acf7a7c0ad6.png" alt class="image--center mx-auto" /></p>
<p>1- Abra o VSCode → aperte <code>F1</code> no teclado → <code>Preferences Open User Settings (JSON)</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712611961604/a3d74789-d3de-4c62-92e6-d80cb7a5c8b4.png" alt class="image--center mx-auto" /></p>
<p>2- Copie e cole o conteúdo abaixo e salve seu arquivo</p>
<blockquote>
<p>⚠️ <mark>Importante:</mark> Ao aplicar estas configurações no VSCode, você precisará adaptar alguns campos específicos para o seu ambiente de desenvolvimento:</p>
<ul>
<li><p><code>terminal.integrated.defaultProfile</code>: Define qual terminal será iniciado automaticamente</p>
</li>
<li><p><code>workbench.colorCustomizations</code>: Permite personalizar as cores da sua interface</p>
</li>
<li><p><code>editor.fontFamily</code>: Especifica qual fonte será utilizada no editor</p>
</li>
</ul>
<p>Abaixo você encontrará um exemplo completo dessas configurações, que serve como um ponto de partida para sua personalização. Sinta-se à vontade para ajustar cada campo de acordo com suas preferências e necessidades de desenvolvimento.</p>
</blockquote>
<pre><code class="lang-json"><span class="hljs-comment">// SimplesCloud VSCode settings.json</span>

{

    <span class="hljs-comment">// Integrated Terminal Settings</span>
    <span class="hljs-attr">"terminal.integrated.defaultProfile.linux"</span>: <span class="hljs-string">"zsh"</span>,
    <span class="hljs-attr">"terminal.integrated.defaultLocation"</span>: <span class="hljs-string">"editor"</span>,
    <span class="hljs-attr">"terminal.integrated.fontSize"</span>: <span class="hljs-number">16</span>,
    <span class="hljs-attr">"terminal.integrated.fontFamily"</span>: <span class="hljs-string">"SauceCodePro Nerd Font"</span>,

    <span class="hljs-comment">// Theme and Appearance</span>
    <span class="hljs-attr">"workbench.colorTheme"</span>: <span class="hljs-string">"Night Owl"</span>,
    <span class="hljs-attr">"workbench.iconTheme"</span>: <span class="hljs-string">"material-icon-theme"</span>,
    <span class="hljs-attr">"workbench.startupEditor"</span>: <span class="hljs-string">"none"</span>,

    <span class="hljs-comment">// Color Customization</span>
    <span class="hljs-attr">"workbench.colorCustomizations"</span>: {
        <span class="hljs-comment">// VSCode Interface</span>
        <span class="hljs-attr">"editorLineNumber.activeForeground"</span>: <span class="hljs-string">"#49E287"</span>,
        <span class="hljs-attr">"statusBarItem.remoteBackground"</span>: <span class="hljs-string">"#000000"</span>,
        <span class="hljs-attr">"statusBarItem.remoteForeground"</span>: <span class="hljs-string">"#49E287"</span>,
        <span class="hljs-attr">"menu.selectionBackground"</span>: <span class="hljs-string">"#000000"</span>,
        <span class="hljs-attr">"menu.selectionForeground"</span>: <span class="hljs-string">"#49E287"</span>,
        <span class="hljs-attr">"tab.activeBorder"</span>: <span class="hljs-string">"#49E287"</span>,
        <span class="hljs-attr">"list.highlightForeground"</span>: <span class="hljs-string">"#FFE400"</span>,
        <span class="hljs-attr">"list.activeSelectionBackground"</span>: <span class="hljs-string">"#000000"</span>,
        <span class="hljs-attr">"list.activeSelectionForeground"</span>: <span class="hljs-string">"#49E287"</span>,
        <span class="hljs-attr">"focusBorder"</span>: <span class="hljs-string">"#49E287"</span>,

        <span class="hljs-comment">// Notifications</span>
        <span class="hljs-attr">"notifications.background"</span>: <span class="hljs-string">"#000000"</span>,
        <span class="hljs-attr">"notifications.foreground"</span>: <span class="hljs-string">"#49E287"</span>,
        <span class="hljs-attr">"notificationLink.foreground"</span>: <span class="hljs-string">"#49E287"</span>,
        <span class="hljs-attr">"notificationsInfoIcon.foreground"</span>: <span class="hljs-string">"#49E287"</span>,

        <span class="hljs-comment">// Terminal Colors</span>
        <span class="hljs-attr">"terminal.background"</span>: <span class="hljs-string">"#011627"</span>,
        <span class="hljs-attr">"terminal.foreground"</span>: <span class="hljs-string">"#dddad6"</span>,
        <span class="hljs-attr">"terminal.ansiBlack"</span>: <span class="hljs-string">"#011627"</span>,
        <span class="hljs-attr">"terminal.ansiBrightBlack"</span>: <span class="hljs-string">"#575656"</span>,
        <span class="hljs-attr">"terminal.ansiBrightBlue"</span>: <span class="hljs-string">"#82AAFF"</span>,
        <span class="hljs-attr">"terminal.ansiBrightCyan"</span>: <span class="hljs-string">"#7FDBCA"</span>,
        <span class="hljs-attr">"terminal.ansiBrightGreen"</span>: <span class="hljs-string">"#22DA6E"</span>,
        <span class="hljs-attr">"terminal.ansiBrightPurple"</span>: <span class="hljs-string">"#C792EA"</span>,
        <span class="hljs-attr">"terminal.ansiBrightRed"</span>: <span class="hljs-string">"#EF5350"</span>,
        <span class="hljs-attr">"terminal.ansiBrightWhite"</span>: <span class="hljs-string">"#FFFFFF"</span>,
        <span class="hljs-attr">"terminal.ansiBrightYellow"</span>: <span class="hljs-string">"#FFEB95"</span>,
        <span class="hljs-attr">"terminal.ansiBlue"</span>: <span class="hljs-string">"#82AAFF"</span>,
        <span class="hljs-attr">"terminal.ansiCyan"</span>: <span class="hljs-string">"#21C7A8"</span>,
        <span class="hljs-attr">"terminal.ansiGreen"</span>: <span class="hljs-string">"#22DA6E"</span>,
        <span class="hljs-attr">"terminal.ansiPurple"</span>: <span class="hljs-string">"#C792EA"</span>,
        <span class="hljs-attr">"terminal.ansiRed"</span>: <span class="hljs-string">"#EF5350"</span>,
        <span class="hljs-attr">"terminal.ansiWhite"</span>: <span class="hljs-string">"#FFFFFF"</span>,
        <span class="hljs-attr">"terminal.ansiYellow"</span>: <span class="hljs-string">"#ADDB67"</span>
    },

    <span class="hljs-comment">// Editor Settings</span>
    <span class="hljs-attr">"editor.guides.bracketPairs"</span>: <span class="hljs-string">"active"</span>,
    <span class="hljs-attr">"editor.fontFamily"</span>: <span class="hljs-string">"SauceCodePro Nerd Font"</span>,
    <span class="hljs-attr">"editor.fontSize"</span>: <span class="hljs-number">16</span>,
    <span class="hljs-attr">"editor.fontLigatures"</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">"editor.minimap.enabled"</span>: <span class="hljs-literal">false</span>,
    <span class="hljs-attr">"editor.wordWrap"</span>: <span class="hljs-string">"on"</span>,
    <span class="hljs-attr">"editor.tabSize"</span>: <span class="hljs-number">4</span>,
    <span class="hljs-attr">"editor.cursorBlinking"</span>: <span class="hljs-string">"expand"</span>,
    <span class="hljs-attr">"editor.cursorStyle"</span>: <span class="hljs-string">"block"</span>,

    <span class="hljs-comment">// Explorer Settings</span>
    <span class="hljs-attr">"explorer.confirmDragAndDrop"</span>: <span class="hljs-literal">false</span>,
    <span class="hljs-attr">"explorer.compactFolders"</span>: <span class="hljs-literal">false</span>,

    <span class="hljs-comment">// Terraform and Terragrunt Specific Settings</span>
    <span class="hljs-attr">"[terraform]"</span>: {
        <span class="hljs-attr">"editor.formatOnSave"</span>: <span class="hljs-literal">true</span>
    },
    <span class="hljs-attr">"[terragrunt]"</span>: {
        <span class="hljs-attr">"editor.formatOnSave"</span>: <span class="hljs-literal">true</span>
    },

    <span class="hljs-comment">// Git Settings</span>
    <span class="hljs-attr">"git.enableSmartCommit"</span>: <span class="hljs-literal">true</span>,

    <span class="hljs-comment">// Miscellaneous Settings</span>
    <span class="hljs-attr">"hediet.vscode-drawio.theme"</span>: <span class="hljs-string">"atlas"</span>,
    <span class="hljs-attr">"window.zoomLevel"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"extensions.ignoreRecommendations"</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">"breadcrumbs.enabled"</span>: <span class="hljs-literal">false</span>,
    <span class="hljs-attr">"editor.stickyScroll.enabled"</span>: <span class="hljs-literal">false</span>,

    <span class="hljs-comment">/* Custom Dracula Theme (Commented)
    To use Dracula theme with custom colors, 
    uncomment this block and comment out the 
    workbench.colorCustomizations above */</span>

    <span class="hljs-comment">// "workbench.colorCustomizations": {</span>
    <span class="hljs-comment">//     // Interface</span>
    <span class="hljs-comment">//     "activityBar.background": "#000000",</span>
    <span class="hljs-comment">//     "activityBar.foreground": "#3884ff",</span>
    <span class="hljs-comment">//     "activityBar.inactiveForeground": "#ffffff",</span>
    <span class="hljs-comment">//     "sideBar.background": "#13121b",</span>
    <span class="hljs-comment">//     "sideBarSectionHeader.background": "#191622",</span>
    <span class="hljs-comment">//     "sideBar.foreground": "#dadada",</span>
    <span class="hljs-comment">//     "editor.background": "#1c1e27",</span>
    <span class="hljs-comment">//     "titleBar.activeBackground": "#191622",</span>

    <span class="hljs-comment">//     // Dropdowns and Inputs</span>
    <span class="hljs-comment">//     "dropdown.background": "#191622",</span>
    <span class="hljs-comment">//     "dropdown.listBackground": "#191622",</span>
    <span class="hljs-comment">//     "dropdown.border": "#191622",</span>
    <span class="hljs-comment">//     "dropdown.foreground": "#dadada",</span>
    <span class="hljs-comment">//     "titleBar.activeForeground": "#dadada",</span>
    <span class="hljs-comment">//     "input.background": "#191622",</span>

    <span class="hljs-comment">//     // Panels and Tabs</span>
    <span class="hljs-comment">//     "panel.background": "#191622",</span>
    <span class="hljs-comment">//     "panel.border": "#3884ff",</span>
    <span class="hljs-comment">//     "panelTitle.activeBorder": "#b470a0",</span>
    <span class="hljs-comment">//     "panelTitle.inactiveForeground": "#0078d4",</span>
    <span class="hljs-comment">//     "badge.background": "#0078d4",</span>

    <span class="hljs-comment">//     // Editor</span>
    <span class="hljs-comment">//     "editorCursor.foreground": "#FFE400",</span>
    <span class="hljs-comment">//     "editorCursor.background": "#000000",</span>
    <span class="hljs-comment">//     "editor.lineHighlightBorder": "#1c1e27",</span>
    <span class="hljs-comment">//     "editor.selectionBackground": "#393744",</span>
    <span class="hljs-comment">//     "editor.wordHighlightBackground": "#000000",</span>
    <span class="hljs-comment">//     "editor.wordHighlightStrongBackground": "#000000",</span>

    <span class="hljs-comment">//     // Status Bar and Breadcrumbs</span>
    <span class="hljs-comment">//     "statusBarItem.remoteBackground": "#1e9b0d",</span>
    <span class="hljs-comment">//     "statusBarItem.remoteForeground": "#ffffff",</span>
    <span class="hljs-comment">//     "breadcrumb.foreground": "#0078d4",</span>
    <span class="hljs-comment">//     "breadcrumb.background": "#191622",</span>

    <span class="hljs-comment">//     // Tabs</span>
    <span class="hljs-comment">//     "tab.activeBackground": "#000000",</span>
    <span class="hljs-comment">//     "tab.inactiveBackground": "#191622",</span>
    <span class="hljs-comment">//     "tab.activeForeground": "#0078d4",</span>
    <span class="hljs-comment">//     "tab.inactiveForeground": "#0078d4",</span>

    <span class="hljs-comment">//     // Terminal</span>
    <span class="hljs-comment">//     "terminal.background": "#1d2033",</span>
    <span class="hljs-comment">//     "terminal.foreground": "#ffffff",</span>
    <span class="hljs-comment">//     "terminalCursor.background": "#E9E9F4",</span>
    <span class="hljs-comment">//     "terminalCursor.foreground": "#E9E9F4",</span>
    <span class="hljs-comment">//     "terminal.ansiBlack": "#282936",</span>
    <span class="hljs-comment">//     "terminal.ansiBlue": "#0717ff",</span>
    <span class="hljs-comment">//     "terminal.ansiBrightBlack": "#626483",</span>
    <span class="hljs-comment">//     "terminal.ansiBrightBlue": "#62D6E8",</span>
    <span class="hljs-comment">//     "terminal.ansiBrightCyan": "#A1EFE4",</span>
    <span class="hljs-comment">//     "terminal.ansiBrightGreen": "#EBFF87",</span>
    <span class="hljs-comment">//     "terminal.ansiBrightMagenta": "#B45BCF",</span>
    <span class="hljs-comment">//     "terminal.ansiBrightRed": "#ff0909",</span>
    <span class="hljs-comment">//     "terminal.ansiBrightWhite": "#F7F7FB",</span>
    <span class="hljs-comment">//     "terminal.ansiBrightYellow": "#00F769",</span>
    <span class="hljs-comment">//     "terminal.ansiCyan": "#A1EFE4",</span>
    <span class="hljs-comment">//     "terminal.ansiGreen": "#49E287",</span>
    <span class="hljs-comment">//     "terminal.ansiMagenta": "#B45BCF",</span>
    <span class="hljs-comment">//     "terminal.ansiRed": "#ff0909",</span>
    <span class="hljs-comment">//     "terminal.ansiWhite": "#E9E9F4",</span>
    <span class="hljs-comment">//     "terminal.ansiYellow": "#00F769"</span>
    <span class="hljs-comment">// }</span>
}
</code></pre>
<hr />
<h2 id="heading-conclusao">Conclusão</h2>
<p>Demonstrei como instalei e configurei o <code>VSCode</code>, fizemos inicialmente a instalação no próprio <code>Windows</code> certificando de marcar a opção de adicionar ao <code>Path</code>, depois instalamos no <code>Linux</code> através do <code>WSL2</code> e passamos brevemente por algumas extensões que estou usando.</p>
<p>Por fim, compartilhei meu arquivo <code>settings.json</code> para que se um dia eu precisar restaurar, possa consultar aqui e recuperar, além disso fica disponível para você se desejar fazer uma configuração semelhante.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Espero que as informações tenham sido úteis para você!</div>
</div>]]></content:encoded></item><item><title><![CDATA[Configure SSH para o Bitbucket, GitLab ou GitHub]]></title><description><![CDATA[Introdução

ℹ
Há muitas hospedagens disponíveis para controle de versão como GitLab, GitHub e Bitbucket, todos possuem prós e contras, não abordarei essas diferenças neste artigo, mas focarei na configuração das chaves SSH para eles. Também abordarei...]]></description><link>https://simplescloud.com.br/configure-ssh-para-bitbucket-gitlab-github</link><guid isPermaLink="true">https://simplescloud.com.br/configure-ssh-para-bitbucket-gitlab-github</guid><category><![CDATA[SSH Git]]></category><category><![CDATA[Git]]></category><category><![CDATA[Bitbucket]]></category><category><![CDATA[GitLab]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[ssh]]></category><dc:creator><![CDATA[SimplesCloud]]></dc:creator><pubDate>Wed, 14 Sep 2022 20:49:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1669641636942/BpbDSkA14.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introducao">Introdução</h2>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Há muitas hospedagens disponíveis para controle de versão como <strong>GitLab</strong>, <strong>GitHub</strong> e <strong>Bitbucket</strong>, todos possuem prós e contras, não abordarei essas diferenças neste artigo, mas focarei na configuração das chaves SSH para eles. Também abordarei como adicionar várias chaves SSH para várias contas diferentes.</div>
</div>

<hr />
<h2 id="heading-criar-uma-chave-ssh">Criar uma Chave SSH</h2>
<p>Antes de qualquer coisa, precisamos e queremos criar nossa chave SSH.<br />Essa etapa pode ser repetida quantas vezes você preferir.</p>
<p>1- Abra seu terminal e crie uma pasta chamada <code>.ssh</code></p>
<pre><code class="lang-bash">mkdir .ssh
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663001732792/yud7Wc_tF.png" alt="image.png" class="image--center mx-auto" /></p>
<p>2- Acesse a pasta <code>.ssh</code> que acabamos de criar:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> ~/.ssh
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663001761005/q2eeksEXs.png" alt="image.png" class="image--center mx-auto" /></p>
<p>3- Gere uma chave SSH com o comando:</p>
<blockquote>
<p>⚠️ <strong>Substitua no comando abaixo:</strong><br /><strong>- "example@simplescloud.io"</strong> para um email de sua preferência<br /><strong>- bitbucket_simplescloud_account_example</strong> para o nome da chave SSH de sua preferência</p>
<p>Não preencha nenhuma pergunta solicitada no terminal → apenas pressione <strong>Enter</strong></p>
</blockquote>
<pre><code class="lang-bash">ssh-keygen -t rsa -b 4096 -C <span class="hljs-string">"example@simplescloud.io"</span> -f bitbucket_simplescloud_account_example
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669643144839/wj6uBquVh.png" alt="image.png" class="image--center mx-auto" /></p>
<p>4- Em nosso exemplo, podemos ver que nesse momento foram gerados dois arquivos:</p>
<ul>
<li><p><code>bitbucket_simplescloud_account_example</code> → chave privada e que não deve ser compartilhada com ninguém</p>
</li>
<li><p><code>bitbucket_simplescloud_account_example.pub</code> → chave pública que precisaremos para os próximos passos</p>
</li>
</ul>
<p>Então é hora de copiarmos o conteúdo de nossa chave pública, você pode fazer isso de várias formas, mas prefiro usar o comando <code>copyfile</code> para isso.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong>Dica:</strong> veja como habilitar o plugin <code>copyfile</code> em nosso artigo 👉 <a target="_blank" href="https://simplescloud.io/vscode">aqui</a></div>
</div>

<p>Então acesse <code>~/.ssh</code> → copie o conteúdo da sua chave pública <code>bitbucket_simplescloud_account_example.pub</code> com o comando <code>copyfile</code></p>
<pre><code class="lang-bash">copyfile ~/.ssh/bitbucket_simplescloud_account_example.pub
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669643743321/wt2fiwNY9.png" alt="image.png" class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">☑</div>
<div data-node-type="callout-text">Pronto! Você já criou sua chave SSH e está com o conteúdo de sua chave pública copiada, agora falta apenas colar ela na conta da hospedagem de controle de versão git de sua preferência, embora o conceito seja o mesmo para todas, pode ser que algumas telas sejam diferentes de uma para outra, então passaremos por alguns exemplos.</div>
</div>

<hr />
<h2 id="heading-configurando-o-ssh-no-bitbucket">Configurando o SSH no Bitbucket</h2>
<p>1- Acesse sua conta do <code>Bitbucket</code> → canto superior direito na sua foto ou avatar → <code>Personal Settings</code> → <code>SSH Keys</code> → <code>Add Key</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669644273554/YvP484UWQ.png" alt="image.png" class="image--center mx-auto" /></p>
<p>2- No campo <code>Label</code> defina um nome fácil de você identificar e no campo <code>Key</code> cole o conteúdo da sua chave pública copiada → <code>Add Key</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669644466205/bnMZ_WVXC.png" alt="image.png" class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-configurando-o-ssh-no-gitlab">Configurando o SSH no GitLab</h2>
<p>1- Acesse sua conta do <code>GitLab</code> → <code>Edit Profile</code> → <code>SSH Keys</code> e cole o conteúdo da sua chave pública → defina um nome de sua preferência → não preencha o campo de data → clique em <code>Add key</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663002104338/2sTaJHUyJ.png" alt="image.png" class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-configurando-o-ssh-no-github">Configurando o SSH no GitHub</h2>
<p>1- Acesse sua conta do <code>GitHub</code> → canto superior direito na sua foto ou avatar → <code>Settings</code> → <code>SSH and GPG Keys</code> → <code>New SSH Key</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669654635114/XbrQT2ZYy.png" alt="image.png" class="image--center mx-auto" /></p>
<p>2- No campo <code>Title</code> defina um nome fácil de você identificar, no campo <code>Key Type</code> deixe como <code>Authentication Key</code> e no campo <code>Key</code> cole o conteúdo da sua chave pública copiada → <code>Add SSH Key</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669654890004/V5uRRMcPc.png" alt="image.png" class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-multiplas-chaves-ssh-para-multiplas-contas">Múltiplas Chaves SSH para Múltiplas Contas</h2>
<p>Agora que já vimos como gerar chaves SSH e adiciona-las nas hospedagens de controle de versões git de sua preferência, é muito provável que em algum momento, você seja adicionado em um projeto, queira criar uma conta, clonar o repositório e esmagar algum código.</p>
<p>Porém não é tão fácil como parece, para a maioria dos repositórios git como GitLab, GitHub e Bitbucket, acontecerá uma mensagem de erro parecida com:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text"><strong>"Someone has already added that SSH key", </strong>ou traduzindo<strong>, "Alguém já adicionou essa chave SSH"</strong></div>
</div>

<p>Essa é uma mensagem um pouco frustrante, pois inicialmente parece fazer sentido querermos usar nossa mesma chave SSH que já temos para uma outra conta recém-criada. Mas não é assim que funciona, explicando melhor essa mensagem diz que sua chave SSH já está adicionada em outra conta, então na prática não podemos "reaproveitar" a mesma chave SSH que você gerou e adicionou na conta Bitbucket pessoal como também em uma segunda conta Bitibucket que você tenha criado por exemplo.</p>
<p>Felizmente há uma solução simples e se aplica da mesma forma para qualquer serviço de hospedagem de controle de versão como <code>GitLab</code> e <code>GitHub</code>, mas para não ficar repetitivo, usarei um passo a passo com o <code>Bitbucket</code>.</p>
<hr />
<h3 id="heading-gere-varias-chaves-ssh">Gere várias chaves SSH</h3>
<p>Se não podemos usar a mesma chave SSH em várias contas, a solução então é ter várias chaves SSH diferentes. Para esse exemplo, vamos criar:</p>
<ul>
<li><p><strong>Chave SSH Pessoal</strong></p>
</li>
<li><p><strong>Chave SSH para o Projeto do Cliente</strong></p>
</li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">☑</div>
<div data-node-type="callout-text">Sem novidades até aqui, basta seguir os passos iniciais deste artigo e gerar chaves SSH com nomes diferentes!</div>
</div>

<hr />
<h3 id="heading-adicione-as-chaves-ssh-ao-agente">Adicione as chaves SSH ao Agente</h3>
<p>Aqui começam as dicas legais, para fazer uso das chaves SSH recém-criadas, precisamos adicioná-las ao <code>ssh-agent</code> que nada mais é do que um programa nativo que contém as chaves privadas usadas para a autenticação pública.</p>
<p>O <code>ssh-agent</code> provavelmente já está sendo executado em segundo plano no seu sistema operacional, mas por precaução vamos verificar com o comando:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">eval</span> <span class="hljs-string">"<span class="hljs-subst">$(ssh-agent -s)</span>"</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669646753539/D41B-t11k.png" alt="image.png" class="image--center mx-auto" /></p>
<p>E adicionando novas chaves SSH usando o comando <code>ssh-add</code>.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Lembre-se de substituir alguns valores do exemplo abaixo para valores reais que você usa.</div>
</div>

<pre><code class="lang-bash">ssh-add ~/.ssh/key_name_personal
ssh-add ~/.ssh/key_name_client
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669646854304/dE7mU1mYU.png" alt="image.png" class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-torne-as-alteracoes-permanentes">Torne as alterações permanentes</h3>
<p>Estamos caminhando bem, mas você notará que os passos acima se tornam repetitivos cada vez que abrir o terminal, vamos melhorar isso tornando essas alterações permanentes.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong>Dica:</strong> uso o <code>Zsh Shell</code> e nossos passos serão através dele, veja mais detalhes sobre o <code>Zsh Shell</code> em nosso artigo 👉 <a target="_blank" href="https://simplescloud.io/windows-terminal#heading-instalando-o-zsh-shell-no-wsl2">aqui</a></div>
</div>

<p>1- Em seu terminal digite o comando:</p>
<pre><code class="lang-bash">sudo nano ~/.zshrc
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669647499883/I6TKRFfuU.png" alt="image.png" class="image--center mx-auto" /></p>
<p>2- Vá para o final do arquivo de configuração do <code>Zsh Shell</code> e adicione os comandos que estávamos fazendo manualmente a cada vez que abríamos o terminal + <code>&amp;&gt; /dev/null</code> ao final para evitar algum output e "travar" a exibição inicial do terminal, ou seja:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">eval</span> <span class="hljs-string">"<span class="hljs-subst">$(ssh-agent -s)</span>"</span> &amp;&gt; /dev/null
ssh-add ~/.ssh/bitbucket_personal_account_wsl2 &amp;&gt; /dev/null
ssh-add ~/.ssh/bitbucket_simplescloud_account_wsl2 &amp;&gt; /dev/null
</code></pre>
<p>Pressione <code>Ctrl + X</code> → <code>Y</code> → <code>Enter</code> para salvar as alterações</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669647694514/MiSZTZkYB.png" alt="image.png" class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-configure-o-ssh">Configure o SSH</h3>
<p>Estamos quase lá, como etapa final, aqui no arquivo de configuração do SSH é que está toda a mágica! Precisamos criar um arquivo de configuração (se você ainda não o tiver) e criar os <code>aliases</code> ou "apelidos" personalizados que irão impor o uso ou uma chave SSH específica para um determinado host. Então vamos fazer isso!</p>
<p>1- Digite o comando:</p>
<pre><code class="lang-bash">sudo nano ~/.ssh/config
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669648062151/QT9KlLGxK.png" alt="image.png" class="image--center mx-auto" /></p>
<p>2- Edite o arquivo conforme o exemplo. Lembre-se de pressionar <code>Ctrl + X</code> → <code>Y</code> → <code>Enter</code> para salvar as alterações</p>
<pre><code class="lang-bash">Host bitbucket-personal.org
  HostName bitbucket.org
  User git
  IdentityFile ~/.ssh/bitbucket_personal_account_wsl2
  IdentitiesOnly yes

Host bitbucket-simplescloud.org
  HostName bitbucket.org
  User git
  IdentityFile ~/.ssh/bitbucket_simplescloud_account_wsl2
  IdentitiesOnly yes
</code></pre>
<p>De agora em diante, toda vez que você clonar um repositório de conta do cliente, simplesmente substitua <code>bitbucket.com</code> por <code>bitbucket-client</code>, por exemplo:</p>
<pre><code class="lang-bash">❌ git <span class="hljs-built_in">clone</span> git@bitbucket.org:client/project.git
✅ git <span class="hljs-built_in">clone</span> git@bitbucket-simplescloud.org:client/project.git
</code></pre>
<p>Ao fazer isso, você está ignorando uma resolução de chave pública padrão e apontando explicitamente <code>ssh-agent</code> para sempre resolver a conexão <code>bitbucket-client.org</code> usando a <code>~/.ssh/bitbucket_simplescloud_account_wsl2</code> em nosso exemplo.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">☑</div>
<div data-node-type="callout-text">Sua chave padrão funcionará como antes. Truque legal, não é? 🥳</div>
</div>

<hr />
<h3 id="heading-altere-a-url-upstream-do-repositorio-ja-existente">Altere a URL upstream do repositório já existente</h3>
<p>Você pode estar se perguntando o que fazer com os repositórios já existentes. Clonar todos eles um por um não parece divertido. Não é e tem solução!</p>
<p>Para alterar uma URL do repositório atualmente existente, use o comando <code>git remote set-url</code>, por exemplo:</p>
<pre><code class="lang-bash">git remote set-url origin git@bitbucket-simplescloud.org:client/project.git
</code></pre>
<hr />
<h3 id="heading-testando-a-conexao">Testando a Conexão</h3>
<p>Além do comando:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">eval</span> <span class="hljs-string">"<span class="hljs-subst">$(ssh-agent -s)</span>"</span>
</code></pre>
<p>Já citado para verificar se o <code>ssh-agent</code> está em execução, outro comando que pode ser muito útil é o:</p>
<pre><code class="lang-bash">ssh -T git@bitbucket-simplescloud.org
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669648853576/I7C2NFKf8.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Observe que no comando já estamos usando o <code>bitbucket-simplescloud.org</code> que é o <code>alias</code> ou "apelido" configurado no arquivo <code>~/.ssh/config</code>. Desta forma conseguimos testar que a conexão foi realizada com sucesso.</p>
<hr />
<h2 id="heading-conclusao">Conclusão</h2>
<p>Esta solução resolveu o meu problema e atendeu bem.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Espero que essas informações tenham sido úteis para você!</div>
</div>]]></content:encoded></item><item><title><![CDATA[JQ - Instalação e Explicação]]></title><description><![CDATA[https://youtu.be/ItqL0iyJYd4
 

Introdução
JSON é um formato de dados estruturado amplamente utilizado na maioria das APIs e serviços modernos para compartilhar dados. É particularmente popular em aplicativos da web devido à sua natureza leve e compa...]]></description><link>https://simplescloud.com.br/jq</link><guid isPermaLink="true">https://simplescloud.com.br/jq</guid><category><![CDATA[jq]]></category><dc:creator><![CDATA[SimplesCloud]]></dc:creator><pubDate>Wed, 14 Sep 2022 20:49:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1663176441733/nhOR_BKhO.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/ItqL0iyJYd4">https://youtu.be/ItqL0iyJYd4</a></div>
<p> </p>
<hr />
<h2 id="heading-introducao">Introdução</h2>
<p><code>JSON</code> é um formato de dados estruturado amplamente utilizado na maioria das APIs e serviços modernos para compartilhar dados. É particularmente popular em aplicativos da web devido à sua natureza leve e compatibilidade como seu próprio nome sugere, o <code>JavaScript</code>.</p>
<p>Infelizmente terminais de comando como o <code>bash</code> não podem interpretar e trabalhar com <code>json</code> diretamente. Isso significa que trabalhar com <code>json</code> por meio da linha de comando pode ser complicado, vejamos por exemplo uma chamada para a API do filme Star Wars:</p>
<pre><code class="lang-bash">curl https://swapi.dev/api/people
</code></pre>
<p>E obtemos uma resposta em <code>json</code> com informações sobre os personagens do filme:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663176625251/fPwGv_QFh.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Bom, podemos ver que o <code>json</code> retornado não é muito amigável para nossa leitura, mas não se preocupe porque há uma forma simples e fácil de resolver isso, e o nome da solução se chama <code>jq</code> que acabará se tornando uma das suas ferramentas favoritas!</p>
<p>2- Veja como o mesmo <code>request</code> ficaria usando o <code>jq</code>:</p>
<pre><code class="lang-bash">curl https://swapi.dev/api/people | jq <span class="hljs-string">'.'</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663176694642/Fv6wrVjQP.png" alt="image.png" class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">☑</div>
<div data-node-type="callout-text"><strong>WOW!</strong> Visualmente falando, ficou muito melhor né? 🥳</div>
</div>

<hr />
<h2 id="heading-instalacao">Instalação</h2>
<p>1- Abra seu terminal e digite o comando:</p>
<pre><code class="lang-bash">sudo apt install jq
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663176757643/S5UnnetG3.png" alt="image.png" class="image--center mx-auto" /></p>
<p>2- Verifique a instalação com o comando:</p>
<pre><code class="lang-bash">jq --version
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663176788925/QJBGJV-SX.png" alt="image.png" class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-como-usar-o-jq">Como usar o JQ</h2>
<p><code>JQ</code> é mais do que apenas "embelezar" o json em seu bash, ele foi construído em torno do conceito de filtros, como veremos abaixo e existem muitos filtros que podemos usar e combinar sem esforços usando o caractere "<code>pipe</code>" <code>|</code> para manipular os dados do json.</p>
<p>Então vamos começar pelo filtro mais simples de todos, que também será o que você acabará usando com mais frequência:</p>
<pre><code class="lang-bash">curl https://swapi.dev/api/people | jq <span class="hljs-string">'.'</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663176875759/-qgc9wYGX.png" alt="image.png" class="image--center mx-auto" /></p>
<p><strong>Vamos entender o que aconteceu aqui:</strong></p>
<ul>
<li><p>Adicionamos ao final do nosso comando <code>| jq '.'</code></p>
</li>
<li><p>Esse <code>'.'</code> é um filtro que estamos dizendo ao jq <code>"hey, pegue todos os dados e imprima em um formato json visualmente mais bonito para mim"</code>.</p>
</li>
</ul>
<hr />
<p><strong>Avançando...</strong></p>
<p>Ok, já conseguimos ver o json melhor agora, mas imagino que você deve estar se perguntando nesse momento "Certo, é só isso? Mas como que eu pego apenas o nome de um personagem por exemplo?".</p>
<p>Se você se questionou sobre isso, estamos no caminho certo aqui. Vamos detalhar como podemos filtrar apenas o nome do personagem Star Wars no meio de toda essa informação:</p>
<p>1- Se olharmos bem, um json é constituído de <code>"chave":"valor"</code> ou no inglês <code>"key":"value"</code>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663176973412/hhiiP7x-3.png" alt="image.png" class="image--center mx-auto" /></p>
<p>2- E a key <code>name</code> está dentro de um <code>array</code> (matriz) chamado <code>results</code>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663177017134/OdFWXAULb.png" alt="image.png" class="image--center mx-auto" /></p>
<p>3- Então para filtrarmos, poderíamos começar com:</p>
<pre><code class="lang-bash">curl https://swapi.dev/api/people | jq <span class="hljs-string">'.results'</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663177053058/_YyUkyNBR.png" alt="image.png" class="image--center mx-auto" /></p>
<p><strong>Vamos entender o que aconteceu aqui:</strong></p>
<ul>
<li><p>Adicionamos ao final do nosso comando <code>| jq '.results'</code></p>
</li>
<li><p>Esse <code>'.results'</code> é um filtro que estamos dizendo ao jq <code>"hey, pegue todos os dados do array (matriz) chamado results e imprima o json desses itens".</code></p>
</li>
<li><p>Com isso as primeiras linhas que não fazem parte de <code>results</code> foram digamos assim "ignoradas".</p>
</li>
</ul>
<hr />
<p><strong>Avançando ainda mais...</strong></p>
<p>4- Se continuarmos olhando com atenção, poderemos ver que esse <code>array</code> (matriz) <code>results</code> possui uma lista de itens, onde:</p>
<ul>
<li><p>a primeira posição do <code>array</code> (matriz) é o <code>index</code> (índice) <code>0</code> e o nome é <code>Luke Skywalker</code></p>
</li>
<li><p>a segunda posição do <code>array</code> (matriz) é o <code>index</code> (índice) <code>1</code> e o nome é o <code>C-3PO</code></p>
</li>
</ul>
<p>Então podemos limitar nosso filtro passando como index (índice) <code>0</code> e isso nos retornará o nome <code>Luke Skywalker</code> como previsto:</p>
<pre><code class="lang-bash">curl https://swapi.dev/api/people | jq <span class="hljs-string">'.results[0]'</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663177196208/8MxVlm67B.png" alt="image.png" class="image--center mx-auto" /></p>
<p><strong>Vamos entender o que aconteceu aqui:</strong></p>
<ul>
<li><p>Adicionamos ao final do nosso comando <code>| jq '.results[0]'</code></p>
</li>
<li><p>Esse <code>'.results[0]'</code> é um filtro que estamos dizendo ao jq <code>"hey, pegue todos os dados do array (matriz) chamada results e imprima o index (índice) 0 (primeira posição da matriz) em um json".</code></p>
</li>
<li><p>Com isso o segundo item dessa matriz, no caso o <code>C-3PO</code> é digamos assim "ignorado", pois limitamos para o index (índice) <code>0</code> em nosso filtro.</p>
</li>
</ul>
<hr />
<p><strong>Avançando mais e mais...</strong></p>
<p>5- Até agora já descobrimos como chegar nesse valor, mas lembra que queríamos apenas o nome?</p>
<p>Bom, então só precisamos informar essa propriedade para o <code>jq</code>:</p>
<pre><code class="lang-bash">curl https://swapi.dev/api/people | jq <span class="hljs-string">'.results[0] | .name'</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663177312903/XZPxS0Ggc.png" alt="image.png" class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">☑</div>
<div data-node-type="callout-text"><strong>WOW</strong>, finalmente chegamos lá! 🥳</div>
</div>

<p>Mas aqui vale mais um pouco da sua atenção, vamos dividir nosso comando para entendermos melhor:</p>
<ul>
<li><p><code>curl https://swapi.dev/api/people</code> → faz um <code>request</code> para a API do filme Star Wars</p>
</li>
<li><p><code>| jq '.results[0]</code> → filtra os dados do index <code>0</code> no array <code>results</code></p>
</li>
<li><p><code>| .name'</code> → imprime na saída a propriedade <code>name</code> do index <code>0</code> no <code>array results</code></p>
</li>
</ul>
<p>Observe que depois do filtro, adicionamos novamente um "<code>pipe</code>" <code>|</code>, esse último bloco é responsável por "imprimir" as informações para nós como definirmos, isso é a mesma coisa que <code>stdout</code>. Grave essa informação, pois ela será útil em todos os próximos comandos, onde vamos mudar e manipular a forma que esses dados serão apresentados para nós.</p>
<hr />
<p>Agora ao invés de listar apenas o nome do index (índice) 0 do array (primeira posição da matriz), vamos listar todos os nomes dessa matriz, para isso é só removermos o 0 de .results[0], ficando assim:</p>
<pre><code class="lang-bash">curl https://swapi.dev/api/people | jq <span class="hljs-string">'.results[] | .name'</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663177421462/wJePWpyVW.png" alt="image.png" class="image--center mx-auto" /></p>
<p><strong>Vamos entender o que aconteceu aqui:</strong></p>
<ul>
<li><p>Adicionamos ao final do nosso comando <code>| jq '.results[] | .name'</code></p>
</li>
<li><p>Esse <code>'.results[] | .name'</code> é um filtro que estamos dizendo ao jq <code>"hey, pegue todos os dados do array (matriz) chamada results (ele inteiro sem qualquer índice) e imprima a propriedade name".</code></p>
</li>
</ul>
<hr />
<p><strong>Avançando mais, mais e mais...</strong></p>
<p>6- Legal, já conseguimos listar o nome de todos, mas eles ainda estão digamos assim "jogados", "soltos", vamos consertar isso:</p>
<pre><code class="lang-bash">curl https://swapi.dev/api/people | jq <span class="hljs-string">'.results[] | {name: .name}'</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663177514373/bzesrvSld.png" alt="image.png" class="image--center mx-auto" /></p>
<p><strong>Vamos entender o que aconteceu aqui:</strong></p>
<ul>
<li><p>Adicionamos ao final do nosso comando <code>| jq '.results[] | {name: .name}'</code></p>
</li>
<li><p>Esse <code>'.results[] | {name: .name}'</code> é um filtro que estamos dizendo ao jq <code>"hey, pegue todos os dados do array (matriz) chamada results (ele inteiro sem qualquer índice) e imprima a key (chave) name com o value (valor) da propriedade name entre {}".</code></p>
</li>
</ul>
<hr />
<p><strong>Avançando mais, mais, mais e ainda mais...</strong></p>
<p>7- Estamos melhorando, mas ainda podemos ver que essas informações estão "jogadas", não há formatação <code>json</code> e nem vírgulas no final de cada <code>{}</code>, vamos consertar isso:</p>
<pre><code class="lang-bash">curl https://swapi.dev/api/people | jq <span class="hljs-string">'[.results[] | {name: .name}]'</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663177648143/_O2NF7kE2.png" alt="image.png" class="image--center mx-auto" /></p>
<p><strong>Vamos entender o que aconteceu aqui:</strong></p>
<ul>
<li><p>A única diferença é que adicionamos colchetes <code>[]</code> no início e final do nosso filtro <code>'[.results[] | {name: .name}]'</code></p>
</li>
<li><p>Então estamos dizendo ao jq aqui <code>"hey coloque o resultado desse filtro dentro de um array (matriz)".</code></p>
</li>
</ul>
<hr />
<p><strong>Avançando e avançando...</strong></p>
<p>8- Até agora vimos exemplos somente com uma propriedade <code>name</code>, mas e se quisermos usar várias propriedades juntas? A resposta é simples, separe por vírgulas, por exemplo:</p>
<pre><code class="lang-bash">curl https://swapi.dev/api/people | jq <span class="hljs-string">'[.results[] | {name: .name, eye_color: .eye_color}]'</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663177748210/FRKJFxL39.png" alt="image.png" class="image--center mx-auto" /></p>
<p><strong>Vamos entender o que aconteceu aqui:</strong></p>
<ul>
<li><p>A única diferença é que separamos as propriedades <code>name</code> e <code>eye_color</code> por vírgulas → ou seja → <code>'[.results[] | {name: .name, eyecolor: .eye_color}]'</code></p>
</li>
<li><p>Então estamos dizendo ao jq aqui <code>"hey coloque o resultado desse filtro dentro de um array (matriz) com as keys (chaves) name e eye_color com os values (valores) das respectivas propriedades".</code></p>
</li>
</ul>
<hr />
<p><strong>Último avanço...</strong></p>
<p>9- Mas e se já tivermos um valor e quisermos fazer uma pesquisa? Por exemplo queremos montar um novo array (matriz) com os nomes dos personagens que possuem olhos azuis, faremos um <code>select</code>:</p>
<pre><code class="lang-bash">curl https://swapi.dev/api/people | jq <span class="hljs-string">'[.results[] | select(.eye_color=="blue") | {name: .name}]'</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663177870956/C8ZDmMjIb.png" alt="image.png" class="image--center mx-auto" /></p>
<p><strong>Vamos entender o que aconteceu aqui:</strong></p>
<ul>
<li><p>A única diferença é que adicionamos <code>select(.eye_color=="blue")</code>.</p>
</li>
<li><p>Então estamos dizendo ao jq aqui <code>"hey vá para a array (matriz) results, ache o value (valor) blue (azul) na propriedade eye_color de cada item e coloque o resultado desse filtro dentro de um array (matriz) com a keys (chave) name com o seu respectivo value (valor).</code></p>
</li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">☑</div>
<div data-node-type="callout-text">E é isso, espero que com essa breve introdução e exemplos, eu possa ter conseguido demonstrar como o <code>jq</code> funciona e como você pode manipular a saída <code>json</code> para suas preferências ou caso de uso.</div>
</div>

<hr />
<h2 id="heading-use-jq-para-scripts">Use JQ para Scripts</h2>
<p>No seu dia a dia você vai se deparar várias vezes com a necessidade de obter dados de uma saída <code>json</code>, mas isso não se aplica somente a sistemas web, você também vai notar que precisará disso principalmente para seus scripts funcionarem corretamente, por exemplo pode ser comum você precisar obter o ID de uma instância na AWS, então para isso você faria:</p>
<pre><code class="lang-bash">aws ec2 describe-instances
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663177990357/rBn3RBP1p.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Esse comando do AWS CLI faz uma chamada na API da AWS e te retornaria uma saída <code>json</code> com muitas informações, por exemplo:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663178009287/qm8LdWpBj.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Mas nós só queremos o ID dessa instância, é aqui que entra o <code>jq</code> e tudo que vimos nesse artigo, então bastaria nós retornarmos o valor da key <code>InstanceID</code>:</p>
<pre><code class="lang-bash">aws ec2 describe-instances | jq <span class="hljs-string">'.Reservations[] | .Instances[] | {Id: .InstanceId}'</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663178064429/diuh3syPc.png" alt="image.png" class="image--center mx-auto" /></p>
<p><strong>Vamos entender o que aconteceu aqui:</strong></p>
<ul>
<li><p>Adicionamos ao final do nosso comando AWS CLI <code>| jq '.Reservations[] | .Instances[] | {Id: .InstanceId}'</code></p>
</li>
<li><p><code>| jq '.Reservations[]</code> → jq está indo no array <code>Reservations</code></p>
</li>
<li><p><code>| .Instances[]</code> → jq está indo no array <code>Instances</code></p>
</li>
<li><p><code>| {Id: .InstanceId}'</code> → jq está "imprimindo" a key <code>Id</code> com o value <code>InstanceId</code></p>
</li>
</ul>
<p>E essa informação poderia ser muito útil para um script que agenda o ligar/desligar dessa instância por exemplo.</p>
<hr />
<p>Outro exemplo poderia ser se você estiver usando o AWS ECS Fargate para orquestrar seus contêineres e como parte de um Pipeline automático, você gostaria de fazer o Deploy da sua nova imagem em uma nova Task, para isso seria importante você descobrir o ID dessa Task, então você faria:</p>
<pre><code class="lang-bash">aws ecs list-tasks --cluster &lt;clusterName&gt;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663178162581/FH0jppWvf.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Observe que é retornado um ARN que é o nome completo de um recurso da AWS, mas nós só precisamos do ID que está localizado depois do último <code>/</code>, então usaríamos o jq aqui para dividir esses caracteres assim:</p>
<pre><code class="lang-bash">aws ecs list-tasks --cluster &lt;clusterName&gt; | jq -Mr <span class="hljs-string">'.taskArns[] | split("/")[-1]'</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663178218815/lLZlkcQHA.png" alt="image.png" class="image--center mx-auto" /></p>
<p><strong>Vamos entender o que aconteceu aqui:</strong></p>
<ul>
<li><p>Adicionamos no final do nosso comando AWS CLI <code>| jq -Mr '.taskArns[] | split("/")[-1]'</code></p>
</li>
<li><p><code>| jq -Mr '.taskArns[]</code> → jq está indo para o array <code>taskArns</code></p>
</li>
<li><p><code>| split("/")[-1]'</code> → jq está "imprimindo" o último bloco depois da <code>/</code> que é o ID</p>
</li>
</ul>
<hr />
<h2 id="heading-conclusao">Conclusão</h2>
<p>Esses foram alguns exemplos reais e práticos de como usar o <code>jq</code> e de como ele pode ser útil no seu dia a dia, obviamente você poderia fazer várias combinações e filtros diferentes e para diferentes ferramentas como inspecionar containers do docker, kubernetes e muitas outras coisas.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Espero que essas informações tenham sido úteis para você!</div>
</div>]]></content:encoded></item><item><title><![CDATA[Hashicorp Packer - Instalação]]></title><description><![CDATA[https://youtu.be/Px9UOcr5-SI
 

Introdução
Hashicorp Packer é uma ferramenta open-source (gratuita). Com essa poderosa ferramenta somos capazes de automatizar a criação de qualquer tipo de imagem (AMI) para várias plataformas diferentes como AWS, Goo...]]></description><link>https://simplescloud.com.br/hashicorp-packer-instalacao</link><guid isPermaLink="true">https://simplescloud.com.br/hashicorp-packer-instalacao</guid><category><![CDATA[hashicorp packer]]></category><category><![CDATA[hashicorp packer installation]]></category><dc:creator><![CDATA[SimplesCloud]]></dc:creator><pubDate>Wed, 14 Sep 2022 20:48:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1663175612003/TfwWv6WFj.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/Px9UOcr5-SI">https://youtu.be/Px9UOcr5-SI</a></div>
<p> </p>
<hr />
<h2 id="heading-introducao">Introdução</h2>
<p>Hashicorp Packer é uma ferramenta open-source (gratuita). Com essa poderosa ferramenta somos capazes de automatizar a criação de qualquer tipo de imagem (AMI) para várias plataformas diferentes como AWS, Google Cloud, Microsoft Azure, etc. a partir de uma única configuração de origem <code>JSON</code> ou <code>HCL2</code> que define o modelo da infraestrutura imutável.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Neste artigo não abordaremos muito sobre conceitos do Hashicorp Packer, focaremos apenas na sua instalação ou atualização.</div>
</div>

<hr />
<h2 id="heading-instalacao-ou-atualizacao-do-hashicorp-packer">Instalação ou Atualização do Hashicorp Packer</h2>
<p>Você poderá instalar ou atualizar a versão do Hashicorp Packer a qualquer momento, para isso execute o comando abaixo:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Import Hashicorp GPG key</span>
<span class="hljs-keyword">if</span> [ ! -f /etc/apt/trusted.gpg.d/hashicorp.gpg ]; <span class="hljs-keyword">then</span>

  curl -fsSL https://apt.releases.hashicorp.com/gpg | 
    gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/hashicorp.gpg &gt;/dev/null

<span class="hljs-keyword">fi</span> &amp;&amp; \

<span class="hljs-comment"># Add Hashicorp repository without confirmation  </span>
sudo apt-add-repository -y \
  <span class="hljs-string">"deb [arch=amd64] https://apt.releases.hashicorp.com <span class="hljs-subst">$(lsb_release -cs)</span> main"</span> &amp;&amp; \

<span class="hljs-comment"># Update repositories</span>
sudo apt update &amp;&amp; \

<span class="hljs-comment"># Install Packer </span>
sudo apt install packer -y &amp;&amp; \

<span class="hljs-comment"># Print version</span>
packer --version
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1692796770123/a84a6134-f630-4f0e-b88f-db47477b9354.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">☑</div>
<div data-node-type="callout-text">E isso é tudo! 😄</div>
</div>

<p>Mas se você quiser entender o que cada parte deste comando faz, é só continuar lendo abaixo.</p>
<hr />
<h2 id="heading-explicando-o-comando">Explicando o comando:</h2>
<pre><code class="lang-bash"><span class="hljs-comment"># Import Hashicorp GPG key</span>
<span class="hljs-keyword">if</span> [ ! -f /etc/apt/trusted.gpg.d/hashicorp.gpg ]; <span class="hljs-keyword">then</span>

  curl -fsSL https://apt.releases.hashicorp.com/gpg | 
    gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/hashicorp.gpg &gt;/dev/null

<span class="hljs-keyword">fi</span> &amp;&amp; \
</code></pre>
<p>Essa primeira parte verifica se a chave GPG da Hashicorp já está presente em <code>/etc/apt/trusted.gpg.d/</code>. Se não estiver, ele faz o download da chave, decodifica e salva no local correto.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Add Hashicorp repository without confirmation</span>
sudo apt-add-repository -y \
  <span class="hljs-string">"deb [arch=amd64] https://apt.releases.hashicorp.com <span class="hljs-subst">$(lsb_release -cs)</span> main"</span> &amp;&amp; \
</code></pre>
<p>Aqui adicionamos o repositório da Hashicorp ao APT, sem pedir confirmação <code>(-y)</code>.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Update repositories  </span>
sudo apt update &amp;&amp; \
</code></pre>
<p>Atualiza os repositórios para pegar a lista de pacotes do novo repositório adicionado.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Install Packer</span>
sudo apt install packer -y &amp;&amp; \
</code></pre>
<p>Instala o Packer a partir do repositório da Hashicorp.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Print version</span>
packer --version
</code></pre>
<p>Por último, imprime a versão instalada do Packer para confirmar que está funcionando.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Espero que essas informações tenham sido úteis para você!</div>
</div>]]></content:encoded></item><item><title><![CDATA[Terragrunt - Instalação]]></title><description><![CDATA[https://youtu.be/1rQoRtUKmNs
 

Introdução
Terragrunt é um wrapper open-source (gratuito) criado pela empresa Gruntwork que fornece ferramentas extras para manter suas configurações DRY (menos repetitivas) enquanto você trabalha com vários módulos Te...]]></description><link>https://simplescloud.com.br/terragrunt-instalacao</link><guid isPermaLink="true">https://simplescloud.com.br/terragrunt-instalacao</guid><category><![CDATA[terragrunt]]></category><category><![CDATA[terragrunt installation]]></category><dc:creator><![CDATA[SimplesCloud]]></dc:creator><pubDate>Wed, 14 Sep 2022 20:47:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1663015946271/_D38HfS-Y.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/1rQoRtUKmNs">https://youtu.be/1rQoRtUKmNs</a></div>
<p> </p>
<hr />
<h2 id="heading-introducao">Introdução</h2>
<p>Terragrunt é um wrapper open-source (gratuito) criado pela empresa Gruntwork que fornece ferramentas extras para manter suas configurações <code>DRY</code> (menos repetitivas) enquanto você trabalha com vários módulos Terraform e também precisa gerenciar seu estado remoto.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">Neste artigo não abordaremos muito sobre conceitos do Terragrunt, focaremos apenas na sua instalação. Como o Terragrunt está em constante atualizações, pode se tornar trabalhoso instalar cada nova versão. Para minimizar esse esforço, utilizaremos um gerenciador de versões do Terraform chamado <code>TG Switch</code></div>
</div>

<hr />
<h2 id="heading-instalacao">Instalação</h2>
<p>1- Digite o comando:</p>
<pre><code class="lang-bash">sudo curl -L https://raw.githubusercontent.com/warrensbox/tgswitch/release/install.sh | sudo bash
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663016123936/9EyZV52dK.png" alt="image.png" class="image--center mx-auto" /></p>
<p>2- Digite o comando → pressione <code>Enter</code> na versão do <code>Terragrunt</code> que você desejar instalar:</p>
<pre><code class="lang-bash">tgswitch
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663016168729/p0vcBH7A3.png" alt="image.png" class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Aguarde! É demorado mesmo, você terá a impressão de que está travado ou que nada aconteceu, mas apenas aguarde o comando ser executado por completo.</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663016207040/Q6PKtLq13.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Agora precisamos adicionar o diretório <code>/home/&lt;user&gt;/bin</code> criado para o seu <code>PATH</code>. Então digite o comando:</p>
<pre><code class="lang-bash">sudo nano ~/.zshrc
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663014927910/gl5KB9sDn.png" alt="image.png" class="image--center mx-auto" /></p>
<p>E adicione a linha abaixo → pressione <code>CTRL + X</code> → <code>Y</code> → <code>Enter</code> para salvar:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">export</span> PATH=<span class="hljs-variable">$PATH</span>:/home/&lt;user&gt;/bin:PATH
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Lembre-se de alterar <code>user</code> do comando para o usuário real que você usa</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663015071452/v5HoxsEzF.png" alt="image.png" class="image--center mx-auto" /></p>
<p>3- Verifique a versão do Terragrunt instalado digitando o comando:</p>
<pre><code class="lang-bash">terragrunt --version
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1663016242578/pWq-oUCez.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Então sempre que você precisar mudar de versão do terragrunt, basta digitar o comando <code>tgswitch</code> e selecionar a versão desejada. Bacana né?</p>
<p>Se você não quer procurar e selecionar uma versão no menu do <code>tgswitch</code>, pois já sabe exatamente a versão que deseja usar, você pode passar essa informação diretamente no comando:</p>
<pre><code class="lang-bash">tgswitch &lt;version&gt;
</code></pre>
<p>Por exemplo:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># tgswitch 0.36.0</span>
</code></pre>
<p>E isso instalaria a versão <code>0.36.0</code> do Terragrunt.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">✅</div>
<div data-node-type="callout-text">Espero que essas informações tenham sido úteis para você!</div>
</div>]]></content:encoded></item></channel></rss>