Desenvolvendo a Infraestrutura¶
Sobre o Projeto¶
O Projeto a seguir visa aplicar conceitos de Computação em Nuvem (Cloud Computing) por meio da plataforma de serviços de Computação em Nuvem AWS (Amazon Web Services). A ideia é subir uma aplicação sem servidor na AWS utilizando o S3, Lambda, API Gateway e o CloudWatch colocando em prática os conceitos de IaaC (Infrastructure as a Code) por meio do Terraform. O diagrama visual da aplicação pode ser conferido a seguir:
Desenvolvendo a infraestrutura¶
1. Pré-requisitos¶
- Para rodar nossa infraestrutura, estamos utilizando o Ubuntu 22.04.2 LTS (o qual já estava instalado no nosso Windows). A infra pode funcionar em outras versões, porém não há garantia de funcionamento. Assim sendo, indicamos o uso da versão supracitada para testar nossa aplicação (e até mesmo para criar e rodar a sua própria).
-
Conta no Github (+ token de autorização, se necessário, com permissão de criação e atualização de repositórios), caso você desejar subir e deixar o projeto registrado.
-
Node.js instalado na máquina. (no caso, instalei diretamente dentro do Ubuntu 22.04.2 LTS via terminal).
-
Terraform instalado na máquina (no caso, instalei diretamente dentro do Ubuntu 22.04.2 LTS e explico no próximo tópico como fazer você também).
2. Instalação do Terraform¶
A primeira etapa para desenvolvermos essa aplicação é instalar o Terraform na máquina. O Terraform é uma ferramenta de gerenciamento de infraestrutura como código (IaC) desenvolvida pela HashiCorp. Ele permite que os usuários definam, configurem e provisionem infraestruturas de forma automatizada e reprodutível, usando uma linguagem declarativa e uma sintaxe simples. Com o Terraform, é possível criar e gerenciar recursos em diferentes provedores de nuvem, como AWS, Google Cloud, Azure e outros, bem como em plataformas de infraestrutura, como Kubernetes, Docker e OpenStack. Em resumo, o Terraform é uma ferramenta importante para automatizar e gerenciar infraestruturas de nuvem e outras plataformas de infraestrutura, tornando a gestão de infraestrutura escalável, segura e repetível. Sim, é o Terraform quem irá nos auxiliar a não ter que ficar fazendo tudo manualmente no dashboard da AWS, como acabamos de fazer na página anterior.
Caso você não possua o Terraform no seu computador, é necessário baixar e instalar de acordo com o tutorial presente neste link (Windows) ou diretamente neste link (Ubuntu/Linux - Recomendado).
3. Utilização¶
Após a instalação do Terraform na máquina, já é possível rodar a infraestrutura desenvolvida ou criar sua própria infraestrutura com base em tudo que está sendo apresentado aqui.
O primeiro passo é clonar este repositório em uma pasta dentro do seu computador. Caso não saiba como clonar um repositório na sua máquina local, acesse o tutorial presente neste link ou faça o download do respositório e descompacte o arquivo .zip no local desejado.
Dica
Caso você desejar criar a infraestrutura do zero, segui e sugiro a seguinte estrutura de pastas:
Cloud-Project
│
│
└───hello
│ |---function.js
│
└───s3
| │---function.js
│
│───Terraform
│ |---api-gateway.tf
│ |
│ |---hello-api-gateway.tf
│ |
│ |---hello-lamba.tf
│ |
│ |---lambda-s3-bucket.tf
│ |
│ |---provider.tf
│ |
│ |---s3-lambda.tf
│ |
│ |---test-bucket.tf
│ |
│ |---terraform.sh
Independentemente se você escolheu clonar o repositório com a infraestrutura original ou se tiver escolhido criar do zero, lembre-se que tudo deve ser feito dentro do prompt de comando do Ubuntu 22.04.2 LTS caso deseje chegar nos mesmos resultados apresentados aqui sem grandes riscos de problemas.
Credenciais AWS no Terraform¶
Antes de darmos início, é necessário cadastrar suas credenciais AWS na sua máquina. Temos várias formas de fazer isso, porém iremos optar pela alternativa que eu considero mais segura para quem está iniciando na AWS (incluindo eu mesmo): cadastrar diretamente via terminal. Sim, pode haver várias outras formas de fazer isso, então se você considera alguma outra melhor, fique à vontade.
Você deve possuir um .csv com a chave de acesso (Secret Key) e a chave secreta (Secret Access Key) de acesso da sua conta AWS, precisaremos dessas informações agora.
Aviso
A partir de agora, todos os comandos que utilizarmos ou alterações realizadas via prompt de comando deve ser feitas dentro da pasta que designamos para trabalhar neste projeto. Eu optei por trabalhar dentro da raiz da minha máquina, ou seja, dentro do meu diretório, estou trabalhando na seguinte pasta:
root@Lister:/mnt/c/Computacao_em_Nuvem/testando-o-projeto-01/Cloud-Project
Dica
Para manipular arquivos dentro do terminal do Ubuntu, utilize os comandos:
cd → Para navegar entre as pastas dentro do seu computador;
ls → para visualizar os arquivos dentro das pastas;
Exemplo de uso:
cd /mnt/c → Entrei na raiz do meu computador;
cd .. → Sai da raiz e "voltei um caminho", ou seja, agora estou no diretório "/mnt";
code . → Abre toda sua pasta dentro do VS Code (isso sempre me ajuda muito).
Dentro do terminal Ubuntu, insira os comandos:
Após o comando acima, serão solicitadas as suas chaves de acesso. Coloque-as no terminal como solicitado e bora trabalhar!
Rodando a aplicação (se você desejar APENAS rodar a infra já criada)¶
Caso você desejar criar a infra (tal como sugerido e explicado detalhadamente neste handout), vá para a aba "Criando a infraestrutura do zero" e continue o handout. Caso desejar apenas rodá-la, entre na pasta que você clonou a infra e, dentro do diretório "Cloud-Project/terraform" rode os seguintes comandos:
E, em seguida, rode:
The terraform plan command creates an execution plan, which lets you preview the changes that Terraform plans to make to your infrastructure. (Texto extraído do site da Hashicorp)
O comando terraform plan cria um plano de execução, que permite visualizar as alterações que o Terraform planeja fazer em sua infraestrutura. (Texto traduzido do site da Hashicorp)
E, para finalizar, rode:
Após tudo ter funcionado, a infra foi construída na AWS, agora é só testar!
Dica
Entre na sua dashboard da AWS, verifique todos os serviços criados e tente entender como tudo foi criado e o que está acontecendo entre os serviços (para isso, observar o diagrama apresentado no início do handout pode ajudar).
Para testar, digite no terminal:
curl -X POST \
-H "Content-Type: application/json" \
-d '{"name":"Insper"}' \
"https://<id>.execute-api.us-east-1.amazonaws.com/dev/hello"
/\
||
Substitua <id> pelo seu id retornado no prompt de comando
Dica
Além do prompt de comando, teste também diretamente no seu navegador! Para fazer isso, basta substituir a url que foi retornada e passar algum parâmetro após "Name", da seguinte forma:
https:// SEU-ID-AQUI .execute-api.us-east-1.amazonaws.com/dev/hello + o parâmetro ?Name=Lister
Por exemplo:
https://2cmcnumb2l.execute-api.us-east-1.amazonaws.com/dev/hello?Name=Lister
Podemos também invocar essa função com o nome do bucket reebido no prompt de comando + nosso objeto para ver se o lambda conseguirá obter o objeto do bucket.
aws lambda invoke \
--region=us-east-1 \
--function-name=s3 \
--cli-binary-format raw-in-base64-out \
--payload '{"bucket":"test-<your>-<name>","object":"hello.json"}' \
response.json
/\
||
Substitua test-<your>-<name> pelo nome do seu bucket
Rode no terminal o seguinte comando:
Se você receber como retorno Yeah, I am working from Insper, Avelinux :), parabéns, você concluiu sua aplicação e ela está funcionando!
Dica Visual
Se entrarmos no dashboard do CloudWatch novamente, conseguiremos ver os logs de acesso registrados para nossas solicitações.
Criando a infraestrutura do zero¶
Criando uma função Lambda no Terraform¶
O primeiro passo será criarmos uma função lambda que, futuramente, será integrada com o AWS API Gateway.
Mas o que é o "Lambda"?
A AWS Lambda é um serviço de computação sem servidor que permite executar código de forma escalável e sem a necessidade de gerenciar servidores. Ela é projetada para responder a eventos específicos, como alterações em um bucket do Amazon S3 ou atualizações em uma tabela do Amazon DynamoDB.
Inicialmente, começaremos com uma função simples baseada em NodeJS sem nenhuma dependência.
Ao invocar essa função com uma consulta de URL e com o parâmetro Name definido, ela retornará "Hello, Name!".
Também será verificado o método HTTP GET e POST para que seja verificada a resposta padrão. Foi especificado o código de status '200', tipo de conteúdo e a mensagem para ser retornada ao chamador.
Criando o provider¶
Agora que nossa handler já está pronta, começaremos a trabalhar em alguns elementos do nosso Terraform. Criaremos os arquivos .tf dentro de uma pasta intitulada (por motivos intuitivos, claro) como "terraform".
Começaremos criando o arquivo "provider.tf", em que serão declaradas as restrições de versão (região da AWS, por exemplo) para os diferentes provedores AWS, versões de Teraform e afins.
Isso é feito apenas para que, caso alguém pegue esse projeto no futuro e rode em outra versão de Terraform ou com configurações diferentes das que foram aqui padronizadas, o projeto não funcione.
Bucket do S3¶
Agora nós construiremos uma função com todas as dependências, empacotaremos como um arquivo zip para que, assim, consigamos subir num bucket do S3. Ou seja, quando criamos o lambda, apontamos para esse objeto de arquvo zip no bucket S3.
Como os nomes dos buckets do S3 devem ser únicos e exclusivos no mundo inteiro, podemos utilizar um gerador aleatório para nos ajudar a nomear nosso bucket S3.
Em seguida, vamos criar o próprio bucket do S3 com o nome gerado.
Por padrão, deixaremos todo o acesso público ao bucket bloqueado.
IAM e Policies¶
Agora criaremos o código Terraform do lambda. Lembrando que o lambda exigirá acesso a outros serviços da AWS (como o CloudWatch, para gravar logs) e, no nosso caso, concederemos acesso ao bucket do S3 para que seja possível a leitura de um arquivo.
Para isso, precisamos criar uma função do IAM e permitir que o lambda a use.
Criando uma função Lambda¶
O próximo recurso será criar a função lambda, a qual chamaremos de "hello". Em seguida especificaremos o nome do intervalo onde armazenaremos todos os lambdas. E nosso key pointing irá apontar para um arquivo zip com uma função.
O hash do código-fonte foi adicionado para reimplementar a função caso seja alterado/atualizado algo no código-fonte. Se o hash do arquivo zip for diferente, a reimplantação do lambda será forçada.
Criando o CloudWatch¶
O CloudWatch é um serviço de monitoramento e observabilidade oferecido pela AWS. Ele permite que você colete e monitore métricas, registros e eventos de diferentes recursos e serviços da AWS, fornecendo insights valiosos sobre o desempenho, a saúde e a disponibilidade do seu ambiente de nuvem. Com o CloudWatch, você pode definir alarmes para acionar ações automáticas, criar painéis personalizados para visualizar dados em tempo real, além de acessar informações históricas para análise e solução de problemas. Ele é uma ferramenta fundamental para garantir o monitoramento proativo e a operação eficiente dos seus recursos na nuvem da AWS.
Para depurar, criamos um grupo de logs do CloudWatch que conseguisse armazenar todas as instruções e erros do console.log na função. Definimos a retenção para 30 dias, porém poderia ser uma quantidade maior ou menor também, a depender das intenções de quem está desenvolvendo a infraestrutura (além dessas decisões poderem afetar o custo de execução do lambda).
Em seguida, adicionaremos o recurso que empacota o lambda como um arquivo zip.
Nosso último componente visa obter o arquivo zip e carregar no bucket do S3.
Inicializando o Terraform¶
Com os passos feitos até aqui já conseguimos inicializar o terraform:
Agora aplicamos as alterações:
Dica visual
Quando o terraform concluir suas etapas até aqui, podemos entrar no dashboard da AWS e encontrar, dentre outras coisas, um bucket S3 recém-criado com um nome definido por meio de um gerador de animais de estimação aleatório. >
Para abstrair:
Note que dentro do bucket são armazenadas funções lambdas dentro de um zip.
Quando entramos na dashboard da AWS CloudWatch também conseguimos ver o grupo de logs criado.
No dashboard do AWS Lambda conseguimos ver a função lambda empacotada como um zip.
Vamos agora invocar a função com o comando aws lambda invoke.
Lembre-se de especificar ou conferir se o nome da região, função e arquivo estão corretos para registrar a resposta da função.
Ao printarmos a resposta, é esperado um retorno "Olá, Avelino!"
Criando o API Gateway¶
A próxima estapa será criar o API Gateway e integrá-lo ao nosso lambda.
O API Gateway é um serviço da AWS que permite criar, publicar, proteger e gerenciar APIs (Interfaces de Programação de Aplicativos). Ele atua como um ponto de entrada para os aplicativos acessarem funcionalidades e dados, fornecendo recursos como autenticação, autorização, limitação de taxa e transformação de dados. O API Gateway simplifica o processo de criação de APIs, permitindo que você se concentre na lógica do aplicativo, enquanto ele gerencia aspectos como escalabilidade, segurança e monitoramento. Com o API Gateway, é possível criar APIs RESTful ou WebSocket para integrar e expor seus serviços e recursos de forma segura na nuvem da AWS.
Integrando o API Gateway com o Lambda¶
No próximo arquivo Terraform, integraremos o API Gateway com o hello lambda. Primeiramente apontaremos para o ID do API Gateway que acabamos de criar. Em seguida utilizaremos PROXYS AWS e solicitações POST para encaminhar solicitações do API Gateway para o Lambda
Podemos especificar qual tipo de solicitações queremos passar para o lambda, por exemplo: GET ou POST, como abaixo:
Note que em ambos os exemplos é necessário especificar um destino para ser o nosso lambda. Também precisamos conceder permissões ao API Gateway para invocar nossa função lambda:
Invocando o Lambda¶
Por fim, vamos imprimir no console o URL que podemos usar para invocar o lambda.
No terminal, daremos um apply no terraform.
Dica visual
Se entrarmos no dashboard do API Gateway, podemos ver nosso estágio de desenvolvimento "dev" criado e, em "rotas", conseguimos encontrar os métodos GET e POST. > >
Até essa etapa, se você estiver seguindo a risca minha forma de fazer esse handout, é esperada que a estrutura do seu código esteja como na imagem abaixo:
Hora de testar¶
Vamos agora testar o método HTTP GET. A função deve analisá-lo e retornar a mensagem "Olá, + parâmetro de URL"
curl "https://<id>.execute-api.us-east-1.amazonaws.com/dev/hello?Name=InsperUniversity"
/\
||
Substitua <id> pelo seu id retornado no prompt de comando
Também testaremos o método POST. Nesse caso, fornecemos um objeto json para o terminal e veremos que funciona também.
curl -X POST \
-H "Content-Type: application/json" \
-d '{"name":"Insper"}' \
"https://<id>.execute-api.us-east-1.amazonaws.com/dev/hello"
/\
||
Substitua <id> pelo seu id retornado no prompt de comando
Dica
Além do prompt de comando, teste também diretamente no seu navegador! Para fazer isso, basta substituir a url que foi retornada e passar algum parâmetro após "Name", da seguinte forma:
https:// SEU-ID-AQUI .execute-api.us-east-1.amazonaws.com/dev/hello + o parâmetro ?Name=Lister
Por exemplo:
https://2cmcnumb2l.execute-api.us-east-1.amazonaws.com/dev/hello?Name=Lister
Dica visual
Se entrarmos no dashboard do CloudWatch, conseguiremos ver os logs de acesso registrados para nossas solicitações. > >
Criando função lambda com dependências externas e acesso ao bucket S3¶
Vamos agora criar outra função lambda com dependências externas e que garanta acesso para a leitura de um arquivo em um bucket S3.
Novamente, utilizaremos o random pet para nos auxiliar com um nome aleatório e único para nosso bucket do S3 e dicionaremos o prefixo "test" (o que também auxilia na identificação do bucket).
Para esse bucket também deixaremos o acesso público desativado.
Nós também podemos criar um objeto no S3 bucket utilizando terraform e o jsoncode build-in. Isso irá converter para um objeto json válido.
Agora iremos criar uma nova função lambda em uma nova pasta s3.
Começaremos importando o aws-sdk e inicializando o objeto javascript.
Essa função irá nos retornar o conteúdo do objeto.
Dentro do diretório da recém-criada pasta "s3", devemos inicializar o projeto nodejs com o seguinte comando:
Esse comando irá gerar arquivos package.json com dependências. Não há necessidade de preencher as informações solicitadas, basta teclar "enter" para cada info solicitada.
Em seguida, iremos instalar o módulo aws-sdk:
Agora retornaremos à pasta "Terraform" e iremos criar nossas políticas de acesso.
Vamos agora deployar diretamente na máquina local. Para isso será necessário criar um simples script wrapper no Terraform:
(No terminal, diretório /terraform) Vamos fazer o script se tornar executável:
Em seguida podemos rodar:
Note que, ao rodarmos o comando acima, ele automaticamente rodará nosso terraform.sh que possui um "terraform apply", aplicando imediatamente as alterações que fizemos, sem que tenhamos que utilizar novamente o comando "terraform apply" no terminal.
No terminal receberemos de volta o nome do nosso recém-criado bucket do s3. Podemos invocar essa função s3 com o nome do bucket + nosso objeto para ver se o lambda conseguirá obter o objeto do bucket.
aws lambda invoke \
--region=us-east-1 \
--function-name=s3 \
--cli-binary-format raw-in-base64-out \
--payload '{"bucket":"test-<your>-<name>","object":"hello.json"}' \
response.json
/\
||
Substitua test-<your>-<name> pelo nome do seu bucket
Por fim, rode no terminal o seguinte comando:
Se você receber como retorno Yeah, I am working from Insper, Avelinux :), parabéns, você concluiu sua aplicação e ela está funcionando!
Dica Visual
Se entrarmos no dashboard do CloudWatch novamente, conseguiremos ver os logs de acesso registrados para nossas solicitações.
Agora que você já viu todo o ambiente da sua IaaC (Infrastructure as a Code) sendo criado e funcionando, chegou a hora de destruí-lo!
Utilize o comando a seguir no seu terminal para destruir a infraestrutura:
O resultado final deve ser algo parecido com a imagem a seguir:
Dica visual
Entre no dashboard da AWS e veja que todos os recursos sumiram: eles foram destruídos!
Conclusão¶
Parabéns, você acaba de construir (e destruir também) toda uma infraestrutura serverless na AWS! E aí, está se sentindo mais preparado para dar início aos seus próprios projetos?
Você viu como foi bem mais fácil construir toda nossa infraestrutura rodando apenas um conjunto de códigos de uma só vez ao invés de criar serviço por serviço via dashboard da AWS?
A intenção do handout acima era justamente essa! Queria mostrar pra vocês como o uso do Terraform facilita - e muito - o nosso trabalho e também mostrar um pouco o poder do uso da Computação em Nuvem. Lembre-se que o universo Cloud é imenso e possui milhares de possibilidades, então não se restrinja apenas a criar aplicações sem servidor ou sites estáticos! Conheça novos serviços e começe a desfrutar cada vez mais do incrível poder que a Computação em Nuvem pode te oferecer! (E olha que eu nem estou sendo patrocinado para falar tudo isso aqui! Alô @AWS, cadê meu cachê??!!)
Antes de finalizar, confira a seção "Vídeos de aprofundamento" (caso você ainda não tenha conferido) para entender um pouco melhor (e de forma mais visual) o mundo da Computação em Nuvem. Também recomendo conferir a aba "Referências", lá eu deixei vários links que me ajudaram a compreender muito mais a fundo tudo que eu estava desenvolvendo na AWS (e tudo que vocês viram neste handout) durante as últimas 2 semanas (sim, até 2 semanas atrás eu não entendia absolutamente nada de AWS, então se eu consegui aprender tudo isso até aqui, você também consegue).
Por hoje é só! Espero que tenham gostado de todo o material que eu montei aqui. Até a próxima! Tchau :)