Перейти к содержимому

Autoscaling в Kubernetes: HPA, VPA, KEDA, Karpenter

Зачем знать: Middle 2 Go-разработчик должен уметь не только написать сервис, но и сделать его адаптивным к нагрузке. В 2026 году autoscaling — это must-have для любого production-сервиса: спайки трафика (e-commerce sales), event-driven workloads (Kafka consumers), cost optimization (scale-to-zero ночью). Без понимания HPA/VPA/KEDA сервис либо упадёт под нагрузкой, либо будет жечь деньги на простаивающие pods. Особенно важно знать Go-specific gotchas: cold start, GOMAXPROCS адаптация, GOMEMLIMIT при scale up.

  1. Концепция: HPA, VPA, Cluster Autoscaler, KEDA
  2. Production-практики: метрики, behavior, scale-to-zero
  3. Gotchas: HPA flapping, VPA с HPA, cold start
  4. Real cases: Black Friday, Kafka consumer, ML inference
  5. Вопросы для собеседования
  6. Practice
  7. Источники

Kubernetes имеет три уровня autoscaling:

  1. HPA (Horizontal Pod Autoscaler) — увеличивает/уменьшает количество pod replicas.
  2. VPA (Vertical Pod Autoscaler) — изменяет requests/limits на existing pods.
  3. Cluster Autoscaler / Karpenter — добавляет/удаляет nodes в кластере.
[Cluster Autoscaler] → adds/removes nodes
|
| nodes capacity
v
[HPA] → adds/removes pod replicas
|
| resource demand
v
[VPA] → adjusts pod requests/limits
|
| resource utilization
v
[Pod Workload]

HPA периодически (default 15s) опрашивает metrics, считает желаемое число replicas, scale’ит Deployment/StatefulSet/ReplicaSet.

Формула (simplified):

desiredReplicas = ceil[currentReplicas × (currentMetric / targetMetric)]

Пример:

  • 5 replicas, CPU utilization 80%, target 50%.
  • desired = ceil(5 × 80/50) = ceil(8) = 8 replicas.
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api
minReplicas: 3
maxReplicas: 50
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
scaleUp:
stabilizationWindowSeconds: 30
policies:
- type: Percent
value: 100
periodSeconds: 30
- type: Pods
value: 5
periodSeconds: 30
selectPolicy: Max
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 25
periodSeconds: 60

Resource metrics — built-in (CPU, memory). Через metrics-server.

Custom metrics — application metrics (через Prometheus Adapter).

  • Queue length, RPS per pod, response time.
metrics:
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: 100

External metrics — from outside cluster (cloud SQS queue, etc.).

Object metrics — non-pod target (Ingress).

Stabilization window — задержка перед применением scale решения (анти-flapping).

  • scaleUp.stabilizationWindowSeconds: 0 — scale up мгновенно.
  • scaleDown.stabilizationWindowSeconds: 300 — wait 5 мин перед scale down.

Policies — ограничения скорости:

  • Percent: 100 — удвоить за период.
  • Pods: 5 — добавить максимум 5.
  • selectPolicy: Max — берёт самый агрессивный.

Стандарт для production:

  • Scale up быстро (window 30s, +100% или +5 pods).
  • Scale down медленно (window 5-10 мин, -25%).

Это потому что cost быстрого scale-down (cold start при возврате нагрузки) больше cost держать лишние pods 10 мин.

VPA анализирует историю использования и рекомендует/применяет requests/limits.

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: api-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: api
updatePolicy:
updateMode: Auto # или Off, Initial, Recreate
resourcePolicy:
containerPolicies:
- containerName: '*'
minAllowed:
cpu: 100m
memory: 128Mi
maxAllowed:
cpu: 2
memory: 2Gi

Update modes:

  • Off — только рекомендации (через kubectl describe vpa). Безопасно.
  • Initial — применяет только при создании нового pod’a (не recreate existing).
  • Recreate — убивает pod, новый создаётся с новыми requests.
  • Auto = Recreate (deprecated название).
  • InPlace (k8s 1.27+ alpha) — изменяет без рестарта.

Use cases:

  • Right-sizing (находить правильные requests из истории).
  • Slowly changing workloads (где HPA не подходит).

Конфликт: VPA меняет CPU request, HPA scales по CPU utilization → infinite loop.

Правило:

  • VPA + HPA на разных метриках — OK (VPA для memory, HPA по custom metric).
  • VPA на CPU + HPA на CPU — НЕЛЬЗЯ.

Альтернатива: VPA в Off mode для рекомендаций, manual apply, HPA для scaling.

KEDA (Kubernetes Event-Driven Autoscaling) — CNCF проект, расширяет HPA для event-driven scaling.

Scalers (60+ типов):

  • Kafka lag (количество unread сообщений).
  • RabbitMQ queue length.
  • AWS SQS queue depth.
  • Redis list length.
  • Prometheus queries.
  • Cron (scale 9-18 на работе).
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: kafka-consumer-scaler
spec:
scaleTargetRef:
name: consumer
minReplicaCount: 0 # SCALE TO ZERO!
maxReplicaCount: 100
pollingInterval: 30
cooldownPeriod: 300
triggers:
- type: kafka
metadata:
bootstrapServers: kafka:9092
consumerGroup: orders
topic: orders
lagThreshold: "100"

Преимущество KEDA:

  • Scale-to-zero — нет pods при отсутствии трафика.
  • Поддержка десятков event sources.
  • Под HPA капотом — совместимость.

Cluster Autoscaler (CA) — классика, работает на основе node groups (Auto Scaling Groups в AWS).

  • Когда есть pending pods (не помещаются на nodes) → request новый node.
  • Когда node underutilized → drain и remove.
  • Работает медленнее (manage ASG’ами cloud провайдера).

Karpenter (AWS, 2021+) — next-gen autoscaler.

  • Без node groups, провизионит nodes напрямую.
  • Выбирает оптимальный тип instance под pending workload.
  • Быстрее (30-60 сек vs 2-5 мин у CA).
  • Поддерживает spot instances с graceful fallback.
  • В 2024 стало доступно для GCP, Azure.

Production стандарт в AWS 2026: Karpenter.

Knative Serving — serverless platform поверх k8s.

  • Auto scale-to-zero (при отсутствии RPS).
  • Cold start при первом запросе.
  • Концепция Revisions (immutable снимок версии).

Использует activator для буферизации запросов во время cold start.

AWS Predictive Scaling (для ASG) использует ML для prediction нагрузки.

  • Анализирует historical patterns (daily, weekly).
  • Заранее scales up за 30 мин до пика.
  • Снижает cold start impact.

В k8s mire это можно реализовать через:

  • CronHPA — schedule-based HPA.
  • KEDA с cron trigger.
  • Custom controller с ML моделью.

По важности:

  1. Saturation метрики (Golden Signals): queue length, semaphore wait time, threadpool utilization.
  2. Latency: P95 response time.
  3. Throughput: RPS per pod.
  4. CPU: только если CPU-bound сервис.
  5. Memory: редко (memory обычно не scale fast).

CPU как primary metric — плохо для I/O-heavy сервисов. Они wait на DB, CPU низкий, но queue растёт.

Лучшая практика:

  • Custom metric: request_queue_length или inflight_requests.
  • Target: запрос-на-pod, не utilization.
metrics:
- type: Pods
pods:
metric:
name: inflight_requests
target:
type: AverageValue
averageValue: 50 # 50 inflight per pod

Для custom metrics нужен Prometheus Adapter — exposing Prometheus queries как k8s metrics API.

rules:
- seriesQuery: 'http_requests_total{namespace!="",pod!=""}'
resources:
overrides:
namespace: { resource: "namespace" }
pod: { resource: "pod" }
name:
matches: "^(.*)_total"
as: "${1}_per_second"
metricsQuery: "sum(rate(<<.Series>>{<<.LabelMatchers>>}[2m])) by (<<.GroupBy>>)"

После этого:

Окно терминала
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/http_requests_per_second"

Если VPA меняет CPU limit с 1 на 4 (или back), GOMAXPROCS не обновляется автоматически (фиксируется при старте).

Решения:

  1. VPA Recreate mode — pod пересоздаётся, automaxprocs срабатывает заново.
  2. VPA InPlace (1.27+ alpha) — нужна интеграция с runtime.
  3. Periodic re-read из cgroup в Go.

Для большинства случаев Recreate приемлем.

При scale up Deployment’a — новые pods стартуют с тем же GOMEMLIMIT. Если memory limit изменился (через VPA или manual edit), нужен restart.

Cold start = время от создания pod до Ready.

Compose:

  1. Image pull — 5-30 секунд (cached / not).
  2. Container start — milliseconds.
  3. Process init — основной время.
  4. Warm-up — JIT, cache warmup, DB pool init.

Go cold start обычно 50-500ms для simple binary. Долгие старты из-за:

  • Init-heavy code (loading config from API, large embedded data).
  • DB pool init с retries.
  • TLS handshake к downstream.

Optimization:

  1. Lazy init — defer init until first request.
  2. Smaller binary (-ldflags=“-s -w” — strip debug info, ~30% smaller).
  3. PGO (Profile Guided Optimization) — Go 1.20+. Использует профиль с прошлого run.
  4. Reduce imports — каждый import inits.
  5. Distroless image — smaller layer, faster pull.
  6. Pre-pull images — DaemonSet или imageStreams.
  7. Init connections in parallel — не sequentially.
// PARALLEL init
func main() {
var wg sync.WaitGroup
var db *sql.DB
var redis *redis.Client
var kafka *kafka.Conn
wg.Add(3)
go func() { defer wg.Done(); db = initDB() }()
go func() { defer wg.Done(); redis = initRedis() }()
go func() { defer wg.Done(); kafka = initKafka() }()
wg.Wait()
runServer(db, redis, kafka)
}

После scale up новый pod нужно “прогреть”:

  1. DB connection pool — make initial connections.
  2. Cache — load hot data.
  3. JIT — для Java; Go редко страдает.

Readiness probe должен проверять, что warm-up завершился.

var warmedUp atomic.Bool
func startup() {
// Warm-up cache
cache.Preload(ctx)
// Warm-up DB pool
db.Ping(ctx)
warmedUp.Store(true)
}
// /ready
if !warmedUp.Load() {
w.WriteHeader(503)
}

Известный spike (e.g., Black Friday, 12:00 distribution time):

  • Pre-scale за час до пика.
  • KEDA cron trigger или manual.
# KEDA cron pre-scaling
triggers:
- type: cron
metadata:
timezone: Europe/Moscow
start: "0 11 * * 5" # Friday 11am (1h before noon)
end: "0 14 * * 5"
desiredReplicas: "50"
  • Min replicas ≥ 2 (high availability).
  • Max replicas с учётом cluster capacity.
  • Scale up быстро (window 0-30s).
  • Scale down медленно (window 5-15min).
  • Metric корректный (saturation, не just CPU).
  • Target utilization 60-80% (headroom).
  • PDB соответствует minReplicas.

Karpenter spot strategy:

  • Mix on-demand (baseline) и spot (burst).
  • Karpenter сам выбирает cheapest instance.
  • Graceful drain при spot interruption (2-min notice).

Schedule-based scaling:

  • Night-time scale down (если non-24/7 workload).
  • Weekend scale down.

HPA поддерживает multiple metrics — берёт max desired replicas.

metrics:
- type: Resource
resource:
name: cpu
target: { type: Utilization, averageUtilization: 70 }
- type: Pods
pods:
metric: { name: inflight_requests }
target: { type: AverageValue, averageValue: 50 }

Если CPU спокойный, но inflight высокий — scale up.


HPA scale up/down каждые 30 секунд → instability:

  • Pods kill in-flight requests.
  • Cold start spikes.

Решение: stabilizationWindowSeconds 300 для scale down, behavior policies.

Двойной loop. VPA лезет в memory, HPA в CPU — OK. Не на одну метрику.

metrics-server scrape’ит pods каждые 15 секунд, HPA опрашивает каждые 15. Минимум 30 секунд latency. Для быстрых spike недостаточно.

При резком scale up 10 новых pods → DB pool exhaustion (10 × 10 = 100 connections), cache cold → slow responses → ещё больше HPA scale → cascade.

Решение:

  • Connection pool limits.
  • Backoff в startup.
  • pre-warmed standby pods.

Очевидно, но часто забывается. Если minReplicas=10 и workload крошечный — деньги тратятся.

Если PDB minAvailable=2, а HPA хочет down to 1 — HPA блокирован. Логи покажут “blocked by PDB”.

Custom metrics через Prometheus имеют overhead: Prometheus scrape (15s) + Adapter query (5-30s) → HPA decision на основе данных 30-60 секунд назад. Для очень spiky workloads — недостаточно.

VPA в Auto mode убивает pod для apply нового request. Может прерывать long-running requests. Используй PDB.

Если pod scaled to 0, и затем сообщение в Kafka — нужно cold-start. Если client ждёт response 10 секунд — могут быть timeouts. Решение: keep minReplicas=1 для critical paths.

Karpenter может consolidate nodes (drain underutilized). Если на node persistent storage (CSI volume) — может быть проблема. Используй do-not-disrupt annotation для stateful.

Если scale API → downstream DB не масштабируется → bottleneck. Думай about whole pipeline.

Memory растёт постепенно, не реагирует на spike. И GC не освободит память сразу → HPA scale down не сработает.

HPA имеет tolerance ±10% (default), не reaction на маленькие отклонения. Полезно для шумных метрик, но может пропустить slowly building load.

CA не убивает node если:

  • Pod без replicaset (одиночный).
  • Pod с PodSafeToEvictAnnotation = false.
  • Pod с local storage.
  • System pods (kube-system).

Это может оставлять underutilized nodes.


E-commerce компании:

  • Pre-scale 24h до event.
  • HPA с extreme maxReplicas (1000+).
  • Multiple regions с traffic distribution.
  • Karpenter с aggressive spot mix.

После event: scale down постепенно (avoid cold start при still-high tail).

Streaming platform с unpredictable traffic:

  • KEDA с Kafka lag scaler.
  • minReplicas=1, max=200.
  • При спайке partition lag → scale up.
  • При тишине → scale to 1.

ML serving (TF Serving, Triton):

  • Cold start = 30-120 сек (model load).
  • HPA по queue length.
  • minReplicas=baseline для no cold start в hot path.
  • Pre-warming для известных пиков.

Netflix используют custom autoscaling:

  • Predictive (ML на исторических patterns).
  • Multi-region balanced.
  • Чрезвычайно агрессивные timeouts для cold start avoidance.

Авито на распродажах:

  • HPA на custom metric “in-flight requests per pod”.
  • Karpenter с EC2 spot.
  • Pre-warming за час.

Tinder использует geo-aware HPA:

  • Каждый regional cluster имеет свои patterns.
  • HPA per region.

Google Knative team постоянно работает над уменьшением cold start:

  • Activator pre-buffered.
  • Image streaming (initContainer).
  • Result: ~200ms cold start для Go workload.

Q1: В чём разница между HPA и VPA? A: HPA — horizontal, увеличивает количество pod replicas. VPA — vertical, изменяет requests/limits на existing pods. Разные подходы к масштабированию.

Q2: Можно ли использовать HPA и VPA одновременно? A: Да, но на разных метриках. VPA на memory, HPA на CPU — OK. VPA на CPU + HPA на CPU — infinite loop. Альтернатива: VPA в Off mode для рекомендаций.

Q3: Какую метрику лучше использовать для HPA? A: Saturation metrics (queue length, in-flight requests, threadpool utilization). CPU только для CPU-bound сервисов. Memory обычно плохо реагирует. Custom metrics через Prometheus Adapter.

Q4: Что такое behavior в HPA? A: Конфигурация скорости масштабирования (k8s 1.18+). Включает stabilizationWindowSeconds (анти-flapping) и policies (Percent/Pods за период). Стандарт: scale up быстро, scale down медленно.

Q5: Что такое KEDA? A: Kubernetes Event-Driven Autoscaling. CNCF проект, расширяющий HPA для event sources (Kafka, RabbitMQ, SQS, Prometheus, cron). Поддерживает scale-to-zero. 60+ scalers.

Q6: Что такое scale-to-zero? A: Возможность опустить replicas до 0 при отсутствии работы. Используется в KEDA, Knative. Плюс: zero cost. Минус: cold start при первом запросе.

Q7: Cluster Autoscaler vs Karpenter? A: CA — классика, работает через cloud node groups (ASG), медленнее (2-5 мин). Karpenter — next-gen, провизионит nodes напрямую, оптимизирует instance type под workload, быстрее (30-60 сек), поддерживает spot.

Q8: Что такое cold start в k8s и как уменьшить? A: Время от создания pod до Ready. Состоит из image pull + container start + process init + warm-up. Уменьшить через: lazy init, parallel init, smaller binary (-s -w), PGO, distroless image, pre-pull images.

Q9: Как GOMAXPROCS адаптируется к autoscaling? A: При старте Go устанавливает GOMAXPROCS = numCPU из cgroup (через automaxprocs). При VPA Recreate pod пересоздаётся — GOMAXPROCS заново. Без recreate не меняется (фиксируется в start).

Q10: Что такое PGO в Go и как влияет на cold start? A: Profile Guided Optimization (Go 1.20+). Использует профиль с прошлого run для оптимизации. Уменьшает binary size на 5-15%, ускоряет hot path. Помогает с cold start (быстрее старт).

Q11: Зачем нужен Prometheus Adapter? A: Exposing Prometheus queries как k8s custom metrics API. Позволяет HPA использовать application metrics (RPS, queue length). Без него HPA знает только CPU/memory.

Q12: Что такое CronHPA? A: HPA по расписанию (schedule-based). Стандартный HPA не имеет этого, но KEDA cron scaler или Crossplane позволяют. Применение: pre-warming перед известным пиком, ночное scale-down.

Q13: Какие проблемы со scale down? A: 1) Прерывание long-running requests (graceful shutdown!). 2) Cache cold при scale back up. 3) Connection pool теряется. 4) Возможный flapping. Решение: agressive stabilization window 5-15 мин.

Q14: Что такое VPA Recreate? A: VPA update mode, при котором pod пересоздаётся для apply новых requests. Альтернатива — InPlace (1.27+ alpha) без рестарта. Recreate безопаснее для production.

Q15: Knative и зачем нужен activator? A: При scale-to-zero первый запрос приходит когда pod ещё не запущен. Activator буферизует запрос, триггерит cold start, потом проксирует запрос когда pod ready. Без activator client получил бы timeout.

Q16: Multi-dimensional HPA? A: HPA с multiple metrics. Считает desired replicas для каждой, берёт MAX. Например: CPU 70% target + inflight_requests 50/pod target. Если CPU спокойный, но inflight высокий → scale up.

Q17: Какие spot instances и как с ними работать в Karpenter? A: Spot — дешёвые EC2 instances (до 90% off), но cloud может забрать их с 2-минутным notice. Karpenter поддерживает: mix on-demand + spot, graceful drain on interruption, fallback к on-demand при нехватке.

Q18: Что такое PodDisruptionBudget и как влияет на autoscaling? A: PDB гарантирует minimum доступных pods во время disruptions (включая scale down, eviction). Если scale down хочет убить pod, нарушая PDB — блокировано. Должен быть согласован с HPA minReplicas.

Q19: HPA tolerance — что это? A: HPA не реагирует на изменения < 10% (default). Защита от шумных метрик. Минус: можно пропустить slowly building load.

Q20: Какой anti-pattern Cool down? A: Слишком короткий stabilization window (например, 30s scale down). HPA убивает pods → cold start → load растёт → HPA opens up → flapping. Стандарт: 5-15 мин scale down stabilization.


  1. Basic HPA: создай Deployment с CPU stress (например stress-ng), HPA по CPU. Запусти load, посмотри scale up.

  2. Custom metric HPA: настрой Prometheus + Adapter, expose метрику inflight_requests. HPA по custom metric. Сравни с CPU-based.

  3. KEDA Kafka: запусти Kafka, deploy consumer с KEDA scaler по lag. Producer sends spike — наблюдай scale-to-zero → scale up.

  4. VPA recommendations: deploy в VPA Off mode, посмотри рекомендации через 24 часа. Apply manually, сравни.

  5. Cold start measurement: измерь cold start своего Go service. Применяй оптимизации (parallel init, lazy, smaller binary). Сравни.

  6. Stabilization tuning: настрой HPA с разными stabilization windows. Apply oscillating load — наблюдай flapping vs stable.

  7. Karpenter setup (AWS): настрой Karpenter, создай NodePool с mix spot+on-demand. Deploy app с large replicas, посмотри instance selection.

  8. Cron-based pre-scaling: KEDA cron scaler для daily peak. Симулируй pre-scale за час до load.


  1. K8s HPA docs: https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/.
  2. K8s VPA: https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler.
  3. KEDA: https://keda.sh/.
  4. Karpenter: https://karpenter.sh/.
  5. Knative: https://knative.dev/.
  6. Prometheus Adapter: https://github.com/kubernetes-sigs/prometheus-adapter.
  7. uber-go/automaxprocs: https://github.com/uber-go/automaxprocs.
  8. “Cloud Native Patterns” — Cornelia Davis, Manning.
  9. AWS Karpenter blog: https://aws.amazon.com/blogs/containers/category/compute/karpenter/.
  10. Go PGO: https://go.dev/doc/pgo.