AWS Elastic Beanstalk + Go
Tags: aws, go, awscli, elasticbeanstalk
Published: 2021-01-06 01:44:04

Foto de capa: [Gelgas Airlangga](https://www.pexels.com/pt-br/@gelgas)

Vamos lá para um pequeno tutorial ensinando o passo-a-passo de como subir uma aplicação Go no serviço Elastic Beanstalk da AWS.
Vou utilizar o [AWS CLI](https://github.com/aws/aws-cli) porque acho legal para a pessoa que está iniciando saber exatamente todas as coisas que acontecem. Até porque se você em algum momento quiser utilizar Terraform, já tem uma boa idéia do que você vai precisar utilizar da AWS.

Antes de começarmos a ver código e comandos, quero pontuar aqui algumas coisas:
- Estou escrevendo este tutorial considerando que você já tem uma conta na aws. Para resumir, aqui não estou ensinando a criar uma conta.
- Também considero que você já tem instalado o AWS CLI. Se não tiver, basta seguir a [documentação oficial em português](https://docs.aws.amazon.com/pt_br/cli/latest/userguide/cli-chap-install.html) que não tem mistério.
- Por fim considero que você está ciente que **a execução destes serviços na AWS podem resultar em custos**. No meu caso, só para rodar os comandos desse tutorial para validar que está tudo funcionando me custou U$0.10 e eu terminei tudo logo em seguida para não gerar mais custos.

Hoje a trilha sonora é _Anti-Flag - Turncoat_.

---

## Escrevendo a aplicação para usar de exemplo

O código do exemplo é uma coisa bastante simples, apenas 2 endpoints: um de health check e outro para hello world.
Vamos criar um arquivo chamado `application.go` e escrever o código abaixo.

```golang
package main

import (
	"fmt"
	"net/http"
)

func main() {
	fmt.Println("Hello World")
	http.HandleFunc("/hello-world", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Hello world!")
	})
	http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "OK")
	})
	_ = http.ListenAndServe(":5000", nil)
}
```

Caso você ainda não conheça muito de Go, o código dentro da função _main_ está mapeando 2 endereços, no caso `/hello-world` e `/health`. As linhas com `fmt.Fprintf` são responsáveis pela mensagem que será exibida na tela.
Logo depois do mapeamento estamos dizendo que a aplicação vai ficar ouvindo a porta 5000.

**Atençãããão!!! Tem alguns detalhes até aqui.**

#### Por que o arquivo se chama `application.go` e não `maldicao.go`?

A documentação da AWS diz que existem algumas formas de fazer deploy da aplicação. 
A que eu escolhi para este exemplo eu achei ser a mais simples de todas, que é dar o nome de `application.go` para o arquivo principal. Isso porque quando o Elastic Beanstalk for construir (_"buildar"_) a aplicação, ele vai rodar por padrão esse comando aqui: `go build -o bin/application application.go`, ou seja, o Elastic Beanstalk já ta lá esperando encontrar esse arquivo com esse nome.

#### E a porta, por que é 5000 e não 8123?

Mesma situação que o nome do arquivo. Por padrão o Elastic Beanstalk inicia a aplicação na porta 5000.

[Clique aqui](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/go-environment.html) caso queira ler a documentação oficial da AWS sobre isso que expliquei acima. 
Aliás, eu recomendo pare para ler a documentação sempre que estiver estudando algo. Ás vezes a pessoa que está escrevendo o tutorial, tipo eu agora, acaba deixando algo passar, ou entendeu algo errado ou ainda o tutorial pode estar desatualizado, então crie o hábito de validar na documentação. Isso vai agregar um conhecimento legal para você! :)

Ah, antes de irmos para os comandos AWS CLI, também vamos precisar criar um arquivo chamado `options.json`. Ele é necessário para informar qual profile IAM nossa aplicação vai utilizar. Se você não sabe o que é IAM, não se preocupe, isto é assunto para outro tutorial.
Coloque isto dentro do arquivo:
```json
[
  {
      "Namespace": "aws:autoscaling:launchconfiguration",
      "OptionName": "IamInstanceProfile",
      "Value": "aws-elasticbeanstalk-ec2-role"
  }
]
```
---

## Utilizando Elastic Beanstalk

Beleza! Código feito, vamos para a parte tão aguardada: como fazer deploy desse código no Elastic Beanstalk.

**Passo 1**: gerar um `.zip` com o nosso código fonte. Este `.zip` será enviado para a AWS e pode ter o nome que você preferir. 
No caso do meu exemplo eu só tenho dois arquivos para colocar no `.zip`: `application.go` e `go.mod`.

No terminal, navege até a raiz do projeto e execute:
```bash
zip -r application.zip .
``` 

**Passo 2**: criar um S3 Bucket para enviar o arquivo `.zip`. Você pode criar com o nome que você quiser, eu fiz uma mistura de nome legível + o final de um UUID que gerei no Google e ficou assim: beanstalk-app-660390121deb.
O comando para criar o Bucket: 
```bash
aws s3api create-bucket --bucket beanstalk-app-660390121deb --create-bucket-configuration LocationConstraint=us-west-2
```
No caso `--bucket` serve para dizer qual é o nome desejado. Caso você esteja utilizando alguma região diferente de _us-east-1_, é necessário também adicionar o `--create-bucket-configuration LocationConstraint=AQUI_A_SUA_REGIAO` para indicar a região correta.

**Passo 3**: enviar o `.zip` para o Bucket.
Esse passo é muito fácil, só executar aí:
```bash
aws s3 cp application.zip s3://beanstalk-app-660390121deb/
```

**Passo 4**: chegou a hora de criar uma aplicação dentro do Elastic Beanstalk. Esse passo também é bastante simples:
```bash
aws elasticbeanstalk create-application --application-name minha-app-muito-legal --region us-west-2
```

**Passo 5**: criar uma versão da aplicação no Elastic Beanstalk, apontando para o arquivo `.zip` no S3 Bucket.
Na real, isso significa que você está falando que a **v1** por exemplo, utiliza o arquivo `minha_app_v1.zip` por exemplo. Aí depois se você for mexer no seu código e quiser subir uma v2, você poderia subir no Bucket um arquivo `minha_app_v2.zip` e fazer esse "link" com este comando aqui gerando uma **v2**, só precisaria alterar aqui no comando o parâmetro passado em `--version-label`.
O comando para criar a versão v1: 
```bash
aws elasticbeanstalk create-application-version --application-name minha-app-muito-legal --version-label v1 --source-bundle S3Bucket=beanstalk-app-660390121deb,S3Key=application.zip
```

**Passo 6**: chegou a hora de criar um environment no Elastic Beanstalk. O comando é:
```bash
aws elasticbeanstalk create-environment --application-name minha-app-muito-legal --environment-name staging --option-settings file://options.json --version-label v1 --solution-stack-name "64bit Amazon Linux 2 v3.1.4 running Go 1"
```
Explicando melhor: estamos passando por parâmetro o nome da aplicação que estamos ligando neste novo environment. No `--application-name` eu digo qual é a aplicação que eu quero rodar, no `--environment-name` eu posso colocar o nome que eu quiser para o meu ambiente, no caso chamei de _staging_. Agora o `--solution-stack-name` é que requer um pouco mais de atenção. Este é o nome da stack que será utilizada no ambiente e deve ter um valor conhecido pelo Elastic Beanstalk. Você pode encontrar todas as opções disponíveis [nesta documentação](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/concepts.platforms.html). Basta clicar na linguagem que você tiver curiosidade que a doc vai mostrar as opções válidas.
Aqui também foi utilizado o arquivo `options.json` que criamos anteriormente e passamos no comando `--version-label v1` para dizer que o ambiente vai utilizar aquela versão que criamos no Passo 5. Se você deu um nome diferente de _v1_, vai precisar alterar aqui também.

**PRONTO!** Agora você já tem a aplicação rodando no Elastic Beanstalk.
Para o deploy acontecer (ou terminar os serviços), ás vezes demora um pouco. Você pode conferir o status pelo terminal com o comando abaixo:
```bash
aws elasticbeanstalk describe-environments
```
Ou se preferir, basta acessar o serviço Elastic Beanstalk no Console da AWS.

Na imagem abaixo que mostra o Console da AWS, fica fácil de obter diversas informações.
![Console da AWS mostrando Elastic Beanstalk](https://dev-to-uploads.s3.amazonaws.com/i/byeca62ium5ue40406xn.png)

Quando _health_  mudar para OK, sabemos que acabou o deploy e podemos testar a aplicação.
Já na coluna _URL_ temos o endereço da aplicação que vamos usar para testar.

Assim que a coluna _health_ ficar OK (talvez seja necessário recarregar a página), você já pode testar. É só copiar a URL ali da tabela e adicionar no final `/health` ou `/hello-world` que são os 2 endpoints disponíveis na aplicação.

Se deu tudo certo, você vai ver algo parecido com a imagem a seguir:
![Browser com tela mostrando Hello world!](https://dev-to-uploads.s3.amazonaws.com/i/g5acgczdnp8irn5mvxek.png)

Agora digamos que você queira adicionar um novo endpoint, ou remover. Vai precisar criar uma nova versão. Para isso você vai precisar repetir o Passo 1, criando um novo arquivo `.zip`, em seguida vai precisar executar o Passo 3 para enviar esse arquivo para o S3 Bucket. Em seguida vai precisar executar novamente o Passo 5 alterando o nome da versão no `--version-label`. E finalmente será necessário fazer a atualização da versão no environment com o comando abaixo, alterando `--version-label` para a versão desejada:
```bash
aws elasticbeanstalk update-environment --application-name minha-app-muito-legal --environment-name staging --version-label v2
```
**NAO ESQUEÇA DE TERMINAR A APLICAÇÃO!**

Para evitar custos desnecessários, nunca esqueça de parar suas aplicações na AWS.
No nosso caso podemos fazer isso da seguinte forma para remover o environment:
```bash
aws elasticbeanstalk terminate-environment --environment-name staging
```
Agora vamos remover a aplicação do Elastic Beanstalk:
```bash
aws elasticbeanstalk delete-application --application-name minha-app-muito-legal
```

E por fim para remover o S3 Bucket:
```bash
aws s3 rb s3://beanstalk-app-660390121deb --force
```
Nesse caso é necessário utilizar `--force` para remover o Bucket e deletar os arquivos existentes. Sem este parâmetro é necessário primeiro esvaziar o Bucket para depois remover ele.

---

![The horns](https://dev-to-uploads.s3.amazonaws.com/i/59ubznd5w3h8h33ss1d8.gif)

Agora você já conhece todos comandos necessários para realizar o deploy utilizando AWS CLI.
Este foi um exemplo bastante simples. Agora você pode expandir conforme a necessidade, adicionando na aplicação um banco de dados ou fila SQS, por exemplo.

Outra possibilidade de continuação dos estudos seria transformar todos estes comandos em "receitinhas" no [Terraform](https://www.terraform.io/). 

Espero que você tenha curtido essa experiência! Tudo de bom para você! :)