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=5dediğ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
stabilizationWindowSeconds300 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.