Os quarenta e sete artigos anteriores cobriram, em progressão cuidadosa, cada camada da engenharia de software moderna: o terminal Linux, o controle de versão com Git, containers com Docker, pipelines de CI/CD, infraestrutura como código com Terraform, monitoramento com Prometheus e Grafana, AWS em profundidade, Kubernetes, segurança com DevSecOps, compliance, FinOps, resiliência e cultura organizacional. Cada artigo tratou de sua camada com profundidade — ferramentas, padrões, código funcional, decisões de arquitetura.
O que falta é a integração. Sistemas reais não são coleções de tecnologias operando em silos — são organismos onde cada componente interage com os demais de maneiras que criam propriedades emergentes, tanto positivas quanto negativas. Um pipeline de CI/CD excelente tem valor limitado se a infraestrutura que ele provisiona não está monitorada. Observabilidade sofisticada não ajuda se o processo de deploy não tem estratégia de rollback. Segurança no código não basta se a infraestrutura está mal configurada.
O projeto capstone desta série integra todos esses componentes em um sistema completo de produção: uma plataforma de e-commerce com microsserviços, deployed no EKS, com pipeline completo de CI/CD, observabilidade full-stack, segurança em camadas e práticas de FinOps. Não é um sistema simplificado para fins didáticos — é a arquitetura que seria usada em produção real, com as decisões de trade-off que sistemas reais exigem.
Este artigo define a arquitetura. Os artigos 49 e 50 implementam a infraestrutura e os serviços. Os artigos 51 e 52 implementam o pipeline completo e as operações em produção.
O Sistema: Plataforma de E-Commerce
A plataforma escolhida para o capstone é um sistema de e-commerce — domínio suficientemente rico para exigir todas as práticas abordadas no curso, mas familiar o bastante para que o foco permaneça nas práticas de engenharia e não na lógica de negócio.
O sistema é composto por cinco microsserviços, cada um com responsabilidade bem definida:
Serviço de Catálogo — gerencia produtos, categorias, preços e estoque. Alta taxa de leitura, baixa taxa de escrita. Candidato ideal para caching agressivo.
Serviço de Usuários — gerencia contas, autenticação e perfis. Dados sensíveis sob LGPD. Requer auditoria de todos os acessos.
Serviço de Pedidos — orquestra o fluxo de compra: criação de carrinho, checkout, pagamento e fulfillment. Core do negócio — requer alta disponibilidade e consistência eventual entre serviços.
Serviço de Notificações — envia emails, SMS e notificações push. Assíncrono por natureza — opera sobre filas SQS. Tolerante a latência, mas não a perda de mensagens.
API Gateway — ponto único de entrada para clientes externos. Roteamento, autenticação, rate limiting e agregação de respostas.
Diagrama de Arquitetura
┌─────────────────────────────────────────────────────────────────────┐
│ INTERNET │
└──────────────────────────┬──────────────────────────────────────────┘
│
┌──────────▼──────────┐
│ CloudFront CDN │
│ WAF + Shield Std │
└──────────┬──────────┘
│
┌────────────▼────────────┐
│ Application LB (ALB) │
│ Route53 → api.loja.com │
└────────────┬────────────┘
│
┌──────────────────────▼──────────────────────────┐
│ EKS Cluster │
│ ┌────────────────────────────────────────────┐ │
│ │ Namespace: producao │ │
│ │ │ │
│ │ ┌────────────┐ ┌──────────────────┐ │ │
│ │ │ API Gateway│ │ Serviço Catálogo │ │ │
│ │ │ (3 pods) │───▶│ (5 pods) │ │ │
│ │ └─────┬──────┘ └────────┬─────────┘ │ │
│ │ │ │ │ │
│ │ ┌─────▼──────┐ ┌────────▼─────────┐ │ │
│ │ │ Serviço │ │ Serviço │ │ │
│ │ │ Usuários │ │ Pedidos │ │ │
│ │ │ (3 pods) │ │ (5 pods) │ │ │
│ │ └────────────┘ └────────┬─────────┘ │ │
│ │ │ │ │
│ │ ┌────────▼─────────┐ │ │
│ │ │ Serviço │ │ │
│ │ │ Notificações │ │ │
│ │ │ (2 pods) │ │ │
│ │ └──────────────────┘ │ │
│ └────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────┐ │
│ │ Namespace: monitoring │ │
│ │ Prometheus · Grafana · Loki · Tempo │ │
│ └────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────┘
│
┌──────────────────────▼──────────────────────────┐
│ AWS Managed Services │
│ │
│ ┌─────────────┐ ┌──────────────┐ │
│ │ RDS Postgres │ │ ElastiCache │ │
│ │ Multi-AZ │ │ Redis │ │
│ │ │ │ (cluster) │ │
│ └─────────────┘ └──────────────┘ │
│ │
│ ┌─────────────┐ ┌──────────────┐ │
│ │ SQS Queues │ │ S3 │ │
│ │ notificações│ │ assets + │ │
│ │ + DLQ │ │ backups │ │
│ └─────────────┘ └──────────────┘ │
│ │
│ ┌─────────────┐ ┌──────────────┐ │
│ │ Secrets Mgr │ │ KMS │ │
│ │ credenciais │ │ criptografia │ │
│ └─────────────┘ └──────────────┘ │
└──────────────────────────────────────────────────┘
Decisões de Arquitetura e Trade-offs
Toda arquitetura é o resultado de decisões que priorizam algumas propriedades em detrimento de outras. Documentar essas decisões — com a alternativa considerada e o motivo da escolha — é uma prática essencial que o capstone demonstra através de Architecture Decision Records:
ADR-001: Microsserviços vs Monolito Modular
# ADR-001: Adoção de Microsserviços
**Status:** Aceito
**Data:** 2025-01-15
**Decisores:** Time de Arquitetura
## Contexto
O sistema precisa suportar times independentes trabalhando em
diferentes domínios de negócio com ciclos de deploy independentes.
O catálogo tem requisitos de leitura muito diferentes do serviço
de pedidos, que tem requisitos de consistência que o serviço de
notificações não compartilha.
## Decisão
Adotar arquitetura de microsserviços com cinco serviços principais,
cada um com seu próprio banco de dados (database-per-service pattern).
## Alternativa Considerada
Monolito modular — código organizado em módulos com fronteiras claras
mas deployado como uma única unidade. Menor complexidade operacional,
deploy atômico, sem latência de rede entre módulos.
## Motivo da Escolha
A necessidade de deploy independente entre catálogo (deploy a cada
mudança de produto, várias vezes ao dia) e pedidos (deploy mais
controlado, requer testes extensivos) foi o fator determinante.
Times independentes precisam de deployabilidade independente.
## Consequências
Positivas: Deploy independente por serviço, scaling independente,
isolamento de falhas, autonomia de times.
Negativas: Complexidade operacional elevada (requer Kubernetes,
service discovery, tracing distribuído), latência de rede entre
serviços, consistência eventual entre bancos de dados.
## Critério de Revisão
Se o número de microsserviços superar 15 sem crescimento
proporcional do time, reavaliar consolidação de serviços menores.
ADR-002: Comunicação entre Serviços
# ADR-002: Padrão de Comunicação entre Serviços
**Status:** Aceito
**Data:** 2025-01-15
## Contexto
Serviços precisam se comunicar. As opções principais são:
comunicação síncrona via HTTP/gRPC, ou comunicação assíncrona
via mensageria (SQS, Kafka, EventBridge).
## Decisão
Comunicação híbrida:
- **Síncrona (HTTP/REST)** para consultas que precisam de
resposta imediata: API Gateway → serviços, Pedidos → Catálogo
(verificar estoque), Pedidos → Usuários (autenticação)
- **Assíncrona (SQS)** para eventos que não requerem resposta
imediata: Pedidos → Notificações (confirmar pedido),
Pedidos → Catálogo (atualizar estoque após confirmação)
## Padrão para Comunicação Síncrona
Todos os clientes HTTP inter-serviço usam o ClienteHTTPResilient
com circuit breaker e retry — implementado no Artigo 45.
## Padrão para Comunicação Assíncrona
Produtor publica evento no SQS. Consumidor processa com
visibilidade de 30s e até 3 tentativas antes de mover para DLQ.
Eventos têm schema versionado para compatibilidade.
## Consequências
A combinação evita o acoplamento temporal completo (tudo síncrono)
e a complexidade de tornar tudo assíncrono onde a simplicidade
do request-response é adequada.
ADR-003: Estratégia de Banco de Dados
# ADR-003: Banco de Dados por Serviço
**Status:** Aceito
**Data:** 2025-01-15
## Decisão
Cada microsserviço tem seu próprio banco de dados ou schema isolado.
Nenhum serviço acessa diretamente o banco de outro serviço.
Distribuição dos bancos:
- **Catálogo:** PostgreSQL próprio (leituras intensas, writes moderados)
- **Usuários:** PostgreSQL próprio (dados sensíveis LGPD, acesso auditado)
- **Pedidos:** PostgreSQL próprio (consistência transacional crítica)
- **Notificações:** Sem banco próprio — usa SQS como fonte de verdade
Redis compartilhado para cache — não contém dados de negócio,
apenas cache de leitura com TTL. A perda do Redis é tolerável
(degrada performance, não corrompe dados).
## Alternativa Considerada
Schema por serviço no mesmo banco de dados PostgreSQL — menor
custo de operação, transações entre serviços possíveis.
## Motivo da Rejeição
Schema compartilhado cria acoplamento de infraestrutura: uma
migration mal feita em um serviço pode bloquear os demais.
O isolamento completo tem custo financeiro maior mas garante
autonomia operacional total.
Estrutura do Repositório
O projeto capstone usa um monorepo com fronteiras claras entre serviços:
loja-plataforma/
│
├── services/
│ ├── api-gateway/
│ │ ├── src/
│ │ ├── Dockerfile
│ │ ├── package.json
│ │ └── catalog-info.yaml
│ │
│ ├── catalog-service/
│ │ ├── src/
│ │ ├── Dockerfile
│ │ ├── package.json
│ │ └── catalog-info.yaml
│ │
│ ├── user-service/
│ │ ├── src/
│ │ ├── Dockerfile
│ │ ├── package.json
│ │ └── catalog-info.yaml
│ │
│ ├── order-service/
│ │ ├── src/
│ │ ├── Dockerfile
│ │ ├── package.json
│ │ └── catalog-info.yaml
│ │
│ └── notification-service/
│ ├── src/
│ ├── Dockerfile
│ ├── package.json
│ └── catalog-info.yaml
│
├── infrastructure/
│ ├── terraform/
│ │ ├── environments/
│ │ │ ├── staging/
│ │ │ └── production/
│ │ └── modules/
│ │ ├── eks/
│ │ ├── rds/
│ │ ├── elasticache/
│ │ ├── networking/
│ │ └── observability/
│ └── kubernetes/
│ ├── base/
│ │ ├── namespaces.yaml
│ │ ├── network-policies.yaml
│ │ └── resource-quotas.yaml
│ ├── services/
│ │ ├── api-gateway/
│ │ ├── catalog-service/
│ │ ├── user-service/
│ │ ├── order-service/
│ │ └── notification-service/
│ └── platform/
│ ├── argocd/
│ ├── karpenter/
│ ├── prometheus/
│ └── external-secrets/
│
├── .github/
│ └── workflows/
│ ├── ci-services.yml
│ ├── deploy-infrastructure.yml
│ ├── deploy-services.yml
│ └── security-scan.yml
│
├── docs/
│ ├── adr/ # Architecture Decision Records
│ ├── runbooks/ # Runbooks operacionais
│ └── mkdocs.yml
│
└── scripts/
├── local-dev/
├── chaos/
└── finops/
Contratos de API entre Serviços
Os contratos entre serviços são documentados como especificações OpenAPI e mantidos no repositório. Mudanças incompatíveis requerem versionamento da API:
# services/catalog-service/openapi.yaml
openapi: "3.1.0"
info:
title: Catalog Service API
version: "2.0.0"
description: |
API interna do serviço de catálogo.
Versão 2.0 — não é compatível com v1 (removido campo `preco_antigo`).
servers:
- url: http://catalog-service.producao.svc.cluster.local
description: Cluster interno (DNS Kubernetes)
paths:
/produtos/{id}:
get:
operationId: buscarProduto
summary: Busca produto por ID
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
responses:
"200":
description: Produto encontrado
content:
application/json:
schema:
$ref: '#/components/schemas/Produto'
"404":
$ref: '#/components/responses/NaoEncontrado'
"503":
$ref: '#/components/responses/ServicoIndisponivel'
/produtos/{id}/estoque:
get:
operationId: verificarEstoque
summary: Verifica disponibilidade de estoque
description: |
Endpoint crítico chamado pelo serviço de pedidos durante checkout.
SLA: p99 < 50ms. Circuit breaker configurado com threshold 5 falhas.
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
- name: quantidade
in: query
required: true
schema:
type: integer
minimum: 1
responses:
"200":
description: Informação de estoque
content:
application/json:
schema:
type: object
properties:
disponivel:
type: boolean
quantidade_disponivel:
type: integer
reserva_expira_em:
type: string
format: date-time
nullable: true
components:
schemas:
Produto:
type: object
required: [id, nome, preco, ativo]
properties:
id:
type: string
format: uuid
nome:
type: string
maxLength: 255
descricao:
type: string
nullable: true
preco:
type: number
format: decimal
minimum: 0
preco_promocional:
type: number
format: decimal
nullable: true
categoria_id:
type: string
format: uuid
ativo:
type: boolean
criado_em:
type: string
format: date-time
atualizado_em:
type: string
format: date-time
responses:
NaoEncontrado:
description: Recurso não encontrado
content:
application/json:
schema:
type: object
properties:
erro:
type: string
example: "Produto não encontrado"
codigo:
type: string
example: "PRODUTO_NAO_ENCONTRADO"
ServicoIndisponivel:
description: Serviço temporariamente indisponível
headers:
Retry-After:
schema:
type: integer
description: Segundos até tentar novamente
Modelo de Dados
Cada serviço é dono do seu schema. Os schemas são versionados via migrations com Flyway ou equivalente:
-- services/order-service/migrations/V001__criar_tabelas_pedidos.sql
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE pedidos (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
usuario_id UUID NOT NULL,
status VARCHAR(50) NOT NULL DEFAULT 'rascunho',
subtotal DECIMAL(12,2) NOT NULL DEFAULT 0,
desconto DECIMAL(12,2) NOT NULL DEFAULT 0,
frete DECIMAL(12,2) NOT NULL DEFAULT 0,
total DECIMAL(12,2) NOT NULL DEFAULT 0,
moeda CHAR(3) NOT NULL DEFAULT 'BRL',
endereco_entrega JSONB NOT NULL DEFAULT '{}',
metadata JSONB NOT NULL DEFAULT '{}',
criado_em TIMESTAMPTZ NOT NULL DEFAULT NOW(),
atualizado_em TIMESTAMPTZ NOT NULL DEFAULT NOW(),
confirmado_em TIMESTAMPTZ,
cancelado_em TIMESTAMPTZ,
CONSTRAINT status_valido CHECK (
status IN (
'rascunho', 'aguardando_pagamento', 'pago',
'em_separacao', 'enviado', 'entregue', 'cancelado'
)
),
CONSTRAINT total_positivo CHECK (total >= 0),
CONSTRAINT subtotal_positivo CHECK (subtotal >= 0)
);
CREATE TABLE itens_pedido (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
pedido_id UUID NOT NULL REFERENCES pedidos(id) ON DELETE CASCADE,
produto_id UUID NOT NULL,
-- Snapshot do produto no momento do pedido
-- Não usa FK para catalog-service — serviços são independentes
nome_produto VARCHAR(255) NOT NULL,
preco_unitario DECIMAL(12,2) NOT NULL,
quantidade INTEGER NOT NULL,
subtotal DECIMAL(12,2) NOT NULL,
CONSTRAINT quantidade_positiva CHECK (quantidade > 0),
CONSTRAINT preco_positivo CHECK (preco_unitario > 0)
);
CREATE TABLE eventos_pedido (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
pedido_id UUID NOT NULL REFERENCES pedidos(id),
tipo VARCHAR(100) NOT NULL,
payload JSONB NOT NULL DEFAULT '{}',
criado_por VARCHAR(255), -- ID do usuário ou 'sistema'
criado_em TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Índices para as queries mais comuns
CREATE INDEX idx_pedidos_usuario_id
ON pedidos(usuario_id)
WHERE status NOT IN ('cancelado');
CREATE INDEX idx_pedidos_status_criado
ON pedidos(status, criado_em DESC);
CREATE INDEX idx_itens_pedido_pedido_id
ON itens_pedido(pedido_id);
CREATE INDEX idx_eventos_pedido_id
ON eventos_pedido(pedido_id, criado_em DESC);
-- Trigger para atualizar atualizado_em automaticamente
CREATE OR REPLACE FUNCTION atualizar_timestamp()
RETURNS TRIGGER AS $$
BEGIN
NEW.atualizado_em = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trigger_pedidos_atualizado_em
BEFORE UPDATE ON pedidos
FOR EACH ROW EXECUTE FUNCTION atualizar_timestamp();
SLOs do Sistema
Os Service Level Objectives definem o que significa "funcionar bem" para cada serviço:
# kubernetes/platform/slos.yaml
# SLOs definidos usando o formato OpenSLO
apiVersion: openslo/v1
kind: SLO
metadata:
name: api-gateway-disponibilidade
namespace: producao
spec:
service: api-gateway
description: "Disponibilidade do API Gateway — requisições com sucesso"
budgetingMethod: Occurrences
objectives:
- displayName: "99.5% de disponibilidade"
target: 0.995
# Considera falha: status 5xx ou timeout
indicator:
ratio:
good:
metric:
prometheusMetric:
query: |
sum(rate(http_requests_total{
service="api-gateway",
status!~"5.."
}[5m]))
total:
metric:
prometheusMetric:
query: |
sum(rate(http_requests_total{
service="api-gateway"
}[5m]))
---
apiVersion: openslo/v1
kind: SLO
metadata:
name: order-service-latencia
namespace: producao
spec:
service: order-service
description: "Latência do checkout — p99 abaixo de 1 segundo"
budgetingMethod: Occurrences
objectives:
- displayName: "p99 < 1s para checkout"
target: 0.99
indicator:
ratio:
good:
metric:
prometheusMetric:
query: |
sum(rate(http_request_duration_seconds_bucket{
service="order-service",
endpoint="/checkout",
le="1.0"
}[5m]))
total:
metric:
prometheusMetric:
query: |
sum(rate(http_request_duration_seconds_count{
service="order-service",
endpoint="/checkout"
}[5m]))
Plano de Implementação
Os próximos quatro artigos implementam o sistema em etapas incrementais, cada uma entregando valor independente:
Artigo 49 — Infraestrutura: Provisionamento completo do cluster EKS, RDS, ElastiCache, SQS e networking com Terraform. Ao final, a infraestrutura está pronta para receber os serviços.
Artigo 50 — Os Serviços: Implementação dos cinco microsserviços com código funcional, testes, Dockerfiles otimizados e manifestos Kubernetes. Ao final, os serviços rodam localmente com Docker Compose e no cluster com kubectl apply.
Artigo 51 — Pipeline Completo: Pipeline de CI/CD com GitHub Actions que executa testes, scanning de segurança, build de imagem, deploy no EKS via ArgoCD e verificação pós-deploy. Ao final, um push para main resulta automaticamente em deploy em produção.
Artigo 52 — Operações em Produção: Dashboards de observabilidade, alertas calibrados, runbooks, experimentos de chaos, configuração de backups e o postmortem do primeiro incidente simulado. Ao final, o sistema está operacionalmente maduro.
O Que Vem a Seguir
O próximo artigo começa a implementação com o que sustenta tudo: a infraestrutura. O Terraform provisiona o cluster EKS, os bancos de dados, o cache, as filas e toda a rede com os controles de segurança que os artigos anteriores descreveram — desta vez, integrados em um único sistema coerente.
Referências para Aprofundamento
Arquitetura de microsserviços - Microservices Patterns — Chris Richardson — microservices.io — Catálogo completo dos padrões de microsserviços com descrição do problema, solução, exemplos e trade-offs. Referência essencial para qualquer arquiteto trabalhando com microsserviços. - Building Microservices — O'Reilly — oreilly.com — Livro de referência de Sam Newman cobrindo todos os aspectos de microsserviços em produção, da decomposição à operação.
Architecture Decision Records - ADR GitHub — adr.github.io — Repositório de templates e ferramentas para Architecture Decision Records, incluindo o formato MADR e ferramentas de linha de comando para gerenciamento.
OpenSLO - OpenSLO Specification — openslo.com — Especificação aberta para definição de SLOs, com suporte a múltiplos backends de observabilidade e integração com Kubernetes via operadores.