Article image

EM

Eduardo Matsuoka05/04/2024 00:59
Compartilhe

Como hospedar projetos pessoais gratuitamente usando o AWS Lambda e Chalice

  • #AWS
  • #AWS Lambda

Introdução

 

Como hospedar meus projetos pessoais na AWS sem pagar nada? Um dos elementos mais limitantes para um desenvolvedor deixar disponíveis seus projetos pessoais na web é o custo do servidor, principalmente os custos mensais de um banco de dados SQL. Os serviços de hospedagem tradicionais podem cobram por projeto hospedado, que pode ficar caro no caso de muitos projetos rodando ao mesmo tempo, ou então oferecer um serviço gratuito, mas com muitas limitações, como baixo desempenho, bloqueio de certos recursos ou limitações no número de projetos hospedados na mesma conta.

Por outro lado, projetos pessoais geralmente possuem baixo tráfego, e seria um desperdício contratar um servidor que roda 24 horas por dia e 7 dias por semana apenas para atender alguns poucos acessos por mês.

Uma solução é usar o AWS Lambda como elemento principal para conectar diversos serviços da AWS, aproveitando os Free Tiers que a AWS disponibiliza, o que significa que você pode usar gratuitamente os serviços deles, contato que não passe de um certo nível de utilização. Esses níveis são bastante generosos e é possível ter um projeto com um tráfego baixo/médio e ainda assim permanecer dentro dos limites do Free Tier.

image

Para se ter uma ideia, é possível ter até 1 milhão de solicitações por mês no AWS Lambda sem ultrapassar o limite grátis.

E se meu projeto ultrapassar a cota? Você só pagará o que ultrapassar do limite e a conta não deve passar de alguns reais por mês, pois os serviços são precificados em milhares de utilizações por mês.

O que é o AWS Lambda?

AWS Lambda permite executar código ao receber um evento, sem a necessidade de gerenciar servidores. Ele pode ser usado com diversas linguagens de programação como Node.js, Python, Go ou Java. O código deve estar contido em uma função e essa função é chamada ao receber um evento. Se uma função começar a receber um alto número de solicitações, a AWS automaticamente irá aumentar a capacidade do serviço, sem a necessidade que um desenvolvedor intervenha, e pode diminuir a capacidade, caso a demanda diminua.

No nosso caso, estamos falando em aplicações web, mas o AWS Lambda também pode ser usado para:

  • Processamento de arquivos, como converter arquivos de um formato para outro
  • Processar logs de dados
  • Enviar e-mails a partir de eventos em conjunto com o AWS SES
  • Executar tarefas que devem ser realizadas em certos intervalos de tempo
  • Responder a eventos de outros serviços AWS

Vantagens ao usar serviços serverless

 

Apesar de serverless significar "ausência de servidor", na verdade existe uma frota de servidores que hospeda o AWS Lambda e outros serviços serverless, mas nós não precisamos gerenciar nada em relação a esses servidores. Configurar, manter e atualizar esses servidores são tarefas da AWS, o que nos deixa livres para pensar o que faz nossos projetos serem únicos e interessantes.

Dito isso, porque é vantajoso escolher um serviço serverless?

  • Confiabilidade: A AWS oferece serviços com alta disponibilidade, ou seja, que dificilmente saem do ar. As maiores empresas de tecnologia do mundo, como o Facebook ou a Netflix usam seus serviços.
  • É um serviço gerenciado: Posso focar em criar funcionalidades para o meu projeto e deixo para a AWS tarefas braçais como: configurar o servidor, instalar atualizações de sistema e manter a infraestrutura segura
  • Pago somente o que usar: O custo é calculado pelo tempo que o código roda em milissegundos ao receber uma solicitação. Se o serviço não é acionado, não há custo
  • Usa padrões do mercado: Aprendendo sobre AWS, aprendo o que a maioria das empresas usa, somando muitos pontos no meu currículo de desenvolvedor
  • Sem limitações: Se necessário, minha aplicação pode ter os mesmos recursos e desempenho que estão disponíveis para as líderes do mercado de tecnologia

 

Substituindo seu framework web pelo AWS Chalice

 

O AWS Lambda é muito conhecido por executar tarefas simples, como converter o formato de um arquivo ou responder um evento, como registrar no banco de dados a criação de um arquivo no AWS S3, mas é possível também coordenar diversas funções Lambda para funcionar como um framework web, graças ao AWS Chalice.

O AWS Chalice é um microframework Python bastante similar ao Flask, bastante conhecido no mundo Python. Com ele, é possível:

  • Criar aplicações com poucas linhas de código
  • Integrar com outros serviços AWS de maneira simples
  • Criar ou destruir funções Lambda com um único comando
  • Evitar ter que configurar manualmente as funções Lambda pela interface web da AWS
  • Cria automaticamente as permissões necessárias na AWS para que tudo funcione sem sua intervenção
  • Testar localmente as rotas da API
  • Cria automaticamente uma API na Amazon API Gateway

Pensando em uma arquitetura MVC (Model-View-Controller), o Chalice representa o View. Cada função escrita usando o Chalice é uma função Lambda, que responde a solicitações feitas nas rotas que foram disponibilizadas. Vamos olhar um exemplo prático para entendermos melhor o que isso representa.

 

Exemplo prático de uma API criada com o AWS Chalice

 

Vamos ver um exemplo prático de uma API REST que cria usuários e os armazena em um banco de dados DynamoDB, que é um banco de dados serverless. Caso queiram um passo-a-passo, a documentação do Chalice explica todas as etapas. Nesse exemplo temos uma rota GET e uma rota POST e cada rota é uma função Lambda:

 

import boto3
from chalice import Chalice
 
 
app = Chalice(app_name='projeto-teste')
# Integração com o DynamoDB
dynamodb = boto3.resource('dynamodb')
 
# A tabela do DynamoDB que será utilizada para armazenar o dados
tabela_dynamodb = dynamodb.Table(os.environ.get('NOME_DA_TABELA'))
 
// Rota para requisicao POST
@app.route('/usuarios', methods=['POST'])
def cria_usuario():
 """ Cria usuario na tabela do DynamoDB """
 # Pega os dados em json do corpo do request
 request = app.current_request.json_body
 
 # Cria um usuario
 item = {
     'PK': f'User#{request["usuario"]}',
     'SK': f'Profile#{request["usuario"]}',
 }
 
 # O usuario é criado ou atualizado no banco de dados
 tabela_dynamodb.put_item(Item=item)
 
 # Retorna dicionario vazio
 return {}
 
// Rota para solicitacoes GET
@app.route('/usuarios/{usuario}', methods=['GET'])
def get_usuario(usuario):
 """ Pega usuario do banco de dados """
 # Cria uma chave para a busca
 key = {
     'PK': f'User#{usuario}',
     'SK': 'Profile#{usuario}',
 }
 
 # Pega o usuario do banco de dados
 item = tabela_dynamodb.get_item(Key=key)['Item']
 
 # Retorna usuario 
 return item
 

 

 

Pronto! Nossa API está definida e agora é só dar o comando chalice deploy para a aplicação seja criada na AWS. Ao fazer o deploy, o Chalice criará as funções Lambda, bem como as permissões e retornará com a URL para que você possa começar a fazer a requisições. Caso queira eliminar os serviços criados, é só usar o chalice delete e todos os serviços criados serão eliminados da sua conta AWS. Essa facilidade representa uma economia de tempo considerável se comparado à criar as funções Lambda manualmente pela interface web da AWS.

O AWS Chalice cria a seguinte arquitetura com um único comando:

image

Note que o código cria em poucas linhas a referência para o banco de dados DynamoDB e as tarefas de buscar ou inserir o usuário são feitas em uma única linha. É possível integrar com diversos outros serviços AWS, como armazenamento de arquivos, serviços de fila, mensageria, autenticação e outros, todos com a mesma simplicidade. Caso quiséssemos retornar uma página web, podemos armazenar os arquivos HTML, CSS e JavaScript no AWS S3 e retornar esses arquivos em resposta a cada solicitação.

Você pode estar se perguntando se o Chalice vai criar e configurar o banco de dados DynamoDB que é usado pela minha aplicação. A resposta é não nesse exemplo: o DynamoDB e a tabela que deve conter os dados já precisam estar criados na AWS. No entanto, usando o AWS CDK, é possível criar esses serviços com a mesma facilidade que o Chalice criou as funções Lambda, evitando o trabalho manual de criar e configurar manualmente pela interface web.

O que é o AWS CDK?

O AWS CDK (Cloud Development Kit) é um framework que permite criar serviços na AWS com código usando os princípios da POO (Programação Orientada à Objetos). Toda a infraestrutura necessária é definida de uma maneira resumida em código, usando configurações padrão para que o código seja sucinto, e facilitando a administração da infraestrutura criada. Vamos ver um exemplo em Python que cria uma tabela no DynamoDB na nossa aplicação para entendermos melhor:

import os
 
from aws_cdk import (
 aws_dynamodb as dynamodb,
 core as cdk
)
from chalice.cdk import Chalice
 
RUNTIME_SOURCE_DIR = os.path.join(
 os.path.dirname(os.path.dirname(__file__)), os.pardir, 'runtime')
 
# Essa classe representa a nossa aplicação
class ChaliceApp(cdk.Stack):
 
 def __init__(self, scope: cdk.Construct, id: str, **kwargs) -> None:
     super().__init__(scope, id, **kwargs)
     # Cria tabela no DynamoDB
     self.dynamodb_table = self._create_ddb_table()
     self.chalice = Chalice(
         self, 'ChaliceApp', source_dir=RUNTIME_SOURCE_DIR,
         stage_config={
             'environment_variables': {
                 # Cria variável de ambiente com o nome da tabela
                 'APP_TABLE_NAME': self.dynamodb_table.table_name
             }
         }
     )
     # Cria permissão para que seja possível ler e escrever na tabela
     self.dynamodb_table.grant_read_write_data(
         self.chalice.get_role('DefaultRole')
     )
 
 # Executado ao criar uma tabela
 def _create_ddb_table(self):
     dynamodb_table = dynamodb.Table(
         self, 'AppTable',
         partition_key=dynamodb.Attribute(
             name='PK', type=dynamodb.AttributeType.STRING),
         sort_key=dynamodb.Attribute(
             name='SK', type=dynamodb.AttributeType.STRING
         ),
         removal_policy=cdk.RemovalPolicy.DESTROY)
     cdk.CfnOutput(self, 'AppTableName',
                   value=dynamodb_table.table_name)
     return dynamodb_table

No código acima definimos os serviços que devem constar na nossa aplicação ao criar a classe ChaliceApp, criamos uma tabela do DynamoDB, definimos uma variável de ambiente com o nome AppTable, que pode ser acessado do Chalice e, por fim, criamos as permissões necessárias para que a tabela possa ser lida ou modificada pela aplicação.

O CDK organiza hierarquicamente a infraestrutura. Cada serviço é um Construct, que está dentro de um Stack, que por sua vez, está dentro de um App:

image

Ao integrar o código que define a infraestrutura na nossa aplicação Chalice, estamos possibilitando que haja um versionamento da infraestrutura na nuvem. Se infraestrutura na AWS for modificada, podemos saber quando e reverter modificações que causaram problemas. Esse é um método que facilita muito a vida do desenvolvedor e aumenta a qualidade e estabilidade do projeto.

Ao usar o AWS CDK, a estrutura do nosso app serverless fica organizada da seguinte maneira:

├── infrastructure
│  ├── app.py # As definições de serviços AWS ficariam aqui
│  ├── requirements.txt #Dependências necessárias para definir a estrutura
├── runtime
│  ├── app.py # O código Chalice fica aqui
│  ├── requirements.txt # Dependências necessárias para o Chalice
└── requirements.txt # Contém referências para os dois arquivos requirements.txt

A pasta infrastructure contém tudo que é relacionado à criação de serviços AWS necessários para a nossa aplicação funcionar. Na pasta runtime, temos as definições de rotas que estarão disponíveis na aplicação e as funções que serão ativadas ao receber solicitações por essas rotas. Ao usar o AWS CDK, ao invés de usar o chalice deploy, iremos usar o cdk deploy. Isso irá criar toda a infraestrutura necessária e subir nossa aplicação Chalice para a AWS para que todo o deploy aconteça a partir de um único comando.

Desvantagens

Nem tudo são flores e há algumas desvantagens ao se optar pela abordagem serverless:

  • É necessário entender sobre diversos serviços AWS ao mesmo tempo
  • É necessária uma readaptação ao migrar de frameworks web tradicionais
  • Você estará preso à AWS, não é possível mudar essa aplicação para o Google Cloud ou Microsoft Azure sem fazer mudanças drásticas no código e na implementação
  • Os custos podem ser mais altos que um serviço não serverless, se a aplicação não for configurada corretamente ou receber um altíssimo número de solicitações
  • A documentação da AWS poderia ser melhor: pode conter informações desatualizadas ou informações importantes podem estar espalhadas em diversas páginas e artigos

 

Conclusão

Usando o AWS Chalice e o AWS CDK em conjunto, podemos integrar diversos serviços AWS ao tradicional AWS Lambda, de forma elegante e simples. Com essa facilidade, podemos dizer que temos disponível um framework web extremamente poderoso em mãos, altamente integrado à AWS.  

Apesar de exigir um investimento inicial de tempo para aprender sobre os conceitos da AWS e do serverless, certamente vale a pena usar esses serviços, pois uma vez dominada a tecnologia, é possível:

  • Criar rapidamente diversos tipos de aplicações a um custo muito reduzido
  • As aplicações criadas demandam menos atenção do desenvolvedor, uma vez que uma grande carga de trabalho foi repassada para à AWS
  • Economizar, pois não é mais necessário pagar por um serviço ocioso e por especialistas em DevOps ou banco de dados
  • Terminar os serviços a qualquer momento, sem a necessidade de pagar multas contratuais
  • Oferecer uma tecnologia que é buscada por muitas empresas que querem diminuir seus custos operacionais
  • Subir aplicações em produção de maneira rápida, além de criar ambientes de teste sem esforço, pois a infraestrutura está definida em código

 

 

Compartilhe
Comentários (2)
Victor Silva
Victor Silva - 05/04/2024 10:41

Parabéns!

Muito esclarecedor o artigo.


Regilene Silva
Regilene Silva - 05/04/2024 08:47

Muito completo teu artigo! Muito útil!