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.

Benzer Konular

Bir yanıt yazın

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