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-dataparametresinibreachingolarak ayarlayın. Eğer instance durur ve veri göndermezse, alarm otomatik tetiklensin. Varsayılanmissingdeğeri sizi uyarmaz.
- Alarm gürültüsü:
evaluation-periodsvedatapoints-to-alarmdeğ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-agentkomutunu ç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
CloudWatchAgentServerPolicydeğil, SSM üzerinden konfig okuyacaksanızAmazonSSMManagedInstanceCorepolitikası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-8belirtmeyi 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.
