Ir para o conteúdo
Ferramenta para Plataforma1613 palavras

Prometheus para AWS: Guia Completo de Deploy

Introdução

Monitorar aplicações em produção não é opcional. É a diferença entre descobrir um problema pelo alerta do seu dashboard ou pelo cliente reclamando no Twitter. O Prometheus se consolidou como a ferramenta padrão de monitoramento no ecossistema cloud native, e quando combinado com a infraestrutura da AWS, forma uma stack de observabilidade robusta e escalável.

Neste guia, vamos configurar o Prometheus na AWS do zero, passando pelo deploy, pela integração com serviços gerenciados e pela instrumentação de aplicações em TypeScript. O objetivo é que, ao final da leitura, você tenha um caminho claro para implementar monitoramento de verdade nos seus projetos.

Se você já acompanha o blog, este post complementa o guia DevOps para Devs: Docker, CI/CD, Kubernetes e AWS em Produção, onde cobrimos a base de infraestrutura que vamos usar aqui.

Por que usar Prometheus com AWS

O problema que estamos resolvendo

A AWS oferece o CloudWatch como solução nativa de monitoramento. Ele funciona bem para métricas de infraestrutura básica (CPU, memória, rede), mas apresenta limitações sérias quando você precisa de métricas customizadas de aplicação, alertas complexos baseados em queries PromQL e dashboards granulares.

O Prometheus resolve exatamente essas lacunas. Ele permite que você defina métricas de negócio (quantas transações por segundo, latência do endpoint de checkout, taxa de erro por tenant), e consulte esses dados com uma linguagem de query poderosa.

Quando essa combinação brilha

Existem cenários onde Prometheus na AWS é a escolha ideal:

  1. Microserviços em ECS ou EKS: quando você tem dezenas de serviços e precisa de métricas padronizadas com service discovery automático.
  2. Aplicações multi-tenant em SaaS: onde métricas por cliente são essenciais para SLAs e billing.
  3. Workloads com auto scaling: o Prometheus descobre automaticamente novas instâncias via EC2 service discovery ou Kubernetes SD.
  4. Equipes que já usam Grafana: a integração entre Prometheus e Grafana é nativa e madura.

Amazon Managed Service for Prometheus (AMP)

A AWS oferece o Amazon Managed Service for Prometheus, que elimina a necessidade de gerenciar o servidor Prometheus manualmente. Ele é compatível com PromQL, aceita remote write do Prometheus padrão e escala automaticamente. Para equipes que não querem manter infraestrutura de monitoramento, o AMP é a escolha mais pragmática.

Setup do Prometheus na AWS

Opção 1: Prometheus self-hosted no ECS

Vamos começar com o deploy do Prometheus como container no ECS Fargate. Primeiro, crie o arquivo de configuração do Prometheus:

YAML
# prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s
 
scrape_configs:
  - job_name: "api-service"
    ec2_sd_configs:
      - region: sa-east-1
        port: 3000
        filters:
          - name: "tag:Environment"
            values: ["production"]
          - name: "tag:Monitoring"
            values: ["enabled"]
    relabel_configs:
      - source_labels: [__meta_ec2_tag_Name]
        target_label: instance_name
      - source_labels: [__meta_ec2_instance_id]
        target_label: instance_id
      - source_labels: [__meta_ec2_availability_zone]
        target_label: availability_zone
 
  - job_name: "ecs-services"
    dns_sd_configs:
      - names:
          - "api.production.local"
          - "worker.production.local"
        type: SRV
        port: 9090

Para subir o Prometheus no ECS, use a AWS CLI:

Bash
# Criar o repositório ECR para a imagem customizada do Prometheus
aws ecr create-repository \
  --repository-name monitoring/prometheus \
  --region sa-east-1
 
# Build e push da imagem
docker build -t prometheus-custom .
docker tag prometheus-custom:latest \
  123456789012.dkr.ecr.sa-east-1.amazonaws.com/monitoring/prometheus:latest
 
aws ecr get-login-password --region sa-east-1 | \
  docker login --username AWS --password-stdin \
  123456789012.dkr.ecr.sa-east-1.amazonaws.com
 
docker push \
  123456789012.dkr.ecr.sa-east-1.amazonaws.com/monitoring/prometheus:latest
 
# Registrar a task definition
aws ecs register-task-definition \
  --cli-input-json file://prometheus-task-definition.json
 
# Criar o serviço
aws ecs create-service \
  --cluster monitoring \
  --service-name prometheus \
  --task-definition prometheus:1 \
  --desired-count 1 \
  --launch-type FARGATE \
  --network-configuration "awsvpcConfiguration={subnets=[subnet-abc123],securityGroups=[sg-abc123],assignPublicIp=DISABLED}"

Opção 2: Amazon Managed Prometheus (AMP)

Para quem prefere o serviço gerenciado, a configuração é mais direta:

Bash
# Criar o workspace do AMP
aws amp create-workspace \
  --alias production-metrics \
  --region sa-east-1
 
# O comando retorna um workspaceId, que vamos usar para configurar o remote write
# Exemplo de saída: ws-abc123def456
 
# Configurar o remote write no prometheus.yml

Adicione a seção de remote write ao seu prometheus.yml:

YAML
remote_write:
  - url: https://aps-workspaces.sa-east-1.amazonaws.com/workspaces/ws-abc123def456/api/v1/remote_write
    queue_config:
      max_samples_per_send: 1000
      max_shards: 200
      capacity: 2500
    sigv4:
      region: sa-east-1

A autenticação é feita via IAM usando SigV4, então a role do seu ECS task precisa da policy AmazonPrometheusRemoteWriteAccess.

Exemplo Prático: Instrumentando uma API TypeScript

Exportando métricas customizadas com prom-client

Vamos instrumentar uma API Express real com métricas que importam em produção. Este primeiro exemplo mostra a configuração completa do módulo de métricas:

TYPESCRIPT
// src/metrics/prometheus.ts
import express, { Request, Response, NextFunction } from "express";
import client, {
  Registry,
  Counter,
  Histogram,
  Gauge,
  Summary,
} from "prom-client";
 
const register = new Registry();
 
client.collectDefaultMetrics({
  register,
  prefix: "api_",
  labels: {
    service: "checkout-api",
    environment: process.env.NODE_ENV || "development",
  },
});
 
export const httpRequestsTotal = new Counter({
  name: "http_requests_total",
  help: "Total de requisicoes HTTP recebidas",
  labelNames: ["method", "route", "status_code"] as const,
  registers: [register],
});
 
export const httpRequestDuration = new Histogram({
  name: "http_request_duration_seconds",
  help: "Duracao das requisicoes HTTP em segundos",
  labelNames: ["method", "route", "status_code"] as const,
  buckets: [0.01, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10],
  registers: [register],
});
 
export const activeConnections = new Gauge({
  name: "active_connections",
  help: "Numero de conexoes ativas no momento",
  registers: [register],
});
 
export const checkoutProcessingTime = new Summary({
  name: "checkout_processing_duration_seconds",
  help: "Tempo de processamento do checkout",
  labelNames: ["payment_method", "tenant_id"] as const,
  percentiles: [0.5, 0.9, 0.95, 0.99],
  registers: [register],
});
 
export function metricsMiddleware(
  req: Request,
  res: Response,
  next: NextFunction
): void {
  const start = process.hrtime.bigint();
 
  activeConnections.inc();
 
  res.on("finish", () => {
    const durationNs = Number(process.hrtime.bigint() - start);
    const durationSeconds = durationNs / 1e9;
 
    const route = req.route?.path || req.path || "unknown";
    const labels = {
      method: req.method,
      route: route,
      status_code: String(res.statusCode),
    };
 
    httpRequestsTotal.inc(labels);
    httpRequestDuration.observe(labels, durationSeconds);
    activeConnections.dec();
  });
 
  next();
}
 
export async function metricsHandler(
  _req: Request,
  res: Response
): Promise<void> {
  res.set("Content-Type", register.contentType);
  const metrics = await register.metrics();
  res.end(metrics);
}
 
export { register };

Usando as métricas em rotas de negócio

O segundo exemplo mostra como instrumentar lógica de negócio real, integrando as métricas com o fluxo de checkout:

TYPESCRIPT
// src/routes/checkout.ts
import { Router, Request, Response } from "express";
import {
  checkoutProcessingTime,
  metricsMiddleware,
  metricsHandler,
} from "../metrics/prometheus";
 
interface CheckoutPayload {
  cartId: string;
  paymentMethod: "credit_card" | "pix" | "boleto";
  tenantId: string;
}
 
interface CheckoutResult {
  orderId: string;
  status: "confirmed" | "pending" | "failed";
  processedAt: string;
}
 
const router = Router();
 
router.use(metricsMiddleware);
router.get("/metrics", metricsHandler);
 
async function processPayment(
  payload: CheckoutPayload
): Promise<CheckoutResult> {
  const delay = Math.random() * 2000 + 500;
  await new Promise((resolve) => setTimeout(resolve, delay));
 
  return {
    orderId: `ORD-${Date.now()}`,
    status: "confirmed",
    processedAt: new Date().toISOString(),
  };
}
 
router.post("/checkout", async (req: Request, res: Response): Promise<void> => {
  const payload: CheckoutPayload = req.body;
  const startTime = performance.now();
 
  try {
    const result = await processPayment(payload);
 
    const durationSeconds = (performance.now() - startTime) / 1000;
 
    checkoutProcessingTime.observe(
      {
        payment_method: payload.paymentMethod,
        tenant_id: payload.tenantId,
      },
      durationSeconds
    );
 
    res.status(200).json({
      success: true,
      data: result,
    });
  } catch (error: unknown) {
    const durationSeconds = (performance.now() - startTime) / 1000;
 
    checkoutProcessingTime.observe(
      {
        payment_method: payload.paymentMethod,
        tenant_id: payload.tenantId,
      },
      durationSeconds
    );
 
    const message =
      error instanceof Error ? error.message : "Erro desconhecido";
    res.status(500).json({
      success: false,
      error: message,
    });
  }
});
 
router.get("/health", (_req: Request, res: Response): void => {
  res.status(200).json({
    status: "healthy",
    uptime: process.uptime(),
    timestamp: new Date().toISOString(),
  });
});
 
export default router;

Com essa instrumentação, você consegue responder perguntas como: "Qual a latência p99 do checkout via Pix no tenant X?" usando PromQL:

PROMQL
histogram_quantile(0.99, 
  rate(checkout_processing_duration_seconds{payment_method="pix", tenant_id="tenant-42"}[5m])
)

Boas Práticas de Monitoramento com Prometheus na AWS

Nomenclatura e cardinalidade

Siga a convenção de nomes do Prometheus: snake_case, com sufixos que indicam a unidade (_seconds, _bytes, _total). Cuidado absoluto com a cardinalidade das labels. Nunca use valores como user ID ou request ID como label. Isso vai explodir sua série temporal e derrubar o Prometheus.

Regra prática: se uma label pode ter mais de 100 valores distintos, repense se ela deve existir.

Retenção e armazenamento de longo prazo

O Prometheus local mantém dados por 15 dias, que é suficiente para troubleshooting imediato. Para retenção de longo prazo na AWS, configure o remote write para o Amazon Managed Prometheus ou para um bucket S3 via Thanos. A combinação AMP com Grafana Managed (via Amazon Managed Grafana) elimina toda a operação de manter servidores de monitoramento.

Segurança e rede

Nunca exponha o endpoint /metrics para a internet. Use security groups para permitir acesso apenas do Prometheus ao port de métricas dos seus serviços. Em EKS, utilize network policies. Para o AMP, a autenticação via IAM com SigV4 já fornece controle granular.

Alertas que funcionam

Configure alertas baseados em sintomas, não em causas. Em vez de alertar quando a CPU passa de 80%, alerte quando a latência p95 do seu endpoint crítico ultrapassa o SLA:

YAML
# alerting-rules.yml
groups:
  - name: sla_alerts
    rules:
      - alert: HighCheckoutLatency
        expr: |
          histogram_quantile(0.95,
            rate(http_request_duration_seconds_bucket{route="/checkout"}[5m])
          ) > 2.0
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Latencia p95 do checkout acima de 2 segundos"
          description: "O endpoint /checkout esta com latencia p95 de {{ $value }}s nos ultimos 5 minutos."

Custo

O Amazon Managed Prometheus cobra por amostras ingeridas e armazenadas. Monitore o volume de métricas para evitar surpresas na fatura. Use metric_relabel_configs para descartar métricas desnecessárias antes da ingestão.

Conclusão

Prometheus na AWS não é apenas sobre instalar uma ferramenta de monitoramento. É sobre construir uma cultura de observabilidade onde cada serviço expõe métricas relevantes, os alertas são acionáveis e os dashboards contam a história da saúde do sistema.

O caminho mais pragmático para a maioria das equipes é começar com o Amazon Managed Prometheus para eliminar a operação do servidor, instrumentar as aplicações com prom-client, e usar o Grafana para visualização. Conforme a maturidade cresce, você adiciona alertas baseados em SLOs e expande a cobertura para métricas de negócio.

Comece simples: instrumente um serviço, crie um dashboard, configure um alerta. Depois expanda. Monitoramento é um processo iterativo, e a pior métrica é aquela que não existe.

Guias Relacionados

Explore mais guias técnicos

Mais de 100 guias práticos de integração entre frameworks, ferramentas e plataformas.

Ver todos os guias