Prometheus ile Kubernetes Cluster Monitoring Kurulumu
Kubernetes cluster’ını ayağa kaldırdın, her şey çalışıyor, deployment’lar hazır, servisler ayakta. Peki ya içeride neler döndüğünü gerçekten biliyor musun? Hangi pod ne kadar CPU yiyor, hangi node bellek sınırına yaklaşıyor, bir servis sessizce ölüyor mu? İşte bu soruların cevabını bulmak için Prometheus, Kubernetes dünyasında fiili standart haline gelmiş durumda. Bu yazıda sıfırdan başlayarak production-ready bir Kubernetes monitoring altyapısını nasıl kuracağını, yapılandıracağını ve anlamlı alertler yazacağını adım adım göstereceğim.
Prometheus Neden Kubernetes İçin İdeal?
Prometheus’un Kubernetes ile bu kadar iyi çalışmasının temel sebebi, her ikisinin de aynı felsefeden beslenmesi. Kubernetes dinamik ve kısa ömürlü pod’larla çalışır, Prometheus ise bu dinamizmi kucaklayan service discovery mekanizmasına sahiptir. Pod’lar gelip geçer, IP’leri değişir, ama Prometheus Kubernetes API’sini sürekli dinleyerek neyi scrape edeceğini otomatik olarak günceller.
Buna ek olarak:
- Pull-based model: Prometheus metrikleri kendisi çeker, bu sayede her servise bir push agent kurman gerekmez
- PromQL: Güçlü sorgulama dili sayesinde karmaşık hesaplamalar yapabilirsin
- Kubernetes-native entegrasyon: kube-state-metrics ve node-exporter ile cluster’ın her katmanını görebilirsin
- Ekosistem: Grafana, Alertmanager, PagerDuty entegrasyonları hazır gelir
Kurulum Öncesi Hazırlık
Öncelikle elimizdekileri netleştirelim. Bu yazıda şunları kuracağız:
- Prometheus server
- Alertmanager
- kube-state-metrics (Kubernetes obje metrikleri için)
- node-exporter (fiziksel/sanal node metrikleri için)
- Grafana (görselleştirme)
Helm kullanacağız çünkü hayatı kolaylaştırıyor ve kube-prometheus-stack chart’ı tüm bu bileşenleri tek seferde kuruyor. Manuel kurulum yapmak isteyenler için de kritik noktalara değineceğim.
Gereksinimler:
- Çalışan bir Kubernetes cluster (v1.21+)
- kubectl yapılandırılmış ve cluster’a bağlı
- Helm v3 kurulu
- En az 2 CPU ve 4GB RAM’e sahip node’lar
Namespace oluşturarak başlayalım:
kubectl create namespace monitoring
kubectl get namespaces | grep monitoring
Helm ile kube-prometheus-stack Kurulumu
Prometheus topluluğunun hazırladığı kube-prometheus-stack chart’ı, yukarıda saydığım tüm bileşenleri içeriyor ve production ortamlar için gerçekten iyi varsayılan değerlerle geliyor.
# Helm repo ekle
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
# Mevcut chart versiyonlarını listele
helm search repo prometheus-community/kube-prometheus-stack --versions | head -5
Şimdi özelleştirilmiş bir values dosyası oluşturalım. Varsayılan kurulum çoğu zaman yeterli olsa da production’da storage, retention ve resource limit’leri mutlaka ayarlamak gerekiyor:
# prometheus-values.yaml
prometheus:
prometheusSpec:
retention: 30d
retentionSize: "50GB"
storageSpec:
volumeClaimTemplate:
spec:
storageClassName: standard
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 50Gi
resources:
requests:
memory: "2Gi"
cpu: "500m"
limits:
memory: "4Gi"
cpu: "2000m"
# Tüm namespace'leri izle
serviceMonitorSelectorNilUsesHelmValues: false
podMonitorSelectorNilUsesHelmValues: false
alertmanager:
alertmanagerSpec:
storage:
volumeClaimTemplate:
spec:
storageClassName: standard
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
grafana:
adminPassword: "GucluBirSifre123!"
persistence:
enabled: true
storageClassName: standard
size: 10Gi
service:
type: ClusterIP
nodeExporter:
enabled: true
kubeStateMetrics:
enabled: true
# Kurulumu başlat
helm install prometheus-stack prometheus-community/kube-prometheus-stack
--namespace monitoring
--values prometheus-values.yaml
--wait
# Pod'ların ayağa kalkmasını bekle
kubectl get pods -n monitoring -w
Birkaç dakika sonra şöyle bir çıktı görmen gerekiyor:
kubectl get pods -n monitoring
# Beklenen çıktı:
# alertmanager-prometheus-stack-alertmanager-0 2/2 Running 0
# prometheus-stack-grafana-xxxx 3/3 Running 0
# prometheus-stack-kube-state-metrics-xxxx 1/1 Running 0
# prometheus-stack-operator-xxxx 1/1 Running 0
# prometheus-stack-prometheus-node-exporter-xxxx 1/1 Running 0
# prometheus-prometheus-stack-prometheus-0 2/2 Running 0
Prometheus’a Erişim
Production’da genellikle Ingress kullanırsın ama test için port-forward yeterli:
# Prometheus UI
kubectl port-forward -n monitoring svc/prometheus-stack-kube-prometheus-prometheus 9090:9090 &
# Grafana UI
kubectl port-forward -n monitoring svc/prometheus-stack-grafana 3000:80 &
# Alertmanager UI
kubectl port-forward -n monitoring svc/prometheus-stack-alertmanager 9093:9093 &
Tarayıcında http://localhost:9090 açtığında Prometheus UI’ı göreceksin. Status > Targets menüsünden Prometheus’un neyi scrape ettiğini görebilirsin. Eğer her şey doğru kurulmuşsa onlarca target UP durumunda görünmeli.
Temel PromQL Sorguları
Prometheus’u kurmak güzel ama asıl değer doğru soruları sorabilmekten geliyor. İşte günlük hayatta kullandığım temel sorgular:
Node bazlı CPU kullanımı:
100 - (avg by (instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
Pod’ların memory kullanımı (MB cinsinden):
container_memory_working_set_bytes{container!="", namespace="production"} / 1024 / 1024
Namespace başına toplam CPU request:
sum by (namespace) (kube_pod_container_resource_requests{resource="cpu", unit="core"})
Restart eden pod’lar (son 1 saat):
increase(kube_pod_container_status_restarts_total[1h]) > 0
Node disk doluluk oranı:
100 - ((node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100)
ServiceMonitor ile Özel Uygulama Metrikleri
Prometheus Operator’ün en güzel yanı ServiceMonitor ve PodMonitor CRD’leri. Kendi uygulamanı Prometheus’a tanıtmak için artık Prometheus config dosyasını elle düzenlemene gerek yok.
Diyelim ki /metrics endpoint’i açan bir uygulamaan var. Önce servisine label ekle:
# uygulama-service.yaml
apiVersion: v1
kind: Service
metadata:
name: benim-uygulamam
namespace: production
labels:
app: benim-uygulamam
monitoring: "true"
spec:
selector:
app: benim-uygulamam
ports:
- name: http-metrics
port: 8080
targetPort: 8080
Ardından ServiceMonitor oluştur:
# servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: benim-uygulamam-monitor
namespace: monitoring
labels:
release: prometheus-stack
spec:
namespaceSelector:
matchNames:
- production
selector:
matchLabels:
monitoring: "true"
endpoints:
- port: http-metrics
interval: 30s
path: /metrics
scrapeTimeout: 10s
kubectl apply -f uygulama-service.yaml
kubectl apply -f servicemonitor.yaml
# Birkaç dakika sonra Prometheus UI'da Status > Targets'ta görünmeli
kubectl get servicemonitor -n monitoring
Alerting Kuralları Yazma
İzleme yapmak güzel, ama uyumadığın gecelerde seni uyandıracak alertler daha değerli. İşte gerçek dünyada kullandığım alertler:
# custom-alerts.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: custom-cluster-alerts
namespace: monitoring
labels:
release: prometheus-stack
spec:
groups:
- name: node.rules
interval: 30s
rules:
- alert: NodeHighCPU
expr: 100 - (avg by (instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 85
for: 5m
labels:
severity: warning
annotations:
summary: "Node CPU kullanımı yüksek"
description: "{{ $labels.instance }} node'unda CPU kullanımı {{ $value }}% seviyesinde, 5 dakikadır."
- alert: NodeMemoryPressure
expr: (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100 < 10
for: 2m
labels:
severity: critical
annotations:
summary: "Node bellek kritik seviyede"
description: "{{ $labels.instance }} üzerinde kullanılabilir bellek %{{ $value }} seviyesine düştü."
- alert: NodeDiskAlmostFull
expr: 100 - ((node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100) > 80
for: 10m
labels:
severity: warning
annotations:
summary: "Disk doluluk uyarısı"
description: "{{ $labels.instance }} üzerinde {{ $labels.mountpoint }} bölümü %{{ $value }} dolu."
- name: pod.rules
rules:
- alert: PodCrashLooping
expr: increase(kube_pod_container_status_restarts_total[15m]) > 3
for: 5m
labels:
severity: critical
annotations:
summary: "Pod crash loop döngüsünde"
description: "{{ $labels.namespace }}/{{ $labels.pod }} pod'u son 15 dakikada {{ $value }} kez restart etti."
- alert: PodNotReady
expr: kube_pod_status_ready{condition="true"} == 0
for: 10m
labels:
severity: warning
annotations:
summary: "Pod hazır durumda değil"
description: "{{ $labels.namespace }}/{{ $labels.pod }} 10 dakikadır Ready durumuna geçemedi."
- alert: DeploymentReplicasMismatch
expr: kube_deployment_spec_replicas != kube_deployment_status_available_replicas
for: 5m
labels:
severity: warning
annotations:
summary: "Deployment replica sayısı uyuşmazlığı"
description: "{{ $labels.namespace }}/{{ $labels.deployment }} deployment'ında istenilen ve mevcut replica sayısı eşleşmiyor."
kubectl apply -f custom-alerts.yaml
# Alert kurallarının yüklendiğini doğrula
kubectl get prometheusrule -n monitoring
Prometheus UI’da Alerts sekmesine gittiğinde bu alertleri görebilirsin. Firing, pending ve inactive durumlarını buradan takip edebilirsin.
Alertmanager Yapılandırması
Alert yazmak yetmez, bu alertlerin sana ulaşması gerekiyor. Alertmanager için Slack entegrasyonu en yaygın kullanılan yöntem:
# alertmanager-config.yaml
apiVersion: monitoring.coreos.com/v1alpha1
kind: AlertmanagerConfig
metadata:
name: slack-config
namespace: monitoring
spec:
route:
receiver: 'slack-notifications'
groupBy: ['alertname', 'namespace']
groupWait: 30s
groupInterval: 5m
repeatInterval: 12h
routes:
- matchers:
- name: severity
value: critical
receiver: 'slack-critical'
repeatInterval: 1h
receivers:
- name: 'slack-notifications'
slackConfigs:
- apiURL:
name: slack-webhook-secret
key: url
channel: '#k8s-alerts'
sendResolved: true
title: '[{{ .Status | toUpper }}] {{ .GroupLabels.alertname }}'
text: >-
{{ range .Alerts }}
*Alert:* {{ .Annotations.summary }}
*Açıklama:* {{ .Annotations.description }}
*Severity:* {{ .Labels.severity }}
{{ end }}
- name: 'slack-critical'
slackConfigs:
- apiURL:
name: slack-webhook-secret
key: url
channel: '#k8s-critical'
sendResolved: true
# Slack webhook URL'ini secret olarak sakla
kubectl create secret generic slack-webhook-secret
--from-literal=url='https://hooks.slack.com/services/XXXX/YYYY/ZZZZ'
-n monitoring
kubectl apply -f alertmanager-config.yaml
Grafana Dashboard’ları
Grafana kurulumdan sonra http://localhost:3000 adresinde seni karşılar. Kullanıcı adı admin, şifre ise values.yaml’da belirttiğin şey. kube-prometheus-stack, otomatik olarak bazı temel dashboard’ları yükler ama birkaç tanesi olmazsa olmaz:
Dashboard ID’leri (Import > Dashboard ID ile ekleyebilirsin):
- 315: Node Exporter Full (node metrikleri için en kapsamlı dashboard)
- 6417: Kubernetes Cluster Overview
- 13770: 1 Kubernetes All-in-one Cluster Monitoring KR
- 8685: Kubernetes Deployment Statefulset Daemonset
Dashboard import etmek için Grafana’da sol menüden + ikonuna tıkla, Import seç ve yukarıdaki ID’lerden birini yaz. Prometheus datasource olarak Prometheus seçtiğinde dashboard hemen doluyor.
Gerçek Dünya Senaryosu: Memory Leak Tespiti
Bir production senaryosu üzerinden gidelim. Diyelim ki bir Java uygulamanı deploy ettin ve zamanla yavaşladığını fark ediyorsun. Prometheus’ta şu sorguyu çalıştır:
# Son 6 saatte container memory kullanımının trendi
container_memory_working_set_bytes{
container="java-app",
namespace="production"
}
Eğer bu sorgu düz bir çizgi yerine sürekli yukarı giden bir trend gösteriyorsa memory leak var demektir. Bunu daha anlamlı hale getirmek için:
# Memory kullanımının memory limit'e oranı
(container_memory_working_set_bytes{container="java-app"} /
container_spec_memory_limit_bytes{container="java-app"}) * 100
Bu oran %80’i geçmeye başlıyorsa OOMKilled olma riski var. Bunu bir alert ile de izleyebilirsin:
- alert: ContainerMemoryLeakSuspected
expr: |
(
container_memory_working_set_bytes{container!=""}
/ container_spec_memory_limit_bytes{container!=""}
) * 100 > 80
for: 15m
labels:
severity: warning
annotations:
summary: "Olası memory leak tespit edildi"
description: "{{ $labels.namespace }}/{{ $labels.container }} container'ı limit'inin %{{ $value }}'ini kullanıyor."
Performans Optimizasyonu
Cluster büyüdükçe Prometheus’un kendisi de kaynak tüketmeye başlar. Birkaç kritik optimizasyon:
Scrape interval ayarları: Her metriği 15 saniyede bir çekmeye gerek yok. Kritik olmayan servisler için 60 saniye yeterli.
Recording rules kullanımı: Sık çalıştırılan karmaşık sorguları önceden hesaplatıp saklayabilirsin. Bu hem Grafana dashboard performansını artırır hem de Prometheus üzerindeki yükü azaltır:
- name: node.recording.rules
rules:
- record: instance:node_cpu_utilisation:rate5m
expr: |
100 - (avg by (instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
- record: namespace:container_memory_usage_bytes:sum
expr: |
sum by (namespace) (container_memory_working_set_bytes{container!=""})
Label cardinality: Prometheus’ta en büyük performans sorunlarından biri yüksek cardinality. Uygulama metriklerinde user_id gibi binlerce farklı değer alabilen label’lar kullanma, Prometheus’u felç eder.
Thanos ile Uzun Vadeli Saklama
Prometheus verileri varsayılan olarak local disk’te tutar ve cluster yeniden başlarsa veriler gider. Production’da Thanos veya Cortex kullanarak uzun vadeli saklama sağlayabilirsin. Hızlı başlangıç için values.yaml’a şunu ekleyebilirsin:
prometheus:
prometheusSpec:
thanos:
image: quay.io/thanos/thanos:v0.32.0
objectStorageConfig:
name: thanos-objstore-config
key: objstore.yml
S3-compatible bir storage (MinIO, AWS S3, GCS) için secret oluştur:
cat > /tmp/objstore.yml << EOF
type: S3
config:
bucket: prometheus-long-term
endpoint: s3.amazonaws.com
region: eu-west-1
access_key: AKIAIOSFODNN7EXAMPLE
secret_key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
EOF
kubectl create secret generic thanos-objstore-config
--from-file=objstore.yml=/tmp/objstore.yml
-n monitoring
Monitoring Stack’ini Güncel Tutmak
Prometheus ekosistemi hızlı gelişiyor. Helm ile güncelleme oldukça basit:
# Mevcut release bilgilerini gör
helm list -n monitoring
# Chart'ı güncelle
helm repo update
# Önce ne değiştiğine bak
helm diff upgrade prometheus-stack prometheus-community/kube-prometheus-stack
--namespace monitoring
--values prometheus-values.yaml
# Güvenli görünüyorsa uygula
helm upgrade prometheus-stack prometheus-community/kube-prometheus-stack
--namespace monitoring
--values prometheus-values.yaml
--wait
Güncelleme öncesinde mutlaka helm diff çalıştır. Bazen yeni versiyonlarda CRD değişiklikleri oluyor ve bunları önceden bilmek çok önemli.
Sonuç
Prometheus ve kube-prometheus-stack ile Kubernetes cluster’ında gerçek anlamda görünürlük elde edebiliyorsun. Metrik toplamak, alert yazmak, dashboard kurmak artık saatler yerine dakikalar alıyor. Ama asıl önemli olan bu araçları kurmak değil, doğru soruları sormak.
Başlarken şu üç prensibe sadık kal:
- Az ve öz alert: Her şeye alert yazarsan hiçbir şeye bakmazsın. Sadece aksiyon gerektiren durumlar için alert yaz.
- Cardinality disiplini: Metrik label’larını dikkatli seç, aksi takdirde Prometheus’un kendisi sorun çıkarmaya başlar.
- Recording rules yatırımı: Sık kullandığın sorgular için recording rule yazmak hem performans kazandırır hem de dashboard’larını hızlandırır.
Bir sonraki adım olarak Grafana’da SLO (Service Level Objective) dashboard’ları kurmayı ve Prometheus Operator’ün ProbeMonitor CRD’si ile blackbox monitoring eklemeyi düşünebilirsin. Cluster’ının içinden ne döndüğünü bilmek, gece yarısı uyanık beklemek yerine rahat uyumayı sağlar. Ve bu, bir sysadmin için paha biçilmez.
