Monitoreo AWS con amazon-cloudwatch-agent | Daniel Tinizaray

Monitoreo AWS con amazon-cloudwatch-agent | Daniel Tinizaray

Por qué amazon-cloudwatch-agent

Por defecto, CloudWatch entrega métricas básicas de EC2: CPU promedio, tráfico de red, checks de estado. Suficiente para saber si una instancia está viva, insuficiente para entender cómo se está comportando.

amazon-cloudwatch-agent es el recolector oficial de AWS que corre dentro de la instancia y envía métricas del sistema operativo real: memoria usada/libre, swap, disco por partición, CPU por proceso, y logs personalizados. Sin él, estás monitoreando a ciegas todo lo que pasa fuera del hipervisor.

La diferencia es simple: las métricas de hipervisor te dicen que la instancia está encendida. Las métricas del SO te dicen por qué se cayó.

1. Instalación en EC2 (Amazon Linux 2023 / Ubuntu)

La instalación varía por SO, pero el flujo es idéntico:

Amazon Linux 2023

sudo yum install amazon-cloudwatch-agent -y

Ubuntu 22.04 / 24.04

wget https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb
sudo dpkg -i amazon-cloudwatch-agent.deb

Luego se configura con un wizard interactivo o —recomendado— con un archivo JSON:

sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard

El wizard genera el archivo en /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json. Pero prefiero escribirlo manualmente desde el inicio —más control, menos prompts.

2. Configuración Esencial

El archivo de configuración tiene dos secciones principales: metrics (métricas del SO) y logs (archivos de log).

Aquí una config base que cubre el 90% de los casos:

{
  "agent": {
    "region": "us-east-1",
    "run_as_user": "root",
    "collect_metrics_interval": "60s",
    "omit_hostname": false
  },
  "metrics": {
    "namespace": "CWAgent",
    "metrics_collected": {
      "cpu": {
        "measurement": [
          "cpu_usage_idle",
          "cpu_usage_user",
          "cpu_usage_system",
          "cpu_usage_iowait"
        ],
        "metrics_collection_interval": 60,
        "totalcpu": true
      },
      "mem": {
        "measurement": [
          "mem_used_percent",
          "mem_available_percent"
        ],
        "metrics_collection_interval": 60
      },
      "disk": {
        "measurement": [
          "disk_used_percent",
          "disk_inodes_free"
        ],
        "metrics_collection_interval": 120,
        "resources": ["/", "/var", "/data"]
      },
      "swap": {
        "measurement": ["swap_used_percent"],
        "metrics_collection_interval": 120
      },
      "netstat": {
        "measurement": ["tcp_established", "tcp_time_wait"],
        "metrics_collection_interval": 120
      }
    },
    "append_dimensions": {
      "InstanceId": "${aws:InstanceId}",
      "AutoScalingGroupName": "${aws:AutoScalingGroupName}",
      "ImageId": "${aws:ImageId}"
    }
  },
  "logs": {
    "logs_collected": {
      "files": {
        "collect_list": [
          {
            "file_path": "/var/log/syslog",
            "log_group_name": "syslog",
            "log_stream_name": "{instance_id}",
            "timestamp_format": "%b %-d %H:%M:%S"
          }
        ]
      }
    }
  }
}

Puntos clave de esta configuración:

  • collect_metrics_interval: 60s — Suficiente granularidad sin disparar costos.
  • append_dimensions — Cada métrica se etiqueta con el InstanceId y ASG, habilitando filtros en dashboards.
  • disk.resources — Especificar particiones concretas evita recolectar tmpfs y bind mounts irrelevantes.
  • iowait — La métrica más ignorada y la primera en subir cuando el almacenamiento es el cuello de botella.

Para aplicar la configuración:

sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \
  -a fetch-config -m ec2 \
  -c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json \
  -s

La bandera -s reinicia el servicio con la nueva config. Sin -s, los cambios no se aplican hasta el próximo reinicio.

3. Métricas por Proceso con procstat

Cuando necesitas saber no solo cuánto CPU consume la instancia, sino qué proceso lo está consumiendo, el plugin procstat es la respuesta:

"procstat": [
  {
    "pattern": "nginx",
    "measurement": ["cpu_usage", "memory_rss", "pid_count"],
    "metrics_collection_interval": 60
  },
  {
    "pattern": "python",
    "measurement": ["cpu_usage", "memory_rss"],
    "metrics_collection_interval": 60
  }
]

pattern acepta una expresión regular contra el nombre del proceso. Si el proceso se llama nginx: worker process, con "nginx" como pattern capturas todos los workers. La métrica pid_count te dice cuántos procesos matchearon, útil para verificar que el número de workers de Nginx o Gunicorn es el esperado.

Si en producción ves CPU al 95% pero no sabes si es Nginx, la base de datos o un proceso zombie, procstat es la diferencia entre debugging de 5 minutos y debugging de 2 horas.

4. Logs Personalizados → CloudWatch Logs

El agent también envía logs a CloudWatch Logs. La configuración de ejemplo ya incluye syslog, pero puedes agregar cualquier archivo:

"logs": {
  "logs_collected": {
    "files": {
      "collect_list": [
        {
          "file_path": "/var/log/nginx/access.log",
          "log_group_name": "nginx-access",
          "log_stream_name": "{instance_id}",
          "timestamp_format": "%d/%b/%Y:%H:%M:%S %z",
          "timezone": "UTC"
        },
        {
          "file_path": "/var/log/nginx/error.log",
          "log_group_name": "nginx-error",
          "log_stream_name": "{instance_id}",
          "timestamp_format": "%Y/%m/%d %H:%M:%S",
          "timezone": "UTC"
        }
      ]
    }
  }
}

Una vez en CloudWatch Logs, puedes crear metric filters para extraer patrones (por ejemplo, HTTP 5xx > umbral) sin modificar una línea de código de la aplicación. Son consultas que se ejecutan sobre el flujo de logs en tiempo real y emiten métricas a CloudWatch.

5. Costos: Cómo No Arruinarse

El talón de Aquiles de CloudWatch es el costo de métricas personalizadas. Cada combinación única de nombre de métrica + dimensión se cobra por separado. Con append_dimensions, cada instancia genera su propia combinación.

Reglas prácticas de costo:

  • Usa el namespace CWAgent por defecto. No crees namespaces por proyecto a menos que sea estrictamente necesario.
  • No recolectes todo. De las 60+ métricas que el agent puede recolectar, elige 10-15 que realmente necesites.
  • Intervalos de 60s o más. 60s cuesta 1 unidad de métrica por minuto. 10s cuesta 6. El factor es lineal.
  • Agrupa dimensiones. InstanceId es necesario, pero evita agregar dimensiones volátiles como hostname o ip que multiplican combinaciones.
  • Métricas resumidas via dashboards. Usa AVG, SUM, p95 en el dashboard sobre las métricas raw —no crees métricas pre-agregadas.
  • Limpia instancias terminadas. Las métricas de instancias muertas siguen facturando si tienen alarmas asociadas. Revisa periódicamente.

Una instancia típica con 15 métricas a 60s de intervalo cuesta ~$3-5 USD/mes en custom metrics. Comparado con soluciones third-party, es económico —pero sin control, puede escalar a $50+/mes por instancia.

6. Integración con Alarmas y Dashboards

Una vez que el agent envía datos, las métricas aparecen automáticamente en CloudWatch. Puedes crear alarmas directamente:

  • Memoria > 90% durante 5 minutos → notificación SNS a Slack/Email.
  • Disk usado > 85% en root → escala de volumen EBS o limpieza automática.
  • iowait > 20% sostenido → probablemente el volume EBS está IOPS-throttled. Revisar si es gp2 vs gp3.
  • nginx pid_count == 0 → el proceso no está corriendo. Alarma inmediata.

En el dashboard, las dimensiones InstanceId y AutoScalingGroupName permiten filtrar por servidor o por grupo. Un dashboard bien diseñado responde en segundos: "¿cuál de las 20 instancias tiene alta memoria?" sin tener que revisar una por una.

7. amazon-cloudwatch-agent vs Proveedores Third-Party

¿Por qué usar el agent nativo de AWS y no Datadog, New Relic o Grafana Agent?

  • Costo: CloudWatch Agent no tiene licencia adicional. Solo pagas almacenamiento de métricas y APIs. Ningún third-party es más barato a escala.
  • Latencia: Las métricas viajan dentro de la red de AWS sin salir a internet. En instancias con datos sensibles, evitas exfiltrar métricas a un SaaS externo.
  • Integración nativa: CloudWatch Dashboards, Alarmas, Logs Insights y Lambda son el ecosistema natural de AWS. No necesitas exporters ni bridges.
  • Menos moving parts: Un solo agent, un solo archivo de config. Sin DaemonSets, sin sidecars, sin pipelines de OpenTelemetry complejos.

La contra: CloudWatch no tiene el ecosistema de alertas inteligentes ni dashboards tan flexibles como Grafana. Tampoco tiene SLI/SLO tracking nativo. Para equipos pequeños a medianos (< 50 instancias), es más que suficiente. Para orquestación compleja, Grafana + Prometheus sigue siendo el estándar —pero puedes usar CloudWatch + Grafana vía AWS Managed Grafana sin renunciar a lo mejor de ambos.

Conclusión

amazon-cloudwatch-agent es la pieza faltante entre las métricas del hipervisor y lo que realmente pasa dentro del servidor. Sin él, estás volando a ciegas: sabes que la instancia está encendida, pero no si se está quedando sin memoria, si el disco está saturado, o si Nginx se cayó hace 20 minutos.

La configuración presentada aquí cubre el 90% de los escenarios de monitoreo en producción para equipos que corren aplicaciones web, APIs, workers o batch processing en EC2. No necesitas un stack ELK, ni un cluster de Prometheus, ni un contrato con Datadog. Necesitas un agent de 10 MB, un archivo JSON de 50 líneas, y saber qué métricas importan.

El resto es ruido.


¿Te gustó este artículo?

Si estás lidiando con estos desafíos en tu empresa, hablemos. Sin compromiso. 30 minutos para entender tu situación.

Agenda una llamada gratuita →