DevOps & CI/CD

O que Todo Dev Deve Saber sobre AWS Avançado: EKS, ECS, Lambda e RDS em Ambientes Reais

22 min de leitura

O que Todo Dev Deve Saber sobre AWS Avançado: EKS, ECS, Lambda e RDS em Ambientes Reais

Arquitetura Moderna na AWS: Da Orquestração de Contêineres ao Serverless A computação em nuvem evoluiu significativamente nos últimos anos, e a AWS oferece múltiplos caminhos para executar suas aplicações. Quando você trabalha com ambientes reais e em escala, precisar escolher entre EKS (Elastic Kubernetes Service), ECS (Elastic Container Service), Lambda e banco de dados gerenciado (RDS) não é trivial. Cada um desses serviços resolve um problema específico, e um arquiteto experiente sabe quando usar qual ferramenta. Este artigo é um guia prático baseado em anos de implementação em produção, não em teoria genérica. Vamos explorar quando e como usar cada um desses serviços, com exemplos reais que você pode adaptar para seu contexto. O Contexto Real: Por que essa combinação importa Em uma empresa que cresce, você não usa apenas um serviço. Você pode ter microserviços rodando em ECS, jobs assíncronos em Lambda, e um banco de dados RDS compartilhado. Essa abordagem híbrida é comum e necessária. A diferença entre

<h2>Arquitetura Moderna na AWS: Da Orquestração de Contêineres ao Serverless</h2>

<p>A computação em nuvem evoluiu significativamente nos últimos anos, e a AWS oferece múltiplos caminhos para executar suas aplicações. Quando você trabalha com ambientes reais e em escala, precisar escolher entre EKS (Elastic Kubernetes Service), ECS (Elastic Container Service), Lambda e banco de dados gerenciado (RDS) não é trivial. Cada um desses serviços resolve um problema específico, e um arquiteto experiente sabe quando usar qual ferramenta. Este artigo é um guia prático baseado em anos de implementação em produção, não em teoria genérica. Vamos explorar quando e como usar cada um desses serviços, com exemplos reais que você pode adaptar para seu contexto.</p>

<h3>O Contexto Real: Por que essa combinação importa</h3>

<p>Em uma empresa que cresce, você não usa apenas um serviço. Você pode ter microserviços rodando em ECS, jobs assíncronos em Lambda, e um banco de dados RDS compartilhado. Essa abordagem híbrida é comum e necessária. A diferença entre um arquiteto júnior e um sênior é entender os trade-offs: custo, latência, escalabilidade, equipe e complexidade operacional.</p>

<p>---</p>

<h2>ECS: Orquestração Simplificada para Contêineres</h2>

<h3>O que é ECS e quando usar</h3>

<p>ECS (Elastic Container Service) é o serviço de orquestração de contêineres nativo da AWS. Diferentemente do Kubernetes (usado no EKS), ECS é mais simples, tem menos abstrações e integra-se perfeitamente com outros serviços AWS. Use ECS quando você precisa de uma solução rápida, sua equipe não tem expertise em Kubernetes, ou você quer reduzir overhead operacional.</p>

<p>A arquitetura do ECS é baseada em Tasks (unidades de trabalho) e Services (grupo de tasks rodando continuamente). Uma Task é essencialmente um pod do Kubernetes, mas sem a complexidade. Você define um Task Definition (parecido com um Deployment do Kubernetes), especifica recursos, variáveis de ambiente, e portas expostas. O ECS então gerencia onde essas tasks rodam—em EC2 ou Fargate (serverless).</p>

<h3>Exemplo Prático: Deploy de uma API REST em ECS com Fargate</h3>

<p>Imagine uma API Node.js simples que você quer rodar em ECS. Primeiro, você cria um Dockerfile:</p>

<pre><code class="language-dockerfile">FROM node:18-alpine

WORKDIR /app

COPY package*.json ./

RUN npm install --production

COPY . .

EXPOSE 3000

CMD [&quot;node&quot;, &quot;server.js&quot;]</code></pre>

<p>O arquivo <code>server.js</code>:</p>

<pre><code class="language-javascript">const express = require(&#039;express&#039;);

const app = express();

app.get(&#039;/health&#039;, (req, res) =&gt; {

res.json({ status: &#039;healthy&#039;, timestamp: new Date() });

});

app.get(&#039;/api/data&#039;, (req, res) =&gt; {

res.json({ message: &#039;Hello from ECS&#039;, version: &#039;1.0&#039; });

});

const PORT = process.env.PORT || 3000;

app.listen(PORT, () =&gt; {

console.log(Server running on port ${PORT});

});</code></pre>

<p>Agora você cria a Task Definition via AWS CLI ou Terraform. Aqui está um exemplo em JSON (você pode salvar como <code>task-definition.json</code>):</p>

<pre><code class="language-json">{

&quot;family&quot;: &quot;api-service&quot;,

&quot;networkMode&quot;: &quot;awsvpc&quot;,

&quot;requiresCompatibilities&quot;: [&quot;FARGATE&quot;],

&quot;cpu&quot;: &quot;256&quot;,

&quot;memory&quot;: &quot;512&quot;,

&quot;containerDefinitions&quot;: [

{

&quot;name&quot;: &quot;api-container&quot;,

&quot;image&quot;: &quot;123456789.dkr.ecr.us-east-1.amazonaws.com/my-api:latest&quot;,

&quot;portMappings&quot;: [

{

&quot;containerPort&quot;: 3000,

&quot;protocol&quot;: &quot;tcp&quot;

}

],

&quot;environment&quot;: [

{

&quot;name&quot;: &quot;NODE_ENV&quot;,

&quot;value&quot;: &quot;production&quot;

}

],

&quot;logConfiguration&quot;: {

&quot;logDriver&quot;: &quot;awslogs&quot;,

&quot;options&quot;: {

&quot;awslogs-group&quot;: &quot;/ecs/api-service&quot;,

&quot;awslogs-region&quot;: &quot;us-east-1&quot;,

&quot;awslogs-stream-prefix&quot;: &quot;ecs&quot;

}

}

}

],

&quot;executionRoleArn&quot;: &quot;arn:aws:iam::123456789:role/ecsTaskExecutionRole&quot;

}</code></pre>

<p>Para fazer deploy, você usa:</p>

<pre><code class="language-bash">aws ecs register-task-definition --cli-input-json file://task-definition.json

aws ecs create-service \

--cluster my-cluster \

--service-name api-service \

--task-definition api-service:1 \

--desired-count 2 \

--launch-type FARGATE \

--network-configuration &quot;awsvpcConfiguration={subnets=[subnet-xxx,subnet-yyy],securityGroups=[sg-xxx],assignPublicIp=ENABLED}&quot;</code></pre>

<p>Isso cria um serviço com 2 replicas rodando em Fargate. A AWS gerencia automaticamente a escalabilidade horizontal, health checks e reinicializações.</p>

<h3>Diferenças entre EC2 e Fargate no ECS</h3>

<p>Quando você cria um cluster ECS, pode escolher EC2 ou Fargate. <strong>EC2</strong>: você gerencia instâncias, patches, segurança. Mais barato em workloads estáveis, mas você tem overhead operacional. <strong>Fargate</strong>: você paga por CPU e memória consumidos, sem gerenciar infraestrutura. Ideal para aplicações com padrões impredizíveis ou para reduzir toil operacional. Em minha experiência, Fargate é a escolha padrão para novas implementações, a menos que haja restrição orçamentária severa.</p>

<p>---</p>

<h2>EKS: Kubernetes para Quem Precisa de Potência e Portabilidade</h2>

<h3>Por que Kubernetes? O dilema arquitetural</h3>

<p>EKS (Elastic Kubernetes Service) é Kubernetes gerenciado na AWS. Use quando você precisa de: <strong>portabilidade</strong> (rodar em múltiplas clouds), <strong>controle granular</strong> (network policies, RBAC complexo), <strong>equipe experiente</strong> em K8s, ou <strong>ecossistema Kubernetes</strong> (Helm, ArgoCD, operadores). Se nenhum desses se aplica, ECS é mais simples. Kubernetes tem curva de aprendizado íngreme, e overhead operacional significativo.</p>

<p>Kubernetes organiza recursos de forma diferente do ECS. Você tem Pods (menor unidade), ReplicaSets (garante N replicas), Deployments (estratégia de atualização), Services (rede interna), e muito mais. Para um projeto novo em uma equipe sem K8s, use ECS. Para integração com ferramentas open-source ou múltiplas clouds, use EKS.</p>

<h3>Exemplo Prático: Deploy em EKS com Kubernetes Manifests</h3>

<p>Você já tem a imagem Docker. Agora cria um manifesto Kubernetes:</p>

<pre><code class="language-yaml"># api-deployment.yaml

apiVersion: apps/v1

kind: Deployment

metadata:

name: api-deployment

namespace: default

spec:

replicas: 3

selector:

matchLabels:

app: api

template:

metadata:

labels:

app: api

spec:

containers:

  • name: api

image: 123456789.dkr.ecr.us-east-1.amazonaws.com/my-api:latest

ports:

  • containerPort: 3000

env:

  • name: NODE_ENV

value: &quot;production&quot;

  • name: DATABASE_URL

valueFrom:

secretKeyRef:

name: db-credentials

key: url

resources:

requests:

cpu: &quot;100m&quot;

memory: &quot;128Mi&quot;

limits:

cpu: &quot;500m&quot;

memory: &quot;512Mi&quot;

livenessProbe:

httpGet:

path: /health

port: 3000

initialDelaySeconds: 10

periodSeconds: 10

readinessProbe:

httpGet:

path: /health

port: 3000

initialDelaySeconds: 5

periodSeconds: 5

---

apiVersion: v1

kind: Service

metadata:

name: api-service

spec:

selector:

app: api

type: LoadBalancer

ports:

  • protocol: TCP

port: 80

targetPort: 3000</code></pre>

<p>Deploy com kubectl:</p>

<pre><code class="language-bash"># Primeiro, crie o cluster EKS (via AWS Console ou CLI)

aws eks create-cluster \

--name my-cluster \

--version 1.28 \

--roleArn arn:aws:iam::123456789:role/eks-service-role \

--resourcesVpcConfig subnetIds=subnet-xxx,subnet-yyy

Aguarde o cluster ficar pronto (pode levar 10-15 minutos)

Configure kubectl

aws eks update-kubeconfig --region us-east-1 --name my-cluster

Crie um node group (máquinas que rodam os pods)

aws eks create-nodegroup \

--cluster-name my-cluster \

--nodegroup-name my-nodegroup \

--scaling-config minSize=2,maxSize=10,desiredSize=3 \

--subnets subnet-xxx subnet-yyy \

--nodeRole arn:aws:iam::123456789:role/eks-nodegroup-role

Deploy a aplicação

kubectl apply -f api-deployment.yaml

Verifique o status

kubectl get deployments

kubectl get pods

kubectl get svc</code></pre>

<h3>Escalabilidade em EKS com Horizontal Pod Autoscaler</h3>

<p>Em ambientes reais, você quer que o Kubernetes escale automaticamente. Para isso, instale o Metrics Server e use HPA:</p>

<pre><code class="language-yaml"># hpa.yaml

apiVersion: autoscaling/v2

kind: HorizontalPodAutoscaler

metadata:

name: api-hpa

spec:

scaleTargetRef:

apiVersion: apps/v1

kind: Deployment

name: api-deployment

minReplicas: 2

maxReplicas: 10

metrics:

  • type: Resource

resource:

name: cpu

target:

type: Utilization

averageUtilization: 70

  • type: Resource

resource:

name: memory

target:

type: Utilization

averageUtilization: 80</code></pre>

<p>Aplique com: <code>kubectl apply -f hpa.yaml</code>. Agora seu deployment escala automaticamente entre 2 e 10 replicas conforme a carga.</p>

<p>---</p>

<h2>Lambda: Computação Serverless para Workloads Específicos</h2>

<h3>Quando Lambda faz sentido</h3>

<p>Lambda é função-como-serviço (FaaS). Você escreve código, faz upload, e paga apenas pelo tempo de execução. Use Lambda para: <strong>jobs assíncronos</strong> (processar imagens, enviar emails), <strong>APIs de baixa latência</strong> com tráfego esporádico, <strong>webhooks</strong> e integrações, <strong>processamento de eventos</strong> (S3, DynamoDB streams). Não use para aplicações monolíticas, workloads de longa duração (máximo 15 minutos), ou que precisem estado persistente complexo.</p>

<p>Lambda é gerenciado, logo sem preocupação com infraestrutura. Você escreve código, o AWS gerencia escala, patching, rede. O modelo de custo é por execução: você paga pela quantidade de invocações e pelo tempo de CPU consumido (GB-segundo). Para aplicações que ficam ociosas boa parte do tempo, Lambda é muito mais barato.</p>

<h3>Exemplo Prático: Processamento de Imagens com Lambda e S3</h3>

<p>Imagine que você quer processar imagens quando elas são uploadadas no S3. Cria uma função Lambda (em Python):</p>

<pre><code class="language-python"># lambda_function.py

import json

import boto3

import urllib.parse

from PIL import Image

from io import BytesIO

s3_client = boto3.client(&#039;s3&#039;)

def lambda_handler(event, context):

&quot;&quot;&quot;

Processada acionada quando imagem é enviada para S3.

Redimensiona a imagem e salva thumbnail em outro bucket.

&quot;&quot;&quot;

Extrai informação do evento S3

bucket = event[&#039;Records&#039;][0][&#039;s3&#039;][&#039;bucket&#039;][&#039;name&#039;]

key = urllib.parse.unquote_plus(event[&#039;Records&#039;][0][&#039;s3&#039;][&#039;object&#039;][&#039;key&#039;])

try:

Download da imagem original

response = s3_client.get_object(Bucket=bucket, Key=key)

image_data = response[&#039;Body&#039;].read()

Processa com Pillow

image = Image.open(BytesIO(image_data))

image.thumbnail((200, 200))

Salva thumbnail em outro bucket

thumb_buffer = BytesIO()

image.save(thumb_buffer, format=&#039;JPEG&#039;)

thumb_buffer.seek(0)

thumb_key = f&quot;thumbnails/{key}&quot;

s3_client.put_object(

Bucket=&#039;my-thumbnails-bucket&#039;,

Key=thumb_key,

Body=thumb_buffer.getvalue(),

ContentType=&#039;image/jpeg&#039;

)

return {

&#039;statusCode&#039;: 200,

&#039;body&#039;: json.dumps(f&#039;Thumbnail criado: {thumb_key}&#039;)

}

except Exception as e:

print(f&#039;Erro: {str(e)}&#039;)

return {

&#039;statusCode&#039;: 500,

&#039;body&#039;: json.dumps(f&#039;Erro ao processar: {str(e)}&#039;)

}</code></pre>

<p>O arquivo <code>requirements.txt</code> para deploy:</p>

<pre><code>Pillow==10.0.0

boto3==1.28.0</code></pre>

<p>Deploy via AWS CLI:</p>

<pre><code class="language-bash"># Instale dependências localmente

pip install -r requirements.txt -t lambda_package/

Copie seu código

cp lambda_function.py lambda_package/

Crie ZIP

cd lambda_package &amp;&amp; zip -r ../function.zip . &amp;&amp; cd ..

Crie a função (primeira vez)

aws lambda create-function \

--function-name image-processor \

--runtime python3.11 \

--role arn:aws:iam::123456789:role/lambda-role \

--handler lambda_function.lambda_handler \

--zip-file fileb://function.zip \

--timeout 60 \

--memory-size 512 \

--environment Variables={THUMBNAIL_BUCKET=my-thumbnails-bucket}

Atualize a função (em desenvolvimentos futuros)

aws lambda update-function-code \

--function-name image-processor \

--zip-file fileb://function.zip</code></pre>

<p>Agora crie um trigger para que Lambda seja acionada quando uma imagem chegar no S3:</p>

<pre><code class="language-bash">aws s3api put-bucket-notification-configuration \

--bucket my-images-bucket \

--notification-configuration &#039;{

&quot;LambdaFunctionConfigurations&quot;: [

{

&quot;LambdaFunctionArn&quot;: &quot;arn:aws:lambda:us-east-1:123456789:function:image-processor&quot;,

&quot;Events&quot;: [&quot;s3:ObjectCreated:*&quot;],

&quot;Filter&quot;: {

&quot;Key&quot;: {

&quot;FilterRules&quot;: [

{

&quot;Name&quot;: &quot;suffix&quot;,

&quot;Value&quot;: &quot;.jpg&quot;

}

]

}

}

}

]

}&#039;</code></pre>

<h3>Lambda com RDS: Conexão e Boas Práticas</h3>

<p>Quando sua função Lambda precisa acessar um banco RDS, há desafios: <strong>cold starts</strong> (inicialização lenta da função), <strong>conexões de longa vida</strong> (Lambda por padrão termina conexões rapidamente). Aqui está uma abordagem robusta em Python:</p>

<pre><code class="language-python"># lambda_with_rds.py

import json

import psycopg2

import os

from psycopg2 import pool

Crie um connection pool (reutiliza conexões entre invocações)

connection_pool = None

def get_db_connection():

global connection_pool

if connection_pool is None:

connection_pool = psycopg2.pool.SimpleConnectionPool(

1, 5, # min 1, max 5 conexões

host=os.getenv(&#039;DB_HOST&#039;),

database=os.getenv(&#039;DB_NAME&#039;),

user=os.getenv(&#039;DB_USER&#039;),

password=os.getenv(&#039;DB_PASSWORD&#039;)

)

return connection_pool.getconn()

def lambda_handler(event, context):

&quot;&quot;&quot;

Consulta banco de dados e retorna resultado.

&quot;&quot;&quot;

conn = None

try:

conn = get_db_connection()

cursor = conn.cursor()

Exemplo: busca usuários

cursor.execute(&quot;SELECT id, email FROM users LIMIT 10&quot;)

rows = cursor.fetchall()

cursor.close()

connection_pool.putconn(conn)

return {

&#039;statusCode&#039;: 200,

&#039;body&#039;: json.dumps({

&#039;users&#039;: [{&#039;id&#039;: row[0], &#039;email&#039;: row[1]} for row in rows]

})

}

except Exception as e:

if conn:

connection_pool.putconn(conn)

return {

&#039;statusCode&#039;: 500,

&#039;body&#039;: json.dumps({&#039;error&#039;: str(e)})

}</code></pre>

<p>Deploy com variáveis de ambiente:</p>

<pre><code class="language-bash">aws lambda update-function-configuration \

--function-name my-db-function \

--environment Variables=&#039;{

DB_HOST=mydb.c9akciq32.us-east-1.rds.amazonaws.com,

DB_NAME=production,

DB_USER=admin,

DB_PASSWORD=SecurePassword123

}&#039;</code></pre>

<p>---</p>

<h2>RDS: Banco de Dados Gerenciado para Persistência</h2>

<h3>Arquitetura e Configuração de RDS</h3>

<p>RDS (Relational Database Service) gerencia bancos SQL (PostgreSQL, MySQL, MariaDB, Oracle, SQL Server). Você não se preocupa com patches, backups automáticos, replicação—tudo é automático. RDS é essencial quando suas aplicações precisam persistência robusta e ACID compliance.</p>

<p>RDS oferece várias opções de deployment: <strong>Single-AZ</strong> (simples, menos resiliente), <strong>Multi-AZ</strong> (replica automática em outra zona, failover instantâneo), e <strong>Read Replicas</strong> (cópias apenas-leitura para distribuir carga de leitura). Em produção, use Multi-AZ. O custo é dobrado, mas a confiabilidade é incomparável.</p>

<h3>Exemplo Prático: RDS Multi-AZ com PostgreSQL e Terraform</h3>

<p>Aqui está como provisionar um RDS robusto usando Terraform:</p>

<pre><code class="language-hcl"># rds.tf

provider &quot;aws&quot; {

region = &quot;us-east-1&quot;

}

resource &quot;aws_db_subnet_group&quot; &quot;main&quot; {

name = &quot;main-subnet-group&quot;

subnet_ids = [aws_subnet.private_a.id, aws_subnet.private_b.id]

tags = {

Name = &quot;Main subnet group&quot;

}

}

resource &quot;aws_security_group&quot; &quot;rds_sg&quot; {

name = &quot;rds-security-group&quot;

vpc_id = aws_vpc.main.id

ingress {

from_port = 5432

to_port = 5432

protocol = &quot;tcp&quot;

cidr_blocks = [&quot;10.0.0.0/8&quot;] # Permite de dentro da VPC

}

egress {

from_port = 0

to_port = 0

protocol = &quot;-1&quot;

cidr_blocks = [&quot;0.0.0.0/0&quot;]

}

tags = {

Name = &quot;RDS SG&quot;

}

}

resource &quot;aws_db_instance&quot; &quot;production&quot; {

identifier = &quot;production-db&quot;

engine = &quot;postgres&quot;

engine_version = &quot;15.3&quot;

instance_class = &quot;db.t3.small&quot; # 2 vCPU, 2GB RAM

allocated_storage = 100

storage_type = &quot;gp3&quot;

storage_encrypted = true

db_name = &quot;production&quot;

username = &quot;postgres&quot;

password = var.db_password # Use AWS Secrets Manager

db_subnet_group_name = aws_db_subnet_group.main.name

vpc_security_group_ids = [aws_security_group.rds_sg.id]

Multi-AZ para alta disponibilidade

multi_az = true

Backups automáticos

backup_retention_period = 30

backup_window = &quot;03:00-04:00&quot;

Janela de manutenção

maintenance_window = &quot;mon:04:00-mon:05:00&quot;

Enable enhanced monitoring

enable_cloudwatch_logs_exports = [&quot;postgresql&quot;]

Snapshots automáticos antes de deletar

skip_final_snapshot = false

final_snapshot_identifier = &quot;production-db-final-snapshot&quot;

tags = {

Name = &quot;Production PostgreSQL&quot;

}

}

variable &quot;db_password&quot; {

type = string

sensitive = true

}

output &quot;rds_endpoint&quot; {

value = aws_db_instance.production.endpoint

}</code></pre>

<p>Deploy com:</p>

<pre><code class="language-bash">terraform plan

terraform apply</code></pre>

<h3>Exemplo Prático: Migração de Dados para RDS</h3>

<p>Quando você tem um banco local ou em outro servidor, precisa migrar. Aqui está uma abordagem com <code>pg_dump</code>:</p>

<pre><code class="language-bash"># 1. Dump do banco antigo (local ou outro servidor)

pg_dump -h old-server.com -U admin -d production &gt; dump.sql

2. Restaure no RDS

psql -h production-db.c9akciq32.us-east-1.rds.amazonaws.com \

-U postgres \

-d production \

-f dump.sql</code></pre>

<p>Para garantir consistência em tabelas grandes, use AWS DMS (Database Migration Service), que sincroniza em tempo real. Mas para dados iniciais menores, o pg_dump é suficiente.</p>

<h3>Integração com Aplicações: Connection Pooling</h3>

<p>Aplicações conectam-se ao RDS via string de conexão. Para reduzir overhead, use connection pooling. Aqui está um exemplo com Node.js e <code>pg</code>:</p>

<pre><code class="language-javascript">// dbPool.js

const { Pool } = require(&#039;pg&#039;);

const pool = new Pool({

host: process.env.DB_HOST,

port: 5432,

database: process.env.DB_NAME,

user: process.env.DB_USER,

password: process.env.DB_PASSWORD,

max: 20, // Máximo 20 conexões simultâneas

idleTimeoutMillis: 30000,

connectionTimeoutMillis: 2000,

});

pool.on(&#039;error&#039;, (err) =&gt; {

console.error(&#039;Pool error:&#039;, err);

});

module.exports = pool;</code></pre>

<p>Usar em sua aplicação:</p>

<pre><code class="language-javascript">// api.js

const express = require(&#039;express&#039;);

const pool = require(&#039;./dbPool&#039;);

const app = express();

app.get(&#039;/users/:id&#039;, async (req, res) =&gt; {

try {

const result = await pool.query(

&#039;SELECT id, email, name FROM users WHERE id = $1&#039;,

[req.params.id]

);

res.json(result.rows[0]);

} catch (error) {

console.error(error);

res.status(500).json({ error: &#039;Database error&#039; });

}

});

app.listen(3000);</code></pre>

<p>---</p>

<h2>Orquestração Híbrida: Juntando Tudo</h2>

<h3>Padrão Arquitetural Recomendado</h3>

<p>Em produção, você raramente usa apenas um serviço. Um padrão comum é: <strong>ECS (ou EKS) para aplicações síncronas</strong>, <strong>Lambda para processamento assíncronos</strong>, <strong>RDS como banco central</strong>. Aqui está um diagrama conceitual:</p>

<pre><code>[Client] → [ALB] → [ECS/EKS Tasks] → [RDS]

[SQS Queue]

[Lambda Function] → [S3/DynamoDB]</code></pre>

<p>A aplicação principal roda em ECS/EKS. Quando precisa processar algo longo (redimensionar imagem, enviar email), publica mensagem em SQS. Uma Lambda consome a fila e processa. RDS é o repositório central.</p>

<h3>Exemplo Real: Integração entre ECS e Lambda via SQS</h3>

<p>Sua aplicação ECS publica mensagens:</p>

<pre><code class="language-python"># ecs_application.py

import boto3

import json

sqs = boto3.client(&#039;sqs&#039;)

QUEUE_URL = &#039;https://sqs.us-east-1.amazonaws.com/123456789/my-queue&#039;

def process_order(order_id):

&quot;&quot;&quot;

Quando um pedido é criado, envia para fila SQS.

Lambda vai processar o pagamento.

&quot;&quot;&quot;

message = {

&#039;order_id&#039;: order_id,

&#039;action&#039;: &#039;process_payment&#039;

}

sqs.send_message(

QueueUrl=QUEUE_URL,

MessageBody=json.dumps(message)

)

return {&#039;status&#039;: &#039;queued&#039;}</code></pre>

<p>Lambda consome:</p>

<pre><code class="language-python"># lambda_consumer.py

import json

import boto3

def lambda_handler(event, context):

&quot;&quot;&quot;

Consome mensagens da SQS e processa pagamentos.

&quot;&quot;&quot;

for record in event[&#039;Records&#039;]:

body = json.loads(record[&#039;body&#039;])

order_id = body[&#039;order_id&#039;]

Processa pagamento (simulado)

print(f&#039;Processando pagamento para order {order_id}&#039;)

Aqui você chamaria uma API de pagamento (Stripe, etc)

payment_result = stripe.charge(...)

Atualiza banco de dados (via RDS)

update_order_status(order_id, &#039;paid&#039;)

return {&#039;statusCode&#039;: 200}</code></pre>

<p>Configure Lambda para consumir SQS via trigger no AWS Console ou:</p>

<pre><code class="language-bash">aws lambda create-event-source-mapping \

--event-source-arn arn:aws:sqs:us-east-1:123456789:my-queue \

--function-name payment-processor \

--batch-size 10</code></pre>

<p>---</p>

<h2>Conclusão</h2>

<p>Você aprendeu três coisas fundamentais sobre arquitetura AWS em escala. <strong>Primeira</strong>: ECS é mais simples que EKS e funciona bem para a maioria dos casos; use Kubernetes apenas se realmente precisar de portabilidade ou se sua equipe já domina. <strong>Segunda</strong>: Lambda não substitui servidores—é complementar. Use para jobs assíncronos, integrações, webhooks. Misture com ECS/EKS para uma arquitetura completa. <strong>Terceira</strong>: RDS é a base sólida. Multi-AZ, backups automáticos, connection pooling—esses padrões não são opcionais em produção, são fundamentais.</p>

<p>O sucesso em AWS avançado não é memorizar CLIs ou sintaxe. É entender os trade-offs entre simplicidade operacional (ECS) vs. flexibilidade (EKS), entre custo (EC2) vs. conveniência (Fargate), entre serverless (Lambda) e aplicações contínuas (ECS/EKS). Implemente esses conceitos em seu próximo projeto, adapte para seu contexto, e você terá arquitetura que escala.</p>

<p>---</p>

<h2>Referências</h2>

<ul>

<li><a href="https://docs.aws.amazon.com/ecs/latest/developerguide/Welcome.html" target="_blank" rel="noopener noreferrer">AWS ECS Documentation</a></li>

<li><a href="https://aws.github.io/aws-eks-best-practices/" target="_blank" rel="noopener noreferrer">AWS EKS Best Practices Guide</a></li>

<li><a href="https://docs.aws.amazon.com/lambda/latest/dg/welcome.html" target="_blank" rel="noopener noreferrer">AWS Lambda Developer Guide</a></li>

<li><a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_BestPractices.html" target="_blank" rel="noopener noreferrer">AWS RDS Best Practices</a></li>

<li><a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs" target="_blank" rel="noopener noreferrer">Terraform AWS Provider Documentation</a></li>

</ul>

<p>&lt;!-- FIM --&gt;</p>

Comentários

Mais em DevOps & CI/CD

Dominando Tekton em Kubernetes: Pipelines Cloud-Native do Zero em Projetos Reais
Dominando Tekton em Kubernetes: Pipelines Cloud-Native do Zero em Projetos Reais

O que é Tekton e por que você precisa aprender Tekton é um framework open-sou...

Dominando Chaos Engineering: Princípios, Chaos Monkey e LitmusChaos em Kubernetes em Projetos Reais
Dominando Chaos Engineering: Princípios, Chaos Monkey e LitmusChaos em Kubernetes em Projetos Reais

Entendendo Chaos Engineering: Fundamentos e Filosofia Chaos Engineering é uma...

Shell Scripting Bash: Variáveis, Condicionais, Laços e Funções na Prática
Shell Scripting Bash: Variáveis, Condicionais, Laços e Funções na Prática

Variáveis em Bash: Fundamentos e Boas Práticas Variáveis são contêineres que...