Simulando AWS local com localstack e Node.js

5 minutos leitura

Nesse artigo quero compartilhar como aprendi a trabalhar com o Localstack com Node.js para testar funções serverless e outros serviços da Amazon Web Service. Se você trabalha com desenvolvimento de aplicações na AWS, aprender a testar os serviços como SQS, S3 ou Lambda primeiro na sua máquina, é uma ótima estratégia para acelerar seu fluxo de desenvolvimento.

Recentemente acabei testando pela AWS um projeto que estou em fase de desenvolvendo, embora eu tenha separado meus ambientes (dev, stage e prd), isso me custou quase US$ 100, se considerar que o dólar no momento que escrevo este post passa dos R$ 5,10, imagine minha cara de tristeza quando vi o Billing na AWS, por pura bobeira. 🙁

Esse artigo foi escrito com exemplos em Node.js e comandos do AWS CLI, se você tiver alguma dificuldade de compreender, deixe um comentário explicando sua dúvida que vou te ajudar.

Introdução ao Localstack

O Localstack é um framework que fornece uma estrutura de testes e simulação de serviços da AWS, direto na sua máquina local. Desta forma se você quer aprender a trabalhar com os serviços da AWS, é uma ótima opção, além de evitar custos desnecessários em sua conta.

O diagrama a baixo ilustra um pipeline de desenvolvimento, integração e implantação, usando o LocalStack, uma clássica imagem vista no site oficial.

diagrama localstack

Com o Localstack, você pode executar funções Lambda, armazenar dados em tabelas no DynamoDB, armazenar arquivos no S3, configurar o API Gateway e muito mais. Tudo acontecendo em sua máquina local.

A lista de serviços suportados no momento que escreve este artigo contém 25 serviços, entre eles SQS, Lambda, S3, DynamoDB, API Gateway, SES, Elasticsearch, CloudWatch e Route53. Na versão Pro, você conta com suporte adicional a outras APIs, como CloudFront, ECS, ECR, EKS, ElastiCache e RDS.

Configurando o Localstack

Pré-requisitos

Em primeiro lugar, a documentação sugere que o primeiro passo é ter o Python, o Pip e o Docker instalado na maquina local. Os três são pré-requisitos para instalação do Localstack. Para verificar se já estão instalados, execute o comando a seguir no seu terminal:

python3 --version && pip3 --version && docker --version

O resultado deve ser parecido com este print do meu ambiente:

print resultado do python pip docker

Caso não estejam instalados, você pode baixar aqui o Docker e aqui Python3, escolha a versão para seu sistema e faça o download do instalador. Após finalizar a instalação, reabra seu terminal e execute o comando anterior novamente. O pip não precisa ser baixado, ele é instalado junto com o Python, assim como o NPM é um gerenciador de pacotes para Node.js, o Pip é para o Python.

Instalando o Localstack

O segundo passo, após finalizar o setup dos pré-requisitos, é seguir com a instalação do Localstack, execute o seguinte comando:

pip3 install localstack

O resultado final é a mensagem de sucesso Successfully installed localstack-xxx, onde XXX é a versão instalada. Outra forma de verificar a instalação do localstack é executar o comando localstack –version no terminal, o resultado é a versão instalada na sua máquina.

Como inicializar o Localstack

Por último, com Localstack instalado, podemos inicia-lo executando o comando start no terminal, como no script a baixo:

localstack start

Com isso, todos os serviços serão iniciados em um container Docker, este é o comportamento padrão. A partir daqui, você pode verificar o status dos serviços acessando: http://localhost:4566/health

Resultado da url de health no meu ambiente:

localstack health services

Iniciar Localstack com Docker Compose

Se você quiser personalizar a inicialização do Localstack, definindo quais serviços quer usar, portas, entre outras variáveis de ambiente, você pode configurar um arquivo docker-compose.yml e iniciar a partir dele. As opções possíveis estão descritas na documentação oficial.

A baixo um exemplo de docker-compose.yml, configurado para executar apenas os serviços SQS, S3, Lambda e API Gateway.

version: '3.1'
services:
  localstack:
    container_name: "localstack_main"
    image: localstack/localstack
    network_mode: bridge
    ports:
      - "4566-4583:4566-4583"
    environment:
      - SERVICES=s3,lambda,sqs,apigateway
      - AWS_DEFAULT_REGION=us-east-1
      - EDGE_PORT=4566
      - DEBUG=1
    volumes:
      - "${TEMPDIR:-/tmp/localstack}:/tmp/localstack"
      - "/var/run/docker.sock:/var/run/docker.sock"

Usando Localstack

Seguindo nosso tutorial, agora com o Localstack em execução, vamos realizar o primeiro teste, criando um Bucket no S3 usando o AWS CLI. Se você ainda não tem ele instalado, pode baixar aqui o AWS CLI.

Vamos lá, digite no seu terminal o seguinte comando:

# Criar um bucket
aws --endpoint-url=http://localhost:4566 s3 mb s3://danieldcs

# Listar todos os buckets
aws --endpoint-url=http://localhost:4566 s3 ls

O resultado será um bucket criado e depois a listagem de buckets.

Usando Localstack com Node.js

Agora chegamos na parte mais importante, vamos ver como usar o Localstack com Node.js. Em primeiro lugar, vamos criar nossa aplicação com a dependência do AWS SDK. Execute no terminal:

mkdir nodejsLocalAWS
cd nodejsLocalAWS
npm init -y
npm install aws-sdk
touch sqs-consumer.js sqs-publisher.js

Em segundo lugar, no arquivo sqs-publisher.js adicione o seguinte código:

const AWS = require('aws-sdk');
const { promisify } = require('util');
AWS.config.update({ region: 'us-east-1' });
const sns = new AWS.SNS({ endpoint: '' });
sns.publish = promisify(sns.publish);
const TopicArn = '';
async function publish(msg) {
  const publishParams = {
    TopicArn,
    Message: msg
  };
  let topicRes;
  try {
    topicRes = await sns.publish(publishParams);
  } catch (e) {
    topicRes = e;
  }
  console.log('TOPIC Response: ', topicRes);
}
for (let i = 0; i < 5; i++) {
  publish('message #' + i);
}

Em terceiro lugar, no arquivo sqs-consumer.js adicione o seguinte código:

const AWS = require('aws-sdk');
const { promisify } = require('util');
AWS.config.update({ region: 'us-east-1' });
const sqs = new AWS.SQS({ endpoint: '' });
sqs.receiveMessage = promisify(sqs.receiveMessage);
const QueueUrl = '';
const receiveParams = {
  QueueUrl,
  MaxNumberOfMessages: 1
};
async function receive() {
  try {
    const queueData = await sqs.receiveMessage(receiveParams);
  if (
      queueData &&
      queueData.Messages &&
      queueData.Messages.length > 0
    ) {
      const [firstMessage] = queueData.Messages;
      console.log('RECEIVED: ', firstMessage);
      const deleteParams = {
        QueueUrl,
        ReceiptHandle: firstMessage.ReceiptHandle
      };
      sqs.deleteMessage(deleteParams);
    } else {
      console.log('waiting...');
    }
  } catch (e) {
    console.log('ERROR: ', e);
  }
}
setInterval(receive, 500);

A partir de agora, vamos usar o AWS CLI para criar uma fila, um tópico e inscrever nossa fila ao SNS para receber notificações.

Primeiro, digite no seu terminal o seguinte comando para criar a fila:

aws sqs create-queue \
--queue-name local-queue \
--endpoint-url http://localhost:4566
--region us-east-1 \
# deve retornar algo como:
{
  "QueueUrl": "http://localhost:4566/000000000/local-queue"
}

Segundo, crie um tópico no SNS para envio das notificações com este comando:

aws sns create-topic \
--name local-topic \
--endpoint-url http://localhost:4566 \
--region us-east-1 
# deve retornar algo como:
{
  "TopicArn": "arn:aws:sns:us-east-1:000000000:local-topic"
}

Por último, vamos inscrever nossa Fila ao Tópico do SNS:

aws sns subscribe \
--notification-endpoint http://localhost:4566/000000000/local-queue \
--topic-arn arn:aws:sns:us-east-1:000000000:local-topic \
--protocol sqs \
--endpoint-url=http://localhost:4575 \
--region us-east-1

Finalizado a criação da fila e tópico, vamos atualizar nossos arquivos js, com os valores que foram retornados no terminal.

No arquivo sqs-publisher.js, atualize a inicialização do SQS colocando na variável endpoint, a url do Localstack da sua maquina e na variável TopicArn, adicione o ARN gerado ao criar o tópico.

No arquivo sqs-consumer.js, também atualize a variável endpoint com a url do Localstack e na variável QueueUrl, adicione a url da fila criada.

Por último, abra o terminal e execute o comando node sqs-consumer.js, em outra janela execute node sqs-publisher.js. De um lado você verá uma inscrição sendo inserida, do outro, seu consumidor recebendo a mensagem. That’s it! 😀

A partir daqui, o limite é sua criatividade. Você precisa apenas definir o endpoint na inicialização do serviço, como no nosso exemplo, apontando para o localstack, que o resto vai funcionar normalmente.

Se este artigo te ajudou não deixe de compartilhar, se tiver qualquer dúvida, pode deixar nos comentários, vou tentar te ajudar.

Don't miss out!
Invalid email address
Gostou do conteúdo? Que tal ajudar compartilhando? :)

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *