Uma das lacunas que eu queria fechar nos estudos para o SAA-C03 era o monitoramento de instâncias EC2. Não a parte teórica de “o CloudWatch coleta métricas e dispara alarmes”, essa parte eu já sabia. A lacuna era não ter feito isso do zero nenhuma vez: instância no ar, agente instalado, alarme configurado, email chegando. Ciclo completo.
Esse post documenta esse ciclo, incluindo os problemas que apareceram no caminho, que acabaram servindo de aprendizado.
Subindo a instância EC2
No painel da AWS, vou em EC2 e clico em Launch Instance.
- Nome:
ec2-cloudwatch-nginx-lab - Imagem: Ubuntu 24.04 LTS
- Tipo:
t3.micro - AZ:
sa-east-1a(region mais próxima, menor latência para o lab)
Em Key pair, clico para gerar uma nova. Nome: aws-ec2-cloudwatch-nginx-lab, tipo RSA, formato .pem. O arquivo baixa automaticamente.
Em Network Settings, deixei o SSH aberto para qualquer IP. Não recomendo em produção, mas como é um lab que será deletado depois, prefiro ter essa flexibilidade para acessar de lugares diferentes. Marquei também Allow HTTP traffic e Allow HTTPS traffic.
Storage no padrão, 8 GB. Launch Instance.
Em pouquíssimo tempo a instância está up.
Conectando via SSH
Para conectar, abro o PowerShell do Windows dentro da pasta onde está a chave .pem e rodo:
ssh -i aws-ec2-cloudwatch-nginx-lab.pem ubuntu@SEU-DNS-PUBLICO
Se aparecer o erro UNPROTECTED PRIVATE KEY FILE, rode esses dois comandos no PowerShell:
icacls aws-ec2-cloudwatch-nginx-lab.pem /inheritance:r
icacls aws-ec2-cloudwatch-nginx-lab.pem /grant:r "%USERNAME%:(R)"
Se ainda reclamar, tenta executar o PowerShell como administrador.
No linux você pode usar o comando chmod:
chmod 400 aws-ec2-cloudwatch-nginx-lab.pem
Como alternativa, a AWS tem o EC2 Instance Connect, você abre o terminal da instância direto no navegador. É só acessar a instância, clicar em Connect e pronto. Bem prático quando você está numa máquina que não tem o .pem.
Instalando o Docker e subindo o Nginx
Conectado, primeiro atualizo o sistema:
sudo apt update && sudo apt upgrade -y
Instalo o Docker:
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker ubuntu
Já fiz isso no meu tutorial de Homelab no OCI, então é bem tranquilo.
Crio uma pasta para o lab:
mkdir ec2_teste
cd ec2_teste/
Crio o arquivo do docker-compose.yml:
touch docker-compose.yml
sudo nano docker-compose.yml
Conteúdo:
version: '3.8'
services:
nginx-proxy:
image: jc21/nginx-proxy-manager:latest
container_name: nginx-proxy
restart: unless-stopped
ports:
- "80:80"
- "81:81"
- "443:443"
volumes:
- ./npm-data:/data
- ./npm-letsencrypt:/etc/letsencrypt
CTRL+O para salvar, CTRL+X para sair do nano.
Libero as portas no firewall:
sudo apt install iptables-persistent -y
sudo iptables -I INPUT 1 -p tcp -m multiport --dports 80,443,81 -j ACCEPT
sudo netfilter-persistent save
Subo o container:
sudo docker compose up -d
Abrindo o navegador com o IP público da instância, o Nginx Proxy Manager já está no ar.
Instalando e configurando o CloudWatch Agent
Com a instância rodando e o Nginx no ar, o próximo passo é monitorar os recursos dela com o CloudWatch.
Por padrão, a AWS já coleta algumas métricas básicas de CPU via hipervisor, mas disco e memória não aparecem sem o CloudWatch Agent instalado. Vamos resolver isso.
Instalando o agente
O pacote não está nos repositórios padrão do Ubuntu, então baixo o .deb direto da AWS:
wget https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb
sudo dpkg -i amazon-cloudwatch-agent.deb
Configurando o agente
Com o agente instalado, rodo o wizard de configuração:
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard
Respondi assim:
| Pergunta | Resposta |
|---|---|
| On which OS? | 1 (Linux) |
| EC2 or on-premises? | 1 (EC2) |
| Which user? | 2 (root) |
| StatsD daemon? | 2 (no) |
| Monitor metrics? | 1 (yes) |
| CPU interval | 4 (60s) |
| Disk metrics | 1 (yes) |
| Memory metrics | 1 (yes) |
| Resto | Enter para aceitar os padrões |
O wizard gera o arquivo de configuração automaticamente. Inicio o agente:
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \
-a fetch-config -m ec2 -s \
-c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json
Erro 1: arquivo do collectd não encontrado
Apareceu esse erro:
open /usr/share/collectd/types.db: no such file or directory
O agente procura um arquivo do collectd que não vem instalado por padrão no Ubuntu 24.04. A solução é simples: criar o arquivo vazio para o agente parar de reclamar.
sudo mkdir -p /usr/share/collectd && sudo touch /usr/share/collectd/types.db
Rodei o comando de iniciar de novo e passou.
Erro 2: métricas não apareciam no CloudWatch
O agente estava rodando, mas o namespace CWAgent não aparecia no console. Fui verificar os logs:
sudo tail -50 /opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log
O erro era bem claro:
UnauthorizedOperation: not authorized to perform: ec2:DescribeTags
Aqui entra um conceito importante do modelo de segurança da AWS: tudo que não foi explicitamente permitido está bloqueado por padrão. Uma instância EC2 não tem acesso a nenhum outro serviço da conta simplesmente por existir. Para que o agente consiga enviar métricas para o CloudWatch, a instância precisa de uma IAM Role com as permissões corretas, e ela não vem configurada por padrão.
A alternativa seria colocar credenciais diretas na instância, mas isso é exatamente o que não se faz. Role é o caminho certo: as credenciais são temporárias, rotacionadas automaticamente e ficam fora do código.
Resolvi assim:
- IAM → Roles → Create role → AWS Service → EC2
- Anexei as policies:
CloudWatchAgentServerPolicyAmazonEC2ReadOnlyAccess
- Nome da role:
ec2-cloudwatch-role - EC2 → instância → Actions → Security → Modify IAM role → seleciono
ec2-cloudwatch-role - Reinicio o agente:
sudo systemctl restart amazon-cloudwatch-agent
Dessa vez sem erros nos logs. Aguardei 2 minutos e o namespace CWAgent apareceu no CloudWatch com as métricas de disco e memória sendo coletadas.
Criando os alarmes
Com as métricas chegando, crio os alarmes. No console AWS:
CloudWatch → Alarms → All alarms → Create alarm
Clico em Select metric → EC2 → Per-Instance Metrics, busco minha instância e seleciono CPUUtilization.
Configurações:
- Period: 1 minute
- Condition: Greater than 80
Em Notification, crio um novo tópico SNS com meu email. A inscrição chega no email e confirmo.
Nome do alarme: CPU-alto-lab.
Repito o processo para disco: em CWAgent busco disk_used_percent e crio o alarme com threshold de 80%.
Testando o alarme de CPU
Hora de ver se funciona de verdade. Instalo o stress:
sudo apt install stress -y
Forço carga máxima de CPU nos 2 núcleos por 3 minutos:
stress --cpu 2 --timeout 180
No CloudWatch o gráfico sobe imediatamente. Em 1 a 2 minutos o alarme muda para In alarm e o email de alerta chega.
O ciclo fechou: instância no ar, agente coletando, alarme disparando, notificação chegando. O Erro 2 foi o que deu mais trabalho, mas também o que ficou. A negação implícita da AWS não é detalhe de configuração, é o modelo. Entender isso muda como você pensa permissões em cloud.