Simulando a AWS no seu ambiente Local

devinicius

Vinicius Pereira de Oliveira

Posted on August 17, 2023

Simulando a AWS no seu ambiente Local

Opa, espero que esteja tudo bem com você que está lendo esse artigo no momento.
Passei por situações interessantes, no período em que desenvolvia uma feature na atual empresa em que me encontro.

Tive a necessidade de utilizar recursos da AWS, seja para aprender o que eu iria manusear, como implementar no ambiente corporativo de forma correta.

Durante meus estudos, para evitar gastos, procurei soluções que me permitiriam usar as funções de armazenamento e envio de e-mail da AWS de forma gratuita. Até que finalmente encontro um recurso, que simula o ambiente cloud da AWS dentro da sua máquina local.

O Localstack: https://localstack.cloud/, é um recurso que possibilita simular diversos recursos AWS (dynamoDB, s3, iam, cognito, ses), dentro da sua máquina, utilizando o docker.

Pré-requisitos

  • Docker & Docker-compose
  • Node (Minimo na versão 16)
  • Aws-cli instalada na máquina

Para ativar, basta criar um docker compose no seu projeto com os seguintes comandos:

version: "3.8"

services:
  localstack:
    container_name: "localstack"
    image: localstack/localstack:1.0.4
    ports:
      - "4566:4566"            # LocalStack Gateway
    environment:
      - DOCKER_HOST=unix:///var/run/docker.sock
      - DEFAULT_REGION=us-east-1
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
Enter fullscreen mode Exit fullscreen mode

Rode o comando docker-compose up para inicializar o funcionamento do localstack

Para validar se está realmente funcionando, abra o seu navegador na seguinte url => http://localhost:4566/health

Iniciando um projeto Node
Não iremos nos preocupar com padrão de projetos, apenas queremos criar uma aplicação, para: criar um arquivo num bucket S3, remover o arquivo, receber a url assinada, enviar um e-mail pelo SES

crie uma pasta e abra no editor de texto da sua preferencia

Inicie o seu projeto node com o seguinte comando:

yarn init -y

Instalando as dependencias

yarn add aws-sdk@2.1438 axios@1.4

yarn add @types/node@20.5 @types/axios@0.14 localstack@1 ts-node-dev@2 typescript@5.1.6 -D

Inicializando o Typescript

yarn tsc --init

dentro do package.json, adicione o script para rodar o projeto

"scripts": {
    "dev": "ts-node-dev --respawn --transpile-only index.ts"
},
Enter fullscreen mode Exit fullscreen mode

crie um arquivo chamado index.ts

O projeto terá a seguinte estrutura

Image description

Codificando o projeto
Dentro do index.ts, iremos realizar as configurações dos serviços S3 e SES

import AWS from 'aws-sdk'
import axios from 'axios'

const s3config = {
    s3ForcePathStyle: true
}

const sesConfig = {
    apiVersion: '2010-12-01'
}

const isLocal = true

if(isLocal) {
    AWS.config.update({
        credentials: {
            accessKeyId: 'test',
            secretAccessKey: 'test'
        },
        region: 'us-east-1'
    })

    const host = 'localhost'
    const awsEndpoint = new AWS.Endpoint(`http://${host}:4566`);

    //@ts-ignore
    s3config.endpoint = awsEndpoint
    //@ts-ignore
    sesConfig.endpoint = awsEndpoint
}

const s3 = new AWS.S3(s3config);
const ses = new AWS.SES(sesConfig)

const bucketName = 'local-data-files'
Enter fullscreen mode Exit fullscreen mode

OBSERVAÇÕES: Dentro da constante isLocal, poderemos inserir esse valor em uma variável de ambiente, para que quando for enviado para ambientes de homologação e Produção, utilizemos os reais valores da AWS e não do Localstack

Para definir que o ambiente utilizado será o localstack, é necessário configurar as chaves da AWS e alterar o endpoint que as classes irão realizar as requisições

AWS.config.update({
        credentials: {
            accessKeyId: 'test',
            secretAccessKey: 'test'
        },
        region: 'us-east-1'
})

const host = 'localhost'
    const awsEndpoint = new AWS.Endpoint(`http://${host}:4566`);
Enter fullscreen mode Exit fullscreen mode

Para realizar a codificação dos demais serviços, iremos criar duas classes

class StorageManagement {

}

class SendEmail {

}
Enter fullscreen mode Exit fullscreen mode

Para as funções de gerenciamento no S3, adicionaremos os seguintes comandos:

class StorageManagement {
    public async execute() {
        const image = 'https://www.purina.co.uk/sites/default/files/2020-12/Dog_1098119012_Teaser.jpg'

        const buffer = await this.downloadImage(image);
        const upload = await this.upload(buffer);

        await this.remove(upload.Key);
    }

    private async downloadImage(imageUrl: string) {
        const response = await axios.get(imageUrl, {
            responseType: 'arraybuffer'
        })

        const buffer = Buffer.from(response.data, 'base64');
        return buffer
    }

    private async upload(buffer: Buffer) {
        const s3Upload = await s3.upload({
            Bucket: bucketName,
            Key: `FILE_${(new Date()).getTime()}`,
            Body: buffer
        }).promise();

        return s3Upload
    }

    private async remove(key: string) {
        await s3.deleteObject({
            Bucket: bucketName,
            Key: key
        })
    }
}
Enter fullscreen mode Exit fullscreen mode

E para o envio de e-mail, temos o seguinte código:

class SendEmail {
    public async execute() {
        var params = {
            Destination: {
             ToAddresses: [
                'envio@teste.com', 
             ]
            }, 
            Message: {
             Body: {
              Html: {
               Charset: "UTF-8", 
               Data: "This message body contains HTML formatting. It can, for example, contain links like this one: <a class=\"ulink\" href=\"http://docs.aws.amazon.com/ses/latest/DeveloperGuide\" target=\"_blank\">Amazon SES Developer Guide</a>."
              }, 
              Text: {
               Charset: "UTF-8", 
               Data: "This is the message body in text format."
              }
             }, 
             Subject: {
              Charset: "UTF-8", 
              Data: "Test email"
             }
            },
            Source: "teste@mailinator.com", 
           };

        const emailSend = ses.sendEmail(params).promise()
    }
}
Enter fullscreen mode Exit fullscreen mode

Antes de rodar nossa aplicação e ver o funcionamento, precisamos realizar alguns comandos via script para que o código funcione

crie um arquivo script.sh e adicione os seguintes comandos

# Nome do Bucket
BUCKET_NAME=local-data-files

# Comando AWS para criar um bucket no S3
# o Endpoint é para definir que iremos criar dentro do localstack
aws \
    s3 mb s3://$BUCKET_NAME \
    --endpoint http://localhost:4566

# Comando para validar o e-mail que iremos utilizar para teste no Localstack
aws ses verify-email-identity \
    --email-address teste@mailinator.com \
    --endpoint-url=http://localhost:4566
Enter fullscreen mode Exit fullscreen mode

Para executar digite no terminal

sh script.sh
Enter fullscreen mode Exit fullscreen mode

Testando
Para Testar cada uma das funcionalidades, instancie as classes e chame a função execute

const test = new StorageManagement()
const testSES = new SendEmail()

testSES.execute()

test.execute()
Enter fullscreen mode Exit fullscreen mode

Validando
Para Validar se o arquivo está presente no s3, deve-se executar o seguinte comando sh

BUCKET_NAME=local-data-files
aws \
    s3 ls s3://$BUCKET_NAME\
    --endpoint http://localhost:4566
Enter fullscreen mode Exit fullscreen mode

Para visualizar se o email foi enviado, entre na seguinte url

http://localhost:4566/_localstack/ses

Espero que esse artigo tenha sido útil para você. Deixe seu comentário e sugestão de próximo tema.

Até mais! ❤️

Repositório GitHub do artigo
https://github.com/DEVinicius/use-s3-ses-localstack

Minhas Redes Sociais

Instagram📗
LinkedIn💼

💖 💪 🙅 🚩
devinicius
Vinicius Pereira de Oliveira

Posted on August 17, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related