Otomatik Ölçeklendirme: HPA ile Yük Bazlı Yönetim

Kubernetes cluster’ınızda bir uygulama deploy ettiniz, her şey güzel çalışıyor. Sabah saatlerinde trafik düşük, pod’larınız boş boş bekliyor. Öğle arası veya kampanya dönemlerinde ise trafik patlar, pod’larınız çığlık atıyor. İşte tam bu noktada HPA devreye giriyor. Horizontal Pod Autoscaler, Kubernetes ekosisteminin en kullanışlı araçlarından biri ve doğru kurgulandığında hem maliyet optimizasyonu hem de uygulama kararlılığı açısından hayat kurtarıcı oluyor.

HPA Nedir ve Nasıl Çalışır?

HPA, Kubernetes’in yerleşik bir bileşenidir ve belirlediğiniz metriklere göre deployment, replicaset veya statefulset içindeki pod sayısını otomatik olarak artırıp azaltır. Temel mantık şu: Metrics Server aracılığıyla pod’larınızın CPU ve memory kullanımını izler, belirlediğiniz eşik değerlere göre replica sayısını ayarlar.

HPA’nın çalışma döngüsü yaklaşık 15 saniyede bir tetiklenir (kube-controller-manager’daki --horizontal-pod-autoscaler-sync-period değeriyle değiştirilebilir). Her döngüde şu adımlar işler:

  • Metrics Server’dan güncel metrik değerlerini çeker
  • Mevcut değeri hedef değerle karşılaştırır
  • Gerekli replica sayısını hesaplar
  • Deployment/ReplicaSet üzerinde scale işlemini uygular

Ölçeklendirme kararı şu formülle hesaplanır:

desiredReplicas = ceil[currentReplicas * (currentMetricValue / desiredMetricValue)]

Örneğin 3 pod’unuz var ve ortalama CPU kullanımı %80, hedefiniz %50 ise: ceil[3 * (80/50)] = ceil[4.8] = 5 pod’a çıkar.

Metrics Server Kurulumu

HPA çalışabilmesi için cluster’ınızda Metrics Server’ın kurulu olması şart. Bunu kontrol edelim:

kubectl top nodes
kubectl top pods

Eğer bu komutlar hata veriyorsa Metrics Server kurulu değildir. Kurulum için:

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

Bazı cluster kurulumlarında (özellikle self-hosted kubeadm kurulumlarında) TLS sertifika doğrulaması sorun çıkarır. Bu durumda deployment’a --kubelet-insecure-tls argümanı ekleyin:

kubectl patch deployment metrics-server -n kube-system --type='json' 
  -p='[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--kubelet-insecure-tls"}]'

Kurulum sonrası 1-2 dakika bekleyin, ardından kubectl top nodes ile test edin.

İlk HPA Tanımı: Basit CPU Bazlı Ölçeklendirme

Örnek bir web uygulaması üzerinden gidelim. Önce uygulamayı deploy edelim:

# web-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  namespace: production
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      containers:
      - name: web-app
        image: nginx:1.25
        resources:
          requests:
            cpu: "200m"
            memory: "256Mi"
          limits:
            cpu: "500m"
            memory: "512Mi"
        ports:
        - containerPort: 80

Önemli not: HPA’nın düzgün çalışması için container’larınızda mutlaka resources.requests tanımlı olmalı. Requests tanımlanmamışsa HPA yüzde bazlı hesaplama yapamaz ve çalışmaz.

Şimdi bu deployment için HPA tanımı oluşturalım:

# web-hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-app-hpa
  namespace: production
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-app
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80
kubectl apply -f web-deployment.yaml
kubectl apply -f web-hpa.yaml

# HPA durumunu kontrol et
kubectl get hpa -n production
kubectl describe hpa web-app-hpa -n production

Scale Up ve Scale Down Davranışını Kontrol Etmek

Varsayılan HPA davranışı çoğu zaman yeterli, ama üretim ortamlarında daha hassas kontrol gerekiyor. behavior bloğu ile bu davranışı özelleştirebilirsiniz:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-app-hpa
  namespace: production
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-app
  minReplicas: 2
  maxReplicas: 20
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 65
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 60
      policies:
      - type: Percent
        value: 100
        periodSeconds: 60
      - type: Pods
        value: 4
        periodSeconds: 60
      selectPolicy: Max
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
      - type: Percent
        value: 25
        periodSeconds: 120
      selectPolicy: Min

Bu konfigürasyonda:

  • stabilizationWindowSeconds (scaleUp): 60 saniye boyunca metrikleri gözlemler, anlık spike’lara karşı koruma sağlar
  • scaleUp policies: 60 saniyede ya mevcut pod sayısının %100’ü kadar ya da maksimum 4 pod ekle, hangisi büyükse onu uygula
  • stabilizationWindowSeconds (scaleDown): 300 saniye boyunca değerlerin düşük kaldığını doğrular, acele scale down yapmaz
  • scaleDown policies: 120 saniyede maksimum %25 oranında küçül

Scale down için stabilizationWindowSeconds‘ı uzun tutmak kritik. Özellikle database bağlantı sayısı veya session gibi state tutan uygulamalarda ani scale down ciddi sorunlara yol açar.

Gerçek Dünya Senaryosu: E-Ticaret Platformu

Bir e-ticaret platformu düşünün. Gece 02:00 ile sabah 08:00 arası trafik minimumda, öğle saatleri ve akşam 19:00-22:00 arası ise yoğun. Ayrıca kampanya dönemlerinde trafik 10 kata çıkabiliyor.

Bu senaryo için katmanlı bir HPA stratejisi kuralım:

# api-gateway-hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-gateway-hpa
  namespace: ecommerce
  annotations:
    description: "API Gateway - Agresif scale up, dikkatli scale down"
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-gateway
  minReplicas: 3
  maxReplicas: 50
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 60
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 75
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 30
      policies:
      - type: Percent
        value: 200
        periodSeconds: 30
      selectPolicy: Max
    scaleDown:
      stabilizationWindowSeconds: 600
      policies:
      - type: Percent
        value: 10
        periodSeconds: 300
      selectPolicy: Min

Bu konfigürasyonun mantığı şu: API gateway kritik bileşen, hız yaparken hızlı büyü (30 saniyede %200’e kadar), küçülürken yavaş küçül (10 dakika bekle, sonra %10 azalt).

Custom Metrics ile Gelişmiş HPA

CPU ve memory her zaman yeterli gösterge değildir. Bazı senaryolarda HTTP request rate, queue uzunluğu veya aktif bağlantı sayısı çok daha anlamlı metrikler olabilir. Bu noktada Prometheus + Prometheus Adapter ikilisi devreye giriyor.

Prometheus Adapter kurulu olduğunu varsayarak custom metric kullanan bir HPA örneği:

# worker-hpa-custom.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: worker-hpa
  namespace: production
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: queue-worker
  minReplicas: 1
  maxReplicas: 30
  metrics:
  - type: Pods
    pods:
      metric:
        name: http_requests_per_second
      target:
        type: AverageValue
        averageValue: "100"
  - type: External
    external:
      metric:
        name: rabbitmq_queue_messages_ready
        selector:
          matchLabels:
            queue: "order-processing"
      target:
        type: AverageValue
        averageValue: "50"

Bu örnekte:

  • Pods metriği: Her pod başına saniyede 100 HTTP isteği hedefle
  • External metrik: RabbitMQ’daki hazır mesaj sayısını izle, her 50 mesaj için 1 worker çalıştır

Queue bazlı ölçeklendirme özellikle asenkron işlem yapan mikroservislerde çok değerli. Kuyruk dolmaya başlayınca worker’ları artır, kuyruk boşalınca azalt.

HPA Sorun Giderme

Üretimde HPA ile karşılaşılan en yaygın problemleri ve çözümlerini inceleyelim.

Problem 1: HPA “unknown” durum gösteriyor

kubectl describe hpa web-app-hpa -n production
# Çıktıda: "unable to fetch metrics from resource metrics API"

Bu genellikle Metrics Server sorunu veya pod’larda resources.requests eksikliğinden kaynaklanır:

# Metrics Server pod durumunu kontrol et
kubectl get pods -n kube-system | grep metrics-server
kubectl logs -n kube-system deployment/metrics-server

# Pod'larda requests tanımlı mı?
kubectl get deployment web-app -n production -o jsonpath='{.spec.template.spec.containers[0].resources}'

Problem 2: HPA scale etmiyor, stuck durumda

# HPA event'lerini incele
kubectl describe hpa web-app-hpa -n production | grep -A 20 Events

# Mevcut metrik değerlerini gör
kubectl get hpa web-app-hpa -n production -o yaml | grep -A 10 currentMetrics

Problem 3: Scale down çok agresif oluyor

# Mevcut HPA konfigürasyonunu patch ile güncelle
kubectl patch hpa web-app-hpa -n production --type='merge' -p='
{
  "spec": {
    "behavior": {
      "scaleDown": {
        "stabilizationWindowSeconds": 600,
        "policies": [
          {
            "type": "Percent",
            "value": 20,
            "periodSeconds": 300
          }
        ]
      }
    }
  }
}'

HPA ile Birlikte Kullanılması Gereken Yapılar

HPA tek başına yeterli değil, şu bileşenlerle birlikte düşünülmeli:

PodDisruptionBudget: Scale down sırasında minimum pod sayısını garanti altına alır.

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: web-app-pdb
  namespace: production
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: web-app

Resource Quota: Namespace bazında HPA’nın ne kadar büyüyebileceğini sınırlar, aşırı kaynak tüketimini engeller.

apiVersion: v1
kind: ResourceQuota
metadata:
  name: production-quota
  namespace: production
spec:
  hard:
    requests.cpu: "20"
    requests.memory: 40Gi
    limits.cpu: "40"
    limits.memory: 80Gi
    count/pods: "100"

readinessProbe: Scale up sırasında yeni pod’ların trafiğe hazır olmadan yük almasını engeller. Bu olmadan HPA anlamsız.

readinessProbe:
  httpGet:
    path: /health
    port: 8080
  initialDelaySeconds: 10
  periodSeconds: 5
  failureThreshold: 3

HPA Kararlarını Gözlemlemek

Üretimde HPA’nın ne yaptığını anlık takip etmek için birkaç kullanışlı komut:

# HPA durumunu sürekli izle
watch -n 5 kubectl get hpa -n production

# HPA geçmişini ve kararlarını detaylı gör
kubectl describe hpa web-app-hpa -n production

# Tüm namespace'lerdeki HPA'ları listele
kubectl get hpa --all-namespaces

# Belirli deployment'ın replica geçmişini loglardan çek
kubectl get events -n production --field-selector reason=SuccessfulRescale --sort-by='.lastTimestamp'

# Pod kaynak kullanımını izle
kubectl top pods -n production --sort-by=cpu

Prometheus ve Grafana kullanıyorsanız, kube_horizontalpodautoscaler_spec_max_replicas, kube_horizontalpodautoscaler_status_current_replicas ve kube_horizontalpodautoscaler_status_desired_replicas metriklerini dashboard’a ekleyin. Bu üç metrik yan yana görüldüğünde HPA’nın davranışını anlamak çok kolaylaşır.

Sık Yapılan Hatalar

Sahadaki deneyimlerden derlediğim en kritik hatalar şunlar:

  • minReplicas’ı 1’e çekmek: Ölçeklendirme sırasında kısa süreliğine sıfır pod kalabilir. Production’da minReplicas en az 2 olmalı, kritik servisler için 3.
  • requests tanımlamadan HPA kurmak: HPA çalışıyor gibi görünür ama “unknown” döner, hiçbir şey ölçeklenmez.
  • limits’i requests’in çok üzerine çıkarmak: CPU throttling yaşanır, pod’lar gerçekte kullanabildiğinden az kaynak gözükür, HPA yanlış kararlar verir. limits/requests oranını 2-3x’i geçmeyin.
  • Hem HPA hem manuel replica ayarlamak: kubectl scale deployment web-app --replicas=5 dediğinizde HPA bir sonraki döngüde bunu override eder. HPA açıkken manuel müdahale yapmayın.
  • scaleDown’ı çok hızlı bırakmak: Varsayılan stabilizationWindowSeconds 300 saniye, bu değeri küçültmek genellikle iyi fikir değil.
  • Tek metrikle sınırlı kalmak: Sadece CPU izlemek yetmez. Memory leak olan bir uygulama CPU’su düşük görünür ama memory patlar. En az CPU + memory ikilisini kullanın.

KEDA ile HPA’yı Güçlendirmek

Kubernetes Event-Driven Autoscaling (KEDA), HPA’nın yeteneklerini genişleten bir araç. Özellikle event kaynaklı iş yükleri için HPA’nın yetersiz kaldığı noktalarda KEDA devreye giriyor. Kafka topic’leri, Azure Service Bus, AWS SQS gibi 50’den fazla trigger kaynağını destekliyor ve sıfıra scale down yapabiliyor (idle pod’ları tamamen kaldırabilir).

# KEDA kurulumu
helm repo add kedacore https://kedacore.github.io/charts
helm repo update
helm install keda kedacore/keda --namespace keda --create-namespace

KEDA kurulduğunda standart HPA objelerini arka planda otomatik oluşturur, mevcut altyapınızla uyumlu çalışır. Hem HPA hem KEDA kullanıyorsanız aynı deployment için her ikisini birden tanımlamayın, çakışma yaşanır.

Sonuç

HPA, Kubernetes’in en değerli özelliklerinden biri ama doğru kurgulanmadığında hem pahalıya patlar hem de uygulamayı zora sokabilir. Temel prensipleri özetleyecek olursam:

Her şeyden önce resources.requests doğru ayarlanmadan HPA anlamsız. Bu tek başına en önemli nokta. İkinci olarak scale up agresif, scale down temkinli olmalı. Ani trafik artışlarına hızlı tepki ver, düşüşlerde acele etme. Üçüncü olarak stabilizationWindowSeconds değerlerini uygulamanızın karakterine göre ayarlayın, varsayılanları her zaman uygun olmaz.

Production’a almadan önce mutlaka yük testi yapın. kubectl run load-generator ile basit bir yük testi kurabilir, HPA’nın nasıl tepki verdiğini gözlemleyebilirsiniz. Alarm kurmayı da ihmal etmeyin: HPA maxReplicas’a ulaştığında (yani daha fazla scale edemediğinde) uyarı almanız şart.

Son olarak HPA’yı Cluster Autoscaler ile birlikte düşünün. HPA pod sayısını artırır ama node’larınız doluysa bu pod’lar Pending durumda kalır. Cluster Autoscaler ise node ekleyip çıkarır. Bu iki bileşen birlikte doğru kurgülandığında gerçek anlamda elastik, maliyet etkin bir altyapı elde edersiniz.

Yorum yapın