<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Thiago Souza</title>
    <description>The latest articles on DEV Community by Thiago Souza (@thiagosouzasi).</description>
    <link>https://dev.to/thiagosouzasi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F931744%2F3cba8443-edd8-4735-ab73-01dd0ce9c577.jpeg</url>
      <title>DEV Community: Thiago Souza</title>
      <link>https://dev.to/thiagosouzasi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thiagosouzasi"/>
    <language>en</language>
    <item>
      <title>Spring Boot + Docker + AWS EC2</title>
      <dc:creator>Thiago Souza</dc:creator>
      <pubDate>Wed, 26 Apr 2023 19:23:33 +0000</pubDate>
      <link>https://dev.to/thiagosouzasi/spring-boot-docker-aws-ec2-72f</link>
      <guid>https://dev.to/thiagosouzasi/spring-boot-docker-aws-ec2-72f</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Salve galera! Nesse post vou tentar demostrar como publicar uma Api Spring Boot utilizando Docker, DockerHub e uma instância do EC2 da AWS. Então seguem os passos que vamos seguir para publicar a Api.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Criar um projeto Spring Boot&lt;/li&gt;
&lt;li&gt;Criar uma imagem com Dockerfile&lt;/li&gt;
&lt;li&gt;Publicar a imagem no DockerHub&lt;/li&gt;
&lt;li&gt;Configurar uma instância EC2 na AWS e colocar a API em produção&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Vamos Lá!&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando o projeto
&lt;/h2&gt;

&lt;p&gt;Para criação do projeto vamos utilizar a plataforma &lt;a href="https://start.spring.io/"&gt;Spring Initializr&lt;/a&gt; e criar um projeto simples utilizando maven e java 17 e com apenas uma dependência conforme abaixo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--po4G733R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0ouamz3i5ly3gohjbjll.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--po4G733R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0ouamz3i5ly3gohjbjll.png" alt="Image description" width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O projeto consiste em uma pequena Api que vai consultar dados sobre Pokemons em uma outra Api bem famosa, a &lt;a href="https://pokeapi.co/"&gt;PokéApi&lt;/a&gt;. Faremos a consulta passando o nome do pokemon para um controller get na nossa api. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;PokemonControler&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@RestController
public class PokemonController {

    @Autowired
    PokemonService pokemonService;

    @GetMapping("pokemon-info")
    public String GetPokemonInfo(@RequestParam String pokemonName){

        return pokemonService.GetPokemonInfo(pokemonName);
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dentro do nosso controller temos uma injeção de dependência para nossa classe service que por sua vez acionará nosso repository que buscará os dados.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;PokemonService&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Service
public class PokemonService {

    @Autowired
    PokemonRepository pokemonRepository;
    public String GetPokemonInfo(String pokemonName) {
      return pokemonRepository.GetPokemonInfo(pokemonName);
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Por último temos nosso PokemonRepository, geralmente é aqui que fazemos o acesso ao banco de dados, mas como a Api é simples vamos simular esse acesso aos dados com uma chamada para outra Api passando o nome do pokemon recebido pelo controller.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;PokemonRepository&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Repository
public class PokemonRepositoryImplementation implements PokemonRepository {

    @Autowired
    private Environment env;

    @Override
    public String GetPokemonInfo(String pokemonName) {
        try {
          return  new RestTemplate().getForObject(env.getProperty("baseUrl")+pokemonName, String.class);
        }catch (HttpClientErrorException error){
            if (error.getStatusCode() == HttpStatus.NOT_FOUND) {
                throw new ResponseStatusException(HttpStatus.NOT_FOUND);
            } else {
                throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
            }
        }

    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O código completo pode ser encontrado no meu &lt;a href="https://github.com/thiagosouzasi/Spring-deploy-docker-aws"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Criar a imagem com Dockerfile
&lt;/h2&gt;

&lt;p&gt;Vamos criar um arquivo na raiz do projeto com o nome Dockerfile sem extensão. Dentro desse arquivos vamos incluir os comandos Docker para geração da imagem que será enviada para o DockerHub e posteriormente carregada dentro de um container na nossa instância EC2 na AWS. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Dockerfile&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6JFh3D_T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u98fsk83dn1brap4dw8u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6JFh3D_T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u98fsk83dn1brap4dw8u.png" alt="Image description" width="800" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dentro do arquivo vamos entender o que faz cada comando:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;FROM openjdk:17&lt;/code&gt; -&amp;gt; Indica que vamos construir nossa imagem a partir do jdk 17 necessário para que a nossa Api seja executada no container.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;WORKDIR /app&lt;/code&gt; -&amp;gt; Cria o repositório app dentro do nosso container para onde vamos copiar nossos arquivos .jar compliados.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;COPY /target/demo-0.0.1-SNAPSHOT.jar /app/api.jar&lt;/code&gt; -&amp;gt; Aqui estamos copiando nosso jar de dentro da pasta onde ele foi gerado, para dentro do repositório criado no nosso comando anterior.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;EXPOSE 8080&lt;/code&gt; -&amp;gt; Expondo a porta onde nossa aplicação ficará disponível.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ENTRYPOINT ["java","-jar", "api.jar"]&lt;/code&gt; -&amp;gt; Executando nosso arquivo .jar criado para que nossa aplicação seja iniciada.&lt;/p&gt;

&lt;p&gt;Antes de utilizarmos o Dockerfile para criar nossa imagem, precisamos construir o nosso .jar com nosso código fonte compilado, para isso utilizaremos o comando &lt;code&gt;mvn clean install&lt;/code&gt; isso deve gerar nossos arquivos dentro do diretório target do projeto.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x55dA9fj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kvlfw3uh6oc66zpvz54u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x55dA9fj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kvlfw3uh6oc66zpvz54u.png" alt="Image description" width="768" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A partir de agora precisaremos estar com o &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt; instalado e rodando em nossa máquina, pois vamos fazer build utilizando nosso Dockerfile para efetivamente gerar a imagem que será posteriormente enviada ao DockerHub. É necessário também possuir uma conta no &lt;a href="https://hub.docker.com/"&gt;DockerHub&lt;/a&gt; pois vamos precisar efetuar o login na nossa conta para fazer o push da imagem.&lt;/p&gt;

&lt;p&gt;Abra o terminal e execute o seguinte comando &lt;code&gt;docker build  -t pokemon-api .&lt;/code&gt; esse comando vai gerar nossa imagem com o nome pokemon-api utilizando nosso Dockerfile criado anteriormente.&lt;/p&gt;

&lt;p&gt;Podemos agora executar o comando &lt;code&gt;docker images&lt;/code&gt; e verificar que nossa imagem foi criada com. sucesso!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ymVKxq7q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kzswkipzq8ktqn2qcce4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ymVKxq7q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kzswkipzq8ktqn2qcce4.png" alt="Image description" width="800" height="92"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Publicar a imagem no DockerHub
&lt;/h2&gt;

&lt;p&gt;Agora que temos a nossa imagem gerada, vamos subir para a nossa conta no DockerHub. Precisamos fazer login na nossa conta, então vamos rodar o comando &lt;code&gt;docker login&lt;/code&gt; dentro do terminal, nossas credenciais serão solicitadas após isso já poderemos efetuar o push da imagem para nossa conta.&lt;/p&gt;

&lt;p&gt;Vamos marcar a imagem com uma tag que será importante na hora de fazer o pull dentro da nossa instância de EC2. O padrão para esse comando é: &lt;code&gt;docker tag &amp;lt;image_id&amp;gt; &amp;lt;dockerhub_username&amp;gt;/&amp;lt;image_name&amp;gt;:&amp;lt;tag&amp;gt;&lt;/code&gt;, onde image_id é o ID da imagem que desejamos marcar, no meu caso, o comando ficaria assim: &lt;code&gt;docker tag c8a7b3f87156  thiagosouzasi/pokemon-api:0.0.1&lt;/code&gt;. Estou utilizando a tag para versionar a nossa imagem com 0.0.1.&lt;/p&gt;

&lt;p&gt;Agora que a imagem já possui a tag, vamos fazer o push para nosso repositório. Pra isso vamos utilizar o comando &lt;code&gt;docker push thiagosouzasi/pokemon-api:0.0.1&lt;/code&gt;. Lembrando que precisamos estar logados na nossa conta para que o processo funcione.&lt;/p&gt;

&lt;p&gt;Pronto, agora temos nossa imagem publicada dentro do DockerHub.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cB0l9-yT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8bkszgw3a5m2zcw5xd6i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cB0l9-yT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8bkszgw3a5m2zcw5xd6i.png" alt="Image description" width="762" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Configurar uma instância EC2 na AWS e colocar a API em produção.
&lt;/h2&gt;

&lt;p&gt;Finalmente chegou a hora de publicarmos nossa Api, para isso é preciso inicialmente possuir uma conta na &lt;a href="https://aws.amazon.com/pt/?nc2=h_lg"&gt;AWS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Com a conta criada vamos navegar até o console e digitar EC2 na busca. Dentro do EC2 vamos clicar em Executar Instância para criar uma nova Instância de EC2. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LFTu6qv7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/slfgy7bptq1c3egclp74.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LFTu6qv7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/slfgy7bptq1c3egclp74.png" alt="Image description" width="772" height="615"&gt;&lt;/a&gt;&lt;br&gt;
Informamos o nome da instância e escolheremos o tipo Amazon Linux. Devemos ainda selecionar o tipo t2.micro, assim, conseguiremos publicar a Api sem custos. &lt;/p&gt;

&lt;p&gt;Posteriormente precisamos configurar o login sem atribuir chaves de acesso, &lt;strong&gt;atenção&lt;/strong&gt; esse tipo de configuração &lt;strong&gt;não&lt;/strong&gt; é recomendado em projetos reais por deixar brechas de segurança, contudo, por hora isso será o suficiente e facilitará a conexão com a instância que será feita mais a frente. &lt;/p&gt;

&lt;p&gt;Após isso basta clicar em executar instância.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iGiqJXNK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/51h8owzcf0eakwzoj1v5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iGiqJXNK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/51h8owzcf0eakwzoj1v5.png" alt="Image description" width="800" height="483"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Adicionaremos ainda outra configuração importante, devemos liberar a porta http(80) da nossa instância para habilitar o acesso externo. Mais a frente faremos o mapeamento dessa porta para a porta do container que deverá rodar nossa APi. &lt;/p&gt;

&lt;p&gt;Selecione a instância criada, e navegue até a aba segurança. &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oF7bou2T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/twybhtza07zz5psfi9ca.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oF7bou2T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/twybhtza07zz5psfi9ca.png" alt="Image description" width="800" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Em grupo de segurança clicamos em &lt;em&gt;launch-wizard&lt;/em&gt; vai ser aberta uma tela  onde vamos configurar uma regra de entrada. &lt;/p&gt;

&lt;p&gt;Na tela a seguir vamos selecionar regras de entrada e clicar em &lt;em&gt;editar regras de entrada&lt;/em&gt;  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h7m6yVLr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uwev8t23vgub16shfvr0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h7m6yVLr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uwev8t23vgub16shfvr0.png" alt="Image description" width="800" height="148"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vamos adicionar a regra para protocolo http (80) e salvar a configuração.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JnuQXuZ3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wxvwhbxmdscbfh3q6ry4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JnuQXuZ3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wxvwhbxmdscbfh3q6ry4.png" alt="Image description" width="800" height="184"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Agora já estamos com o EC2 configurado, selecione a instância criada e vá em conectar. Agora instalaremos o Docker, faremos o pull da imagem do Dockerhub e executaremos nossa Api.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1IX6b1rV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/74hgpw25ckoplgs3lyk1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1IX6b1rV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/74hgpw25ckoplgs3lyk1.png" alt="Image description" width="800" height="547"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Uma vez conectados basta executar uma sequência de comandos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Primeiro vamos alternar para o modo root no terminal com o comando &lt;code&gt;sudo -i&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Agora vamos atualizar os pacotes da máquina com o comando &lt;code&gt;sudo yum update -y&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Na sequência vamos instalar o Docker na EC2 com o comando &lt;code&gt;sudo yum install docker&lt;/code&gt;. Após o download e instalação dos pacotes podemos verificar se a instalação foi bem sucedida executando o comando &lt;code&gt;docker -v&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9jJ_YE10--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h6qzkbfmps8wzfi76qmv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9jJ_YE10--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h6qzkbfmps8wzfi76qmv.png" alt="Image description" width="407" height="112"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vamos agora iniciar o Docker com o comando &lt;code&gt;sudo service docker start&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Docker rodando, vamos fazer o pull da nossa imagem salva no Dockerhub, para isso precisaremos efetuar novamente o login na nossa conta do Dockerhub com o mesmo comando que utilizamos na nossa máquina local &lt;code&gt;docker login&lt;/code&gt;. Uma vez logados vamos buscar a imagem, o comando pode ser encontrado no próprio Dockerhub onde salvamos a imagem. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5QgFofW4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5gdu12xv76m79enscejh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5QgFofW4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5gdu12xv76m79enscejh.png" alt="Image description" width="800" height="126"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vamos rodar o comando &lt;code&gt;docker pull thiagosouzasi/pokemon-api:0.0.1&lt;/code&gt; substituindo o tag name pela tag da versão da imagem que configuramos anteriormente.&lt;/p&gt;

&lt;p&gt;A imagem será baixada para nossa instância, ao final do processo podemos ainda conferir se deu tudo certo rodando o comando &lt;code&gt;docker images&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VHEJKjeh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aikowb215j4v0m199wqk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VHEJKjeh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aikowb215j4v0m199wqk.png" alt="Image description" width="685" height="152"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Chegamos à última etapa, vamos subir um container utilizando nossa imagem para finalmente colocar nossa Api em produção! &lt;/p&gt;

&lt;p&gt;Rode o comando &lt;code&gt;docker run -d -p 80:8080 thiagosouzasi/pokemon-api:0.0.1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Com esse comando estamos subindo nosso container na porta 8080, mesma porta configurada na nossa api spring boot e estamos mapeando essa porta para a porta 80 da instância EC2, justamente por isso configuramos a regra de entrada nas etapas anteriores. Dessa forma todo tráfego que chegar na porta http padrão será direcionado para a api no nosso container. &lt;/p&gt;

&lt;p&gt;Foi utilizada ainda a flag -d para que nosso container suba em modo detached e permaneça rodando mesmo quando fecharmos o terminal do EC2.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sRkC3EdU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o5ixbextu4j0hdg9x6qr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sRkC3EdU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o5ixbextu4j0hdg9x6qr.png" alt="Image description" width="800" height="261"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Pronto, é chegada a hora da verdade! Agora basta pegar DNS IPv4 público da nossa instância e fazer uma requisição passando o nome de um pokemon que vc conhece para ver se está tudo funcionando. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gI5N3EH0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lu0zvsnhfs2cf5ogafp0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gI5N3EH0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lu0zvsnhfs2cf5ogafp0.png" alt="Image description" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Por hoje é isso pessoal!&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>docker</category>
      <category>aws</category>
      <category>development</category>
    </item>
    <item>
      <title>React - useEffect vs useLayoutEffect</title>
      <dc:creator>Thiago Souza</dc:creator>
      <pubDate>Sun, 09 Oct 2022 19:42:14 +0000</pubDate>
      <link>https://dev.to/thiagosouzasi/react-useeffect-vs-uselayouteffect-1bn7</link>
      <guid>https://dev.to/thiagosouzasi/react-useeffect-vs-uselayouteffect-1bn7</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Olá pessoal, hoje darei início a uma pequena série de posts sobre React, tecnologia que eu trabalho atualmente. Vamos falar um pouco sobre hooks, hoje mais precisamente sobre os hooks &lt;strong&gt;useEffect&lt;/strong&gt; (muito difundido e utilizado) e o &lt;strong&gt;useLayoutEffect&lt;/strong&gt; (bem menos conhecido e utilizado).&lt;/p&gt;

&lt;h2&gt;
  
  
  Funcionamento
&lt;/h2&gt;

&lt;p&gt;Olhando os hooks de maneira um pouco menos criteriosa temos a impressão de que ambos funcionam da mesma maneira, inclusive apresentam nomes e assinaturas bem semelhantes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function MyComponent(){

  useEffect(()=&amp;gt;{
    //função de efeito
    soma()
  },[])//array de dependências


  useLayoutEffect(()=&amp;gt;{
     //função de efeito
     soma()
  },[])//array de dependências


  function soma(a,b){
    return a+b
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para além das semelhanças de sintaxe, ambos possuem comportamento bem similar, e isso pode confundir o desenvolvedor desatento. Olhando rapidamente, o funcionamento dos dois é "exatamente o mesmo"! Executam uma uma função de efeito no primeiro render do componente, e tornam a executar essa função sempre que alguma das dependências do array de dependências sofrer alteração.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qual a diferença?
&lt;/h2&gt;

&lt;p&gt;De maneira bem prática, existem duas diferenças entre os hooks, uma é o momento do &lt;strong&gt;lifecycle&lt;/strong&gt; (Ciclo de vida do componente) em que eles são executados e a outra diferença é que um tem o funcionamento síncrono e o outro tem funcionamento assíncrono.&lt;/p&gt;

&lt;p&gt;Para entender melhor é necessário uma breve explicação sobre o &lt;strong&gt;lifecycle&lt;/strong&gt;. Sempre que uma renderização acontece em um componente React, seja o primeiro render ou um render disparado por alterações nas &lt;strong&gt;&lt;em&gt;props&lt;/em&gt;&lt;/strong&gt; ou &lt;strong&gt;&lt;em&gt;states&lt;/em&gt;&lt;/strong&gt;, uma série de ações são executadas por baixo dos panos até que o usuário visualize as mudanças em tela, é isso que chamamos de lifecycle do componente. Isso posto vamos agora entender a diferença entre os dois hooks, e a principal delas é justamente o momento dentro desse lifecycle onde cada um dos hooks é disparado.&lt;/p&gt;

&lt;h2&gt;
  
  
  useEffect
&lt;/h2&gt;

&lt;p&gt;No caso do useEffect a função de efeito é disparada após as alterações visuais do componente já terem sido aplicadas na tela, portanto já visíveis ao usuário.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vZloy8At--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vf3acoh1ctvu6a3v5dqz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vZloy8At--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vf3acoh1ctvu6a3v5dqz.png" alt="Image description" width="880" height="209"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  useLayoutEffect
&lt;/h2&gt;

&lt;p&gt;Já quando estamos tratando do useLayoutEffect esse comportamento se altera. A função de efeito será chamada sempre &lt;strong&gt;antes&lt;/strong&gt; de o usuário enxergar as alterações na tela.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OPRzRliL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ofo60q17o6escmb818j4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OPRzRliL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ofo60q17o6escmb818j4.png" alt="Image description" width="880" height="183"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Outra diferença do useLayoutEffect é que ele é síncrono, o que na prática indica que o próximo passo do lifecycle (usuário ver as alterações em tela) só acontece  quando a função de efeito disparada for finalizada. Já no caso do useEffect isso não acontece pois seu comportamento é assíncrono.&lt;/p&gt;

&lt;h2&gt;
  
  
  Então qual utilizar?
&lt;/h2&gt;

&lt;p&gt;O próprio React recomenda a utilização do useEffect em 99% dos casos, pois o comportamento síncrono do useLayoutEffect que bloqueia o fluxo de renderização pode passar ao usuário a impressão de que a aplicação está "travada" quando na verdade a tela está esperando a função de efeito terminar de executar para finalizar a renderização. Contudo sempre existem cenários específicos onde pode ser necessário aguardar a finalização de algum processamento antes de exibir os dados na tela, aí nesses casos seria interessante lançar mão do useLayoutEffect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finalizando
&lt;/h2&gt;

&lt;p&gt;Por hoje é isso pessoal, nós próximos posts falaremos mais sobre o useEffect que teve seu comportamento alterado na versão 18 do React&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>hooks</category>
      <category>dev</category>
    </item>
    <item>
      <title>O que devo estudar para iniciar na programação?</title>
      <dc:creator>Thiago Souza</dc:creator>
      <pubDate>Sat, 24 Sep 2022 20:19:51 +0000</pubDate>
      <link>https://dev.to/thiagosouzasi/o-que-devo-estudar-para-iniciar-na-programacao-4h3h</link>
      <guid>https://dev.to/thiagosouzasi/o-que-devo-estudar-para-iniciar-na-programacao-4h3h</guid>
      <description>&lt;p&gt;Olá comunidade! Estou no mundo do desenvolvimento desde o agora longínquo ano de 2012, durante esse tempo ouvi a pergunta do título acima inúmeras vezes, essa e muitas outras relacionadas como: Começo com qual linguagem? Preciso fazer faculdade? Qual linguagem é mais simples? Demora muito pra aprender? etc. Ainda durante esse período trabalhando com desenvolvimento necessitei migrar de linguagem várias vezes (O que para alguns é sempre um novo começo), passei pelo C na faculdade, Java, Php, Delphi, JavaScript, TypeScript, React, React Native. Sempre que estava fazendo essa migração me lembrava das palavras de um professor na faculdade: "Você não deve se preocupar em aprender a linguagem, preocupe-se em aprender a PROGRAMAR!". E, realmente é esse o segredo! Se aprendemos a programar, a linguagem passa a ser secundária, ela se transforma simplesmente em SINTAXE! Abaixo vou &lt;strong&gt;&lt;em&gt;tentar&lt;/em&gt;&lt;/strong&gt;  responder algumas das perguntas que mais ouvi ok?&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Por onde eu começo?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Hoje temos uma oferta gigante de conteúdos pagos e gratuitos sobre desenvolvimento na internet, muitas vezes o desenvolvedor iniciante sente-se perdido sem saber o que realmente tem importância, o que estudo primeiro? Outro fator que atrapalha é o fato de escolher um curso que vai ensinar a LINGUAGEM, não a programar! Antes de escolher um curso para aprender a "linguagem da moda", dê um passo atrás e aprenda a programar antes de aprender a linguagem. Estude lógica de programação, aprenda as estruturas básicas. Veja, se uma pessoa sabe dirigir, ela pode trocar de carro e conseguirá dirigir um carro diferente, mesmo que isso exija uma certa curva de aprendizado e adaptação. Com as linguagens acontece basicamente isso! (É, eu sei, a curva de aprendizado pode ser maior ao trocar de linguagem mas a metáfora ainda vale!)&lt;br&gt;
Enfim, aprenda a lógica, as estruturas de dados, estruturas de repetição, estruturas de desvio de fluxo, tipos de dados pois no final das contas é isso que o programador utiliza no seu cotidiano independente da &lt;strong&gt;LINGUAGEM&lt;/strong&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Preciso ter faculdade?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Bem gente, esse tema é polêmico e já adianto que, como eu fiz, não conheço muito o outro lado da força rs! Contudo trabalho com profissionais muito competentes que não cursaram   faculdade, mas... acredito que a faculdade seja sim  facilitador e se você aí iniciante puder FAÇA! Os cursos superiores oferecem aos alunos um encadeamento lógico dos conhecimentos além de focar bastante justamente nos aspectos mencionados no tópico anterior, criando uma base sólida de conhecimentos indispensáveis a todo dev, ou seja oferece uma trilha a ser percorrida durante o curso facilitando a assimilação do conhecimento. Além disso, o curso vai agregar conhecimentos em outras áreas,  que também serão importantes na caminhada profissional de um desenvolvedor. É importante aprender sobre administração, matemática, inglês etc. Mas... CUIDADO os cursos superiores tem uma tendência de serem muito teóricos, então tenha em mente que será preciso colocar a mão na massa e praticar tudo que for visto durante o curso OK?&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Mas afinal, qual linguagem escolher?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Bem, após adquirir os conhecimentos que mencionei acima, finalmente chega a hora de programar de VERDADE! E aí uma linguagem faz-se necessária! Aqui, meu conselho é realizar uma pesquisa no mercado, veja quais linguagens estão sendo mais utilizadas, veja as que as empresas mais utilizam e faça a sua escolha! Nesse ponto escolher uma linguagem com tipagem dinâmica e fraca pode ajudar o dev iniciante a enfrentar menos problemas e se frustrar menos no início. Hoje no mercado temos o JavaScript e o Python (tipagem dinâmica mas &lt;strong&gt;forte!&lt;/strong&gt;) que na minha visão são excelentes portas de entrada por serem mais flexíveis e permissivas com pequenos deslizes do programador iniciante!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Finalizando&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Agora um último conselho, seja qual for a linguagem PROGRAME!  De nada adianta ter feito mil cursos apenas assistindo aulas, ou ter lido uma montanha de livros e artigos, o que vai te dar fluência em programação, aqui de novo INDEPENDENTE DA LINGUAGEM, é a prática! É na prática que você vai sentir as dores do dia a dia e aprender com elas para se tornar a cada dia um programador melhor.&lt;/p&gt;

&lt;p&gt;Por hoje é isso pessoal, lembrando que o exposto nesse humilde post é minha OPINIÃO com base no que vivenciei ao longo da minha trajetória no desenvolvimento e tem o intuito de ajudar padawans iniciantes ! Até Mais!&lt;/p&gt;

</description>
      <category>begin</category>
      <category>development</category>
      <category>learn</category>
    </item>
  </channel>
</rss>
