AWS CloudWatch ile Sunucu İzleme: Kapsamlı Rehber

Sunucularınız sessiz sedasız çökerken siz kahve içiyor olabilirsiniz. Ya da tam tersi, her şey yolundayken alarm üstüne alarm alıp gecenizi berbat edebilirsiniz. İkisi de kötü. AWS CloudWatch, doğru kurulduğunda bu iki uç arasında sizi dengede tutan bir izleme altyapısı sunar. Ama “doğru kurulduğunda” kısmı önemli, çünkü varsayılan ayarlarla bırakılan CloudWatch kurulumu, sizi gerçek anlamda korumaz.

Bu yazıda production ortamında çalışan EC2 sunucularını CloudWatch ile nasıl etkili şekilde izleyeceğinizi, özel metrikler nasıl göndereceğinizi, anlamlı alarmlar nasıl kuracağınızı ve log yönetimini nasıl yapılandıracağınızı gerçek dünya senaryolarıyla ele alacağız.

CloudWatch’ın Temel Mantığı

CloudWatch temelde üç şey yapar: metrik toplar, log depolar ve bunlara göre aksiyon aldırır. Basit görünüyor ama derinliği var.

Metrikler, CloudWatch’ın kalbidir. CPU kullanımı, disk I/O, ağ trafiği gibi sayısal verilerdir. AWS servisleri bazı metrikleri otomatik olarak gönderir, ama dikkat edin: EC2 için bellek kullanımı varsayılan olarak gelmez. Bunu öğrenen her sysadmin bir an duraksıyor, çünkü bellek dolup sunucu yavaşlarken CloudWatch’ın haberi bile olmayabilir.

Log grupları, uygulamalarınızdan ve sistem loglarından gelen verileri depolar. Alarmlar ise belirlediğiniz eşiklere göre tetiklenir ve SNS, Lambda gibi servislerle entegre çalışır.

IAM Rolü ve Temel Kurulum

Başlamadan önce EC2 instance’ınıza doğru IAM rolü atanmış olması lazım. Sık yapılan hata, bu adımı atlamak ve sonra CloudWatch Agent’ın neden çalışmadığını saatlerce araştırmak.

# IAM rolünü kontrol et
aws iam get-instance-profile --instance-profile-name CloudWatchAgentServerRole

# Rol yoksa oluştur
aws iam create-role 
  --role-name CloudWatchAgentServerRole 
  --assume-role-policy-document '{
    "Version": "2012-10-17",
    "Statement": [{
      "Effect": "Allow",
      "Principal": {"Service": "ec2.amazonaws.com"},
      "Action": "sts:AssumeRole"
    }]
  }'

# CloudWatchAgentServerPolicy politikasını role ekle
aws iam attach-role-policy 
  --role-name CloudWatchAgentServerRole 
  --policy-arn arn:aws:iam::aws:policies/CloudWatchAgentServerPolicy

Rolü oluşturduktan sonra EC2 console üzerinden instance’a atayın. Komut satırından yapmak istiyorsanız:

# Instance profile oluştur ve role ekle
aws iam create-instance-profile 
  --instance-profile-name CloudWatchAgentServerRole

aws iam add-role-to-instance-profile 
  --instance-profile-name CloudWatchAgentServerRole 
  --role-name CloudWatchAgentServerRole

# Çalışan instance'a ata
aws ec2 associate-iam-instance-profile 
  --instance-id i-1234567890abcdef0 
  --iam-instance-profile Name=CloudWatchAgentServerRole

CloudWatch Agent Kurulumu

Varsayılan EC2 metrikleri oldukça kısıtlı. Bellek, disk doluluk yüzdesi, aktif process sayısı gibi kritik bilgilere ulaşmak için CloudWatch Agent kurmak zorundasınız.

# Amazon Linux 2 / Amazon Linux 2023
sudo yum install -y amazon-cloudwatch-agent

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

# Agent durumunu kontrol et
sudo systemctl status amazon-cloudwatch-agent

Kurulum sonrası konfigürasyon wizard’ını çalıştırabilirsiniz ama ben doğrudan JSON config yazmayı tercih ediyorum, çünkü bu şekilde version control’e alabiliyor ve birden fazla sunucuya aynı yapılandırmayı uygulayabiliyorsunuz.

Agent Konfigürasyon Dosyası

Aşağıdaki config, production ortamı için makul bir başlangıç noktası. Belleği, disk kullanımını, swap’ı ve temel sistem metriklerini toplar:

{
  "agent": {
    "metrics_collection_interval": 60,
    "run_as_user": "cwagent"
  },
  "metrics": {
    "namespace": "CWAgent",
    "append_dimensions": {
      "AutoScalingGroupName": "${aws:AutoScalingGroupName}",
      "ImageId": "${aws:ImageId}",
      "InstanceId": "${aws:InstanceId}",
      "InstanceType": "${aws:InstanceType}"
    },
    "metrics_collected": {
      "mem": {
        "measurement": [
          "mem_used_percent",
          "mem_available",
          "mem_total"
        ],
        "metrics_collection_interval": 60
      },
      "disk": {
        "measurement": [
          "used_percent",
          "inodes_free"
        ],
        "metrics_collection_interval": 60,
        "resources": ["/", "/data", "/var/log"]
      },
      "swap": {
        "measurement": ["swap_used_percent"]
      },
      "cpu": {
        "measurement": [
          "cpu_usage_idle",
          "cpu_usage_iowait",
          "cpu_usage_user",
          "cpu_usage_system"
        ],
        "metrics_collection_interval": 30,
        "totalcpu": true
      },
      "netstat": {
        "measurement": [
          "tcp_established",
          "tcp_time_wait"
        ]
      },
      "processes": {
        "measurement": ["running", "sleeping", "dead"]
      }
    }
  },
  "logs": {
    "logs_collected": {
      "files": {
        "collect_list": [
          {
            "file_path": "/var/log/messages",
            "log_group_name": "/ec2/system/messages",
            "log_stream_name": "{instance_id}",
            "retention_in_days": 30
          },
          {
            "file_path": "/var/log/nginx/error.log",
            "log_group_name": "/ec2/nginx/error",
            "log_stream_name": "{instance_id}",
            "retention_in_days": 14
          },
          {
            "file_path": "/var/log/nginx/access.log",
            "log_group_name": "/ec2/nginx/access",
            "log_stream_name": "{instance_id}",
            "retention_in_days": 7
          }
        ]
      }
    }
  }
}

Bu dosyayı /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json olarak kaydedin ve agent’ı başlatın:

# Config dosyasını doğrula
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

# Agent durumunu kontrol et
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl 
  -a status

# Logları izle
sudo tail -f /opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log

Özel Metrik Gönderme

Bazen standart metrikler yetmez. Örneğin uygulama queue boyutu, aktif kullanıcı sayısı veya bir batch job’ın işlediği kayıt sayısı gibi business metriklerini de CloudWatch’a göndermek isteyebilirsiniz.

Gerçek dünya senaryosu: Bir e-ticaret platformu çalıştırıyorsunuz ve sipariş işleme queue’su dolup taşıyor. CPU ve bellek normal görünüyor ama sistem yavaş. Bu durumu ancak özel bir metrikle yakalayabilirsiniz.

#!/bin/bash
# /usr/local/bin/send-custom-metrics.sh

NAMESPACE="MyApp/Orders"
INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
REGION=$(curl -s http://169.254.169.254/latest/meta-data/placement/region)

# Queue boyutunu al (örnek: Redis'ten)
QUEUE_SIZE=$(redis-cli llen order_queue 2>/dev/null || echo 0)

# Aktif DB bağlantı sayısı
DB_CONNECTIONS=$(mysql -u monitor -ppassword 
  -e "SHOW STATUS LIKE 'Threads_connected';" 
  2>/dev/null | awk '/Threads_connected/ {print $2}' || echo 0)

# CloudWatch'a gönder
aws cloudwatch put-metric-data 
  --namespace "$NAMESPACE" 
  --region "$REGION" 
  --metric-data 
    MetricName=OrderQueueSize,Value=$QUEUE_SIZE,Unit=Count,Dimensions="[{Name=InstanceId,Value=$INSTANCE_ID}]" 
    MetricName=DatabaseConnections,Value=$DB_CONNECTIONS,Unit=Count,Dimensions="[{Name=InstanceId,Value=$INSTANCE_ID}]"

echo "$(date): Queue=$QUEUE_SIZE, DB Connections=$DB_CONNECTIONS"

Bu script’i cron’a ekleyin:

# Her dakika çalıştır
echo "* * * * * /usr/local/bin/send-custom-metrics.sh >> /var/log/custom-metrics.log 2>&1" | crontab -

Anlamlı Alarmlar Kurmak

Alarm kurarken en çok yapılan hata: tek bir veri noktasına göre alarm tetiklemek. CPU birkaç saniyeliğine %90’a çıksa bile bu her zaman sorun değildir. Datapoints to alarm parametresini doğru ayarlamak kritik.

Örnek senaryo: CPU 5 dakika boyunca %85’in üzerinde kalırsa gerçekten bir sorun var demektir.

# CPU yüksek kullanım alarmı
aws cloudwatch put-metric-alarm 
  --alarm-name "HighCPU-WebServer-01" 
  --alarm-description "CPU 5 dakikadan fazla %85 uzerinde" 
  --namespace "AWS/EC2" 
  --metric-name "CPUUtilization" 
  --dimensions Name=InstanceId,Value=i-1234567890abcdef0 
  --period 300 
  --evaluation-periods 3 
  --datapoints-to-alarm 3 
  --threshold 85 
  --comparison-operator GreaterThanThreshold 
  --statistic Average 
  --alarm-actions arn:aws:sns:eu-west-1:123456789:ops-alerts 
  --ok-actions arn:aws:sns:eu-west-1:123456789:ops-alerts 
  --treat-missing-data breaching

# Bellek yüksek kullanım alarmı (CloudWatch Agent gerekli)
aws cloudwatch put-metric-alarm 
  --alarm-name "HighMemory-WebServer-01" 
  --alarm-description "Bellek kullanimi %90 uzerinde" 
  --namespace "CWAgent" 
  --metric-name "mem_used_percent" 
  --dimensions Name=InstanceId,Value=i-1234567890abcdef0 
  --period 300 
  --evaluation-periods 2 
  --datapoints-to-alarm 2 
  --threshold 90 
  --comparison-operator GreaterThanThreshold 
  --statistic Average 
  --alarm-actions arn:aws:sns:eu-west-1:123456789:ops-alerts

# Disk doluluk alarmı - /var/log için ayrı alarm
aws cloudwatch put-metric-alarm 
  --alarm-name "DiskFull-VarLog-WebServer-01" 
  --alarm-description "/var/log diski %85 dolu" 
  --namespace "CWAgent" 
  --metric-name "disk_used_percent" 
  --dimensions Name=InstanceId,Value=i-1234567890abcdef0 Name=path,Value=/var/log Name=fstype,Value=xfs 
  --period 300 
  --evaluation-periods 1 
  --threshold 85 
  --comparison-operator GreaterThanThreshold 
  --statistic Maximum 
  --alarm-actions arn:aws:sns:eu-west-1:123456789:ops-alerts

Composite Alarmlar

Birden fazla alarma bağlı composite alarmlar, gürültüyü azaltmanın harika bir yolu. Hem CPU hem bellek yüksekse alarm ver, sadece birisi yüksekse sessiz kal mantığı:

aws cloudwatch put-composite-alarm 
  --alarm-name "CriticalState-WebServer-01" 
  --alarm-description "Hem CPU hem bellek kritik seviyede" 
  --alarm-rule "ALARM(HighCPU-WebServer-01) AND ALARM(HighMemory-WebServer-01)" 
  --alarm-actions arn:aws:sns:eu-west-1:123456789:critical-alerts

CloudWatch Logs Insights ile Log Analizi

Logları CloudWatch’a gönderdikten sonra Logs Insights ile hızlıca analiz edebilirsiniz. Bu, tek başına güçlü bir araç.

# AWS CLI ile Logs Insights sorgusu çalıştır
aws logs start-query 
  --log-group-name "/ec2/nginx/access" 
  --start-time $(date -d '1 hour ago' +%s) 
  --end-time $(date +%s) 
  --query-string 'fields @timestamp, @message
    | filter @message like /5[0-9][0-9]/
    | stats count() as error_count by bin(5m)
    | sort @timestamp desc'

# Sorgu sonuçlarını al (query-id önceki komuttan gelir)
aws logs get-query-results 
  --query-id "12345678-1234-1234-1234-123456789012"

Sık kullanılan bazı Logs Insights sorgu kalıpları:

# Son 1 saatteki HTTP 500 hataları
aws logs start-query 
  --log-group-name "/ec2/nginx/access" 
  --start-time $(date -d '1 hour ago' +%s) 
  --end-time $(date +%s) 
  --query-string 'fields @timestamp, @message
    | filter @message like /" 500 /
    | limit 100'

# En çok istek atan IP'leri bul
# Bu sorguyu CloudWatch console'dan çalıştırmanızı öneririm
# fields @message
# | parse @message '* - - [*] "* * *" * * "*" "*"' as ip, timestamp, method, path, protocol, status, bytes, referer, agent
# | stats count() as req_count by ip
# | sort req_count desc
# | limit 20

Metric Math ile Gelişmiş İzleme

CloudWatch Metric Math, birden fazla metriği birleştirerek yeni metrikler türetmenizi sağlar. Örneğin hata oranını hesaplamak için kullanabilirsiniz.

# Örnek: Otomatik ölçeklendirme grubunun sağlıklı instance oranını izle
aws cloudwatch put-metric-alarm 
  --alarm-name "ASG-HealthyInstanceRatio" 
  --alarm-description "Saglikli instance orani %70'in altina dustu" 
  --metrics '[
    {
      "Id": "healthy",
      "MetricStat": {
        "Metric": {
          "Namespace": "AWS/AutoScaling",
          "MetricName": "GroupInServiceInstances",
          "Dimensions": [{"Name": "AutoScalingGroupName", "Value": "web-asg"}]
        },
        "Period": 60,
        "Stat": "Average"
      }
    },
    {
      "Id": "total",
      "MetricStat": {
        "Metric": {
          "Namespace": "AWS/AutoScaling",
          "MetricName": "GroupTotalInstances",
          "Dimensions": [{"Name": "AutoScalingGroupName", "Value": "web-asg"}]
        },
        "Period": 60,
        "Stat": Average"
      }
    },
    {
      "Id": "ratio",
      "Expression": "healthy / total * 100",
      "Label": "HealthyInstanceRatio"
    }
  ]' 
  --comparison-operator LessThanThreshold 
  --threshold 70 
  --evaluation-periods 2 
  --alarm-actions arn:aws:sns:eu-west-1:123456789:ops-alerts

Dashboard Oluşturma

Alarm aldığınızda ne olduğunu hızlıca görmek için iyi bir dashboard şart. CLI ile dashboard oluşturmak mümkün ama widget’ları JSON olarak tanımlamak biraz zahmetli. Bence en iyi yaklaşım, konsol üzerinden temel bir dashboard oluşturup sonra bunu kod olarak export etmek:

# Mevcut dashboard'ı export et
aws cloudwatch get-dashboard 
  --dashboard-name "WebServer-Overview" 
  | jq -r '.DashboardBody' > dashboard-backup.json

# Dashboard oluştur veya güncelle
aws cloudwatch put-dashboard 
  --dashboard-name "WebServer-Overview" 
  --dashboard-body file://dashboard.json

Log Retention ve Maliyet Yönetimi

CloudWatch logları için retention süresi belirlemezseniz sonsuza kadar saklar ve fatura kabarmaya başlar. Her log grubu için retention politikası belirleyin:

#!/bin/bash
# Tum log gruplarinin retention'ini duzenle

# Retention olmayan log gruplarini bul
aws logs describe-log-groups 
  --query 'logGroups[?retentionInDays==`null`].logGroupName' 
  --output text | tr 't' 'n' | while read log_group; do
    echo "Retention ayarlaniyor: $log_group"
    
    # Kritik loglar icin 90 gun
    if [[ "$log_group" == *"/security/"* ]] || [[ "$log_group" == *"/audit/"* ]]; then
      aws logs put-retention-policy 
        --log-group-name "$log_group" 
        --retention-in-days 90
    # Uygulama loglari icin 30 gun
    elif [[ "$log_group" == *"/app/"* ]]; then
      aws logs put-retention-policy 
        --log-group-name "$log_group" 
        --retention-in-days 30
    # Diger her sey icin 14 gun
    else
      aws logs put-retention-policy 
        --log-group-name "$log_group" 
        --retention-in-days 14
    fi
done

echo "Tamamlandi."

Terraform ile CloudWatch Altyapısı

Production ortamında bütün bu kurulumu elle yapmak sürdürülebilir değil. Terraform ile tüm CloudWatch altyapısını kod olarak yönetmek hem tekrar edilebilirlik hem de versiyon kontrolü açısından çok daha sağlıklı:

# cloudwatch.tf - temel yapı
# Bu dosyayı doğrudan çalıştırmayın, Terraform projesi içinde kullanın

# SNS Topic
resource "aws_sns_topic" "ops_alerts" {
  name = "ops-alerts-${var.environment}"
}

resource "aws_sns_topic_subscription" "email" {
  topic_arn = aws_sns_topic.ops_alerts.arn
  protocol  = "email"
  endpoint  = var.alert_email
}

# CPU Alarm
resource "aws_cloudwatch_metric_alarm" "high_cpu" {
  alarm_name          = "HighCPU-${var.instance_name}"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = 3
  metric_name         = "CPUUtilization"
  namespace           = "AWS/EC2"
  period              = 300
  statistic           = "Average"
  threshold           = 85
  alarm_description   = "CPU kullanimi 15 dakika boyunca yuksek"
  datapoints_to_alarm = 3
  treat_missing_data  = "breaching"

  dimensions = {
    InstanceId = var.instance_id
  }

  alarm_actions = [aws_sns_topic.ops_alerts.arn]
  ok_actions    = [aws_sns_topic.ops_alerts.arn]
}

Yaygın Hatalar ve Çözümleri

Gerçek production deneyiminden öğrendiğim bazı önemli noktalar:

  • “Missing data” politikası: treat-missing-data parametresini breaching olarak ayarlayın. Eğer instance durur ve veri göndermezse, alarm otomatik tetiklensin. Varsayılan missing değeri sizi uyarmaz.
  • Alarm gürültüsü: evaluation-periods ve datapoints-to-alarm değerlerini dikkatli seçin. Sıkça yanlış alarm alıyorsanız ekip alarm yorgunluğuna girer ve gerçek alarmları da görmezden gelmeye başlar.
  • CloudWatch Agent’ın çökmesi: Agent’ı systemd ile başlatın ve restart politikası ekleyin. sudo systemctl enable amazon-cloudwatch-agent komutunu çalıştırmayı unutmayın.
  • Metrik boyutları: Aynı metriği farklı boyutlarla gönderiyorsanız alarmları da o boyutlarla eşleştirin. Yoksa hiç veri görmezsiniz.
  • IAM izinleri: Sadece CloudWatchAgentServerPolicy değil, SSM üzerinden konfig okuyacaksanız AmazonSSMManagedInstanceCore politikasını da eklemeniz gerekebilir.
  • Log encoding: Türkçe karakter içeren loglar bazen CloudWatch’a düzgün gelmiyor. Agent config’de encoding: utf-8 belirtmeyi unutmayın.
  • Zaman dilimi tutarsızlığı: Sunucu UTC’de çalışıyor, alarmlar UTC’de değerlendiriliyor ama siz GMT+3’te bakıyorsunuz. Dashboard’larda zaman dilimine dikkat edin.

Sonuç

CloudWatch ile sunucu izleme, “kuralım çalışsın” mantığıyla yaklaşıldığında iş görmüyor. Bellek metriğinin varsayılan olarak gelmemesi, retention politikası olmayan log grupları, tek veri noktasına bağlı alarmlar… Bunların hepsi sizi beklenmedik bir anda yakalayan tuzaklar.

Doğru yapılandırılmış bir CloudWatch kurulumu şunları sağlar: disk dolmadan önce uyarı alırsınız, bellek sızıntısı olan processleri yakalarsınız, log analizi için ayrı bir araç kurmanıza gerek kalmaz ve gece 3’te gereksiz alarm almadan uyursunuz.

Başlangıç için önerim şu: Önce CloudWatch Agent kurulumunu ve temel metrikleri halledin. Sonra CPU, bellek ve disk için anlamlı alarmlar ekleyin. Ardından uygulama loglarını CloudWatch’a taşıyın. Son adımda Terraform ile tüm bu yapıyı kod haline getirin ve yeni kuracağınız her sunucuya otomatik uygulayın.

CloudWatch mükemmel bir araç değil, özellikle çok fazla metrik ve log söz konusu olduğunda maliyetleri kontrol altında tutmak ayrı bir uğraş istiyor. Ama AWS ekosisteminde çalışıyorsanız, alternatiflerine kıyasla kurulum kolaylığı ve servislerle entegrasyon açısından sunduğu değer göz ardı edilemez. Önemli olan onu çalıştırmak değil, doğru çalıştırmak.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir