apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
spec:
scaleTargetRef: { apiVersion: apps/v1, kind: Deployment, name: web }
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target: { type: Utilization, averageUtilization: 70 }
반드시 알아야 할 두 전제
-
① CPU 사용률은 'requests 대비' 비율이다
- requests 가 없으면 계산이 불가능해 HPA 가 동작하지 않는다
- HPA 를 쓰려면 requests 는 필수다
-
② metrics-server 가 설치돼 있어야 한다
- 없으면 kubectl top 도 안 되고 HPA 도 unknown 으로 멈춘다
- kubectl top nodes 로 먼저 확인한다
세 오토스케일러
- HPA — 파드 '개수' 를 늘린다
- VPA — 파드의 requests/limits 를 조정한다
- Cluster Autoscaler — '노드' 를 늘린다
조합
HPA + Cluster Autoscaler 잘 맞는다
파드가 Pending 이 되면 노드를 늘린다
HPA + VPA (같은 지표) 서로 싸운다. 권장되지 않는다
VPA 는 requests 를 올리고
HPA 는 그 requests 기준 비율을 본다
진동을 막는 장치
behavior:
scaleDown:
stabilizationWindowSeconds: 300 # 축소는 5분 관찰 후
policies:
- type: Percent
value: 50
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 0 # 확장은 즉시
확장은 빠르게, 축소는 천천히 — 가 기본 감각이다 트래픽이 출렁일 때 파드가 늘었다 줄었다 반복하면 기동 비용만 들고 응답은 오히려 나빠진다
사용자 지표로 늘리기
CPU 는 대개 좋은 지표가 아니다
- I/O 대기가 많은 서비스는 CPU 가 안 오르는데도 느려진다
더 나은 지표
- 초당 요청 수 · 큐 길이 · 응답 지연 p95
- Prometheus Adapter · KEDA 로 커스텀·외부 지표를 쓴다
- KEDA 는 이벤트 기반(큐 길이·Kafka lag)으로 0까지 축소도 지원한다
In-Place 리사이즈 (1.35 GA)
예전에는 requests/limits 를 바꾸면 파드가 재생성됐다 1.35 부터 재시작 없이 조정할 수 있다 1.36 에서는 파드 수준 리소스도 조정 가능해졌다 (베타)
상태 있는 워크로드에서 특히 의미가 크다 — 수직 확장이 곧 중단이 아니게 된다
왜 안 늘어나는가 — 확인 순서
kubectl get hpa
# NAME TARGETS MINPODS MAXPODS REPLICAS
# web <unknown>/70% 3 20 3 ← 지표를 못 읽는다
<unknown> 이면
① metrics-server 가 없다 kubectl top nodes 로 확인
② requests 가 없다 비율 계산이 불가능하다
③ 라벨 셀렉터가 파드와 안 맞는다
kubectl describe hpa web 의 Conditions·Events 에 이유가 나온다
ScalingActive False → 지표 문제
AbleToScale False → 대상 문제
늘어도 트래픽이 안 나뉘는 경우
HPA 가 파드를 늘렸는데 응답이 안 좋아진다면
- gRPC·HTTP/2 라 기존 연결이 그대로 쏠린다 (kube-proxy 는 L4 다)
- 병목이 파드가 아니라 DB·외부 API 다
- 파드를 늘릴수록 뒤가 더 아프다
- 기동이 느려 새 파드가 준비되기 전에 트래픽을 받는다
"늘리면 해결된다" 는 병목이 파드에 있을 때만 맞다
면접 함정
- ❌ "HPA만 걸면 자동으로 확장된다" → requests와 metrics-server가 없으면 아무 일도 안 일어난다.
- ❌ "CPU 기준이면 충분하다" → I/O 바운드 서비스는 CPU가 안 오른다.