마이크로서비스/컨테이너 환경에서는 트래픽·이벤트·배치가 시간대/시즌/캠페인에 따라 급격하게 바뀝니다.
고정된 replica 수와 고정 자원만으로 운영하면 보통 다음이 반복됩니다.
그래서 목표는 단순합니다. “필요할 때만, 필요한 만큼” 자동으로 늘고 줄어드는 시스템을 만드는 것입니다.

책에서는 수동 스케일링을 명령형(Imperative) 과 선언형(Declarative) 로 구분합니다.
kubectl scale deploy/random-generator --replicas=10
Deployment.spec.replicas를 변경하고 kubectl apply로 반영합니다.운영 예시
블랙프라이데이/라이브커머스처럼 “시작 시간이 확실한 이벤트”는
HPA가 있어도 프리워밍(Pre-warming) 으로 미리 replicas를 올려두는 편이 더 안전한 경우가 많습니다.
HPA는 Kubernetes 기본 기능으로, 메트릭 기반으로 replicas를 자동 조절합니다.
다만 기본 HPA만으로는 Scale-to-Zero(0 Pod) 가 불가능합니다(minReplicas >= 1 필수).
책에서 제시하는 HPA의 핵심은 아래 공식입니다.
desiredReplicas = ceil(currentReplicas × (currentMetricValue / desiredMetricValue))
계산 예시(책 예시 그대로)
ceil(1 × 90/50) = ceil(1.8) = 2
HPA는 크게 3가지 메트릭 소스/유형을 다룹니다.
| 유형 | 대표 예 | 특징 | 보통 필요한 구성 |
|---|---|---|---|
| Standard(Resource Metrics) | CPU/Memory | Kubernetes 기본 메트릭(리소스 사용량) | metrics-server |
| Custom Metrics | http_requests_per_second 같은 애플리케이션 지표 | “클러스터 내부 객체(예: Pod)”와 연결되는 커스텀 지표 | Custom Metrics Adapter(예: Prometheus Adapter) |
| External Metrics | SQS 큐 길이, 외부 시스템의 backlog | “클러스터 바깥 자원” 지표 | External Metrics Provider + (여러 시스템을 쓰면) 집계 레이어(KEDA 등) |
책 포인트: HPA의 리소스 사용률(Utilization) 계산은
limits가 아니라requests(guaranteed resource) 를 기준으로 합니다.
운영 예시
- Custom: “요청/초(RPS)”를 Prometheus로 수집 → HPA가
custom.metrics로 스케일- External: “큐 길이”를 기준으로 워커를 스케일 → KEDA가 특히 잘 맞습니다.
HPA 메트릭 선택의 핵심 질문은 이것입니다.
“Pod를 늘리면(metric 분산으로) 그 지표가 내려가나요?”
- 좋은 지표: CPU, RPS, 큐 길이(부하 분산과 상관관계가 큼)
- 위험한 지표: Memory(특히 캐시/힙을 오래 잡는 런타임)
나쁜 예시(메모리 기반 HPA 폭주)
Java 서비스가 캐시를 많이 쥐고 있어 메모리 사용률이 80%로 유지됩니다.
HPA는 메모리를 낮추려고 Pod를 계속 늘리지만, 새 Pod도 캐시가 차면서 지표가 내려가지 않습니다.
결국 maxReplicas까지 계속 증가하며 비용 폭발로 이어질 수 있습니다.
결론
메모리 문제는 HPA로 해결하려고 하기보다, VPA/requests 튜닝/애플리케이션 튜닝으로 접근하는 편이 안정적입니다.
HPA는 지표가 흔들릴 때 빠르게 올렸다 내렸다(Thrashing) 하면 오히려 장애를 유발합니다.
그래서 autoscaling/v2의 .spec.behavior로 확장/축소 속도를 제한하는 운영이 일반적입니다.
참고: 아래 HPA 예시는 behavior(Example 29-5) 중심으로 책 예시와 동일하게 맞췄고,
min/max/target값은 설명을 위해 다소 확장해 적었습니다(책 Example 29-4는min=1, max=5, target=50).
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: random-generator-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: random-generator
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
behavior:
scaleDown:
stabilizationWindowSeconds: 300 # 5분 안정화(급격한 축소 방지)
policies:
- type: Percent
value: 10
periodSeconds: 60 # 1분당 10%씩만 감소
scaleUp:
policies:
- type: Pods
value: 4
periodSeconds: 15 # 15초당 최대 4개 증가
운영 팁
일반적으로 scaleUp은 빠르게, scaleDown은 느리게 잡는 편이 사용자 체감 안정성에 유리합니다.
기본 HPA의 대표적인 한계는 “트래픽/이벤트가 완전히 없을 때 0 Pod까지 내려가 비용을 0에 가깝게 만들기 어렵다”는 점입니다.
이를 보완하는 대표적인 Kubernetes 애드온이 Knative 와 KEDA 입니다.
책의 사이드바 요약을 운영 관점으로 풀면 다음과 같습니다.


Knative는 보통 다음 3축으로 이해하시면 편합니다.
그리고 Serving의 핵심 오토스케일러가 KPA(Knative Pod Autoscaler) 입니다.

참고 이미지(공식 문서)
- Knative Serving Architecture:

(Velog에서는 보통 “이미지 직접 링크”가 필요하니, 게시 전 페이지에서 실제 이미지 URL을 복사해 붙여주시는 것을 권장드립니다.)
책의 Table 29-1을 그대로 옮겨, 운영 시 자주 만지는 옵션만 표로 정리합니다.
(공통 prefix autoscaling.knative.dev/는 생략합니다.)
| Annotation | 의미 | 기본값 |
|---|---|---|
target | replica 1개가 처리할 동시 요청 수(soft limit) | 100 |
target-utilization-percentage | concurrency limit의 몇 %에 도달하면 새 replica 생성 시작 | 70 |
min-scale | 최소 replica 수(>0이면 scale-to-zero 불가) | 0 |
max-scale | 최대 replica 수(0이면 무제한) | 0 |
activation-scale | 0에서 올라올 때 초기로 만들 replica 수 | 1 |
scale-down-delay | scale-down 조건이 유지되어야 하는 시간(웜 유지/콜드스타트 완화) | 0s |
window | 스케일 판단에 사용하는 평균 윈도우 | 60s |
운영 예시
- 트래픽이 들쭉날쭉한데 콜드스타트가 부담이면
scale-down-delay를 주고 “웜 유지”를 합니다.- 완전 서버리스(0)로 내리려면
min-scale=0유지가 필수입니다.
책의 Example 29-6을 실습 가능한 형태로 정리했습니다.
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: random
annotations:
autoscaling.knative.dev/target: "80"
autoscaling.knative.dev/window: "120s"
spec:
template:
spec:
containers:
- image: k8spatterns/random
Service와 이름은 같지만, API 그룹이 serving.knative.dev로 다릅니다.target/window는 KPA 오토스케일링 동작을 튜닝하는 대표 파라미터입니다.이벤트 드리븐 확장(Event-driven scaling)
KEDA는 외부 이벤트(큐 메시지, lag, 스케줄, DB 변화 등)를 “트리거”로 보고 워크로드를 확장하는 패턴에 최적화되어 있습니다.
KEDA는 “이벤트 기반 워커(큐/스트림 컨슈머)”에 특히 잘 맞습니다.

책의 핵심 요약은 다음입니다.

책의 Example 29-7을 그대로 가져왔습니다.
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: kafka-scaledobject
spec:
scaleTargetRef:
name: kafka-consumer
pollingInterval: 30
triggers:
- type: kafka
metadata:
bootstrapServers: bootstrap.kafka.svc:9092
consumerGroup: my-group
topic: my-topic
scaleTargetRef: 스케일 대상(기본은 Deployment)pollingInterval: (특히 0에서 올라올 때) KEDA가 트리거를 확인하는 주기triggers: 어떤 외부 시스템을 볼지(여기서는 Kafka)운영 예시
“컨슈머 lag가 쌓이면 consumer를 늘린다”는 전형적인 패턴에서,
KEDA는 외부 시스템의 backlog를 직접 지표로 쓰는 것이 강점입니다.
책의 Table 29-2를 “운영자가 고르는 기준” 중심으로 다시 구성했습니다.
| 구분 | HPA | Knative | KEDA |
|---|---|---|---|
| 대표 워크로드 | 일반 서비스(특히 CPU 기반) | HTTP 서버리스(웹/API) | 이벤트 워커(큐/스트림) |
| Scale-to-Zero | 불가(minReplicas ≥ 1 필수) | 가능(기본 철학) | 가능 |
| 주요 메트릭 | CPU/메모리/커스텀/외부 | concurrency / RPS(트래픽 중심) | 외부 이벤트/큐/lag |
| 방식 | Pull(메트릭 API 조회) | Push(Activator/queue-proxy) | Pull(외부 polling) |
| Typical use case | 안정적 트래픽 웹 앱, 배치 처리 | 트래픽 없으면 0, 첫 요청 버퍼링 | 큐가 쌓이면 워커를 0→N |
VPA는 “Pod 한 개의 사이즈”를 맞추는 오토스케일러입니다.
특히 requests/limits를 잘못 잡아 생기는 문제(OOM, 과도한 낭비) 를 줄이는 데 강점이 있습니다.
책의 Figure 29-4를 말로 풀면, VPA는 다음 3 컴포넌트가 협업합니다.

책에서 설명하는 모드를 운영 관점으로 정리하면 다음과 같습니다.
| 모드 | 무엇을 하나요? | 운영 난이도 |
|---|---|---|
| Off | 추천만 계산(Dry-run) | 낮음 (실무 기본 권장) |
| Initial | Pod 생성 시에만 추천값 주입 | 중간 |
| Recreate | 실행 중 Pod도 적용하되, 강제 evict/재생성 방식 | 높음 |
| Auto | 실행 중 Pod도 적용(Updater가 eviction/reschedule) | 높음 |
책 관점(중요): 의도 상
Auto는 재시작 없이(in-place) 자원 조정을 목표로 하지만, 책이 다루는 시점(2023)에서는Recreate와 동일하게 eviction/재시작으로 적용된다고 설명합니다.
실무 팁
처음에는 반드시 Off 로 “추천값을 충분히 모은 뒤” 매니페스트를 사람이 고정하는 방식이 안전합니다.
VPA는 resourcePolicy로 컨테이너별 하한/상한을 줄 수 있습니다.
실무에서는 “갑자기 추천값이 너무 커지거나 너무 작아지는 것”을 막는 안전장치로 자주 사용합니다.
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: demo-nginx-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: demo-nginx
updatePolicy:
updateMode: "Off"
resourcePolicy:
containerPolicies:
- containerName: "*"
minAllowed:
cpu: 50m
memory: 64Mi
maxAllowed:
cpu: 500m
memory: 512Mi
HPA와 VPA는 같은 축을 동시에 건드리면 예상치 못한 피드백 루프가 생길 수 있습니다.
문제는 HPA가 CPU utilization(= 사용량/requests)에 의존하는 경우입니다.
VPA가 requests를 올려버리면 utilization이 낮아져 HPA가 줄이고,
다시 utilization이 오르고… 같은 Double Scaling이 생길 수 있습니다.
권장 패턴(충돌 방지)
- HPA는 “replicas”만 책임지게 하되,
- VPA는 “Off/Initial”로 requests 튜닝에만 제한적으로 사용하고,
- 가능하면 HPA는 CPU utilization 대신 RPS/큐 길이 같은 지표로 역할 분담을 하시는 편이 안전합니다.
HPA/VPA가 “클러스터 내부에서 Pod를 조절”하는 이야기라면,
CA(Cluster Autoscaler)는 리소스 부족으로 Pod가 스케줄링되지 못해 Pending(Unschedulable) 상태가 발생했을 때 새 노드를 추가하는 방식으로, 노드 자체를 늘리고 줄여 클러스터 용량을 탄력화합니다.
책에서는 CA가 scale-up 시 node group을 확장하는데, 이때 “어떤 node group을 늘릴지”를 고르는 전략으로 expander를 소개합니다.
운영 예시
CPU 노드그룹과 GPU 노드그룹이 함께 있을 때, expander가 없거나 설정이 부적절하면
“GPU 노드를 불필요하게 늘리는” 비용 사고가 날 수 있습니다.
책에서 CA scale-down을 “안전하게” 수행하기 위한 4가지 조건을 명시합니다.
운영 함정(자주 겪는 장애)
“노드가 텅 비어 보이는데도” scale-down이 안 되는 이유는 대개 4번입니다.
특히 PDB / local PV / DaemonSet / eviction 방지 annotation 을 먼저 의심하시면 해결이 빨라집니다.
책은 “어디부터 손대야 하는가?”를 더 명확하게 하기 위해 스케일링 레벨을 4단계로 정리합니다.

Kubernetes 밖의 이야기지만, “컨테이너 안 앱이 자원을 잘 쓰게” 만드는 단계입니다.
예시(자주 겪는 케이스)
팁
이 단계가 제대로 되지 않으면, 그 위에서 HPA/VPA/CA를 아무리 잘 붙여도 “비효율이 커진 채로” 확장만 하게 됩니다.
이 부록은 책 내용을 이해하기 위한 실습 가이드(책 밖 보충) 입니다. 운영 환경에 그대로 적용하기보다는, 개념 검증용으로 사용해 주세요.
목표: “부하를 만들고 → HPA가 replicas를 늘리고 → VPA 추천값을 확인”하는 흐름을 체험합니다.
Knative/KEDA는 환경이 갖춰졌다면 선택적으로 따라가시면 됩니다.
kubectl apply -f <https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml>
kubectl -n kube-system rollout status deploy/metrics-server
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-nginx
spec:
replicas: 2
selector:
matchLabels:
app: demo-nginx
template:
metadata:
labels:
app: demo-nginx
spec:
containers:
- name: nginx
image: nginx:1.27
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
memory: 128Mi
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: demo-nginx
spec:
selector:
app: demo-nginx
ports:
- port: 80
targetPort: 80
kubectl apply -f demo.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: demo-nginx-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: demo-nginx
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 10
periodSeconds: 60
scaleUp:
policies:
- type: Pods
value: 4
periodSeconds: 15
kubectl apply -f hpa.yaml
kubectl get hpa -w
kubectl run -it --rm loadgen --image=busybox:1.36 --restart=Never -- sh -c \\
'while true; do wget -q -O- <http://demo-nginx>; done'
다른 터미널에서 관찰합니다.
kubectl get deploy,pod,hpa -w
kubectl top pod
VPA는 클러스터에 따라 별도 설치가 필요합니다(설치 방법은 환경별로 상이하므로 공식 가이드를 참고해 주세요). 설치가 되어 있다면, 아래처럼 Off(추천만) 모드로 먼저 사용하시는 것을 권장드립니다.
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: demo-nginx-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: demo-nginx
updatePolicy:
updateMode: "Off"
kubectl apply -f vpa.yaml
kubectl describe vpa demo-nginx-vpa
책의 결론을 한 문장으로 요약하면, Elastic Scale은 단지 “늘리고 줄이는 자동화”가 아니라,
외부 스트레스(트래픽/부하)가 커질수록 시스템이 더 커지고 더 강해지는, 즉 “antifragile”에 가까운 특성을 제공한다
는 관점입니다.
장애를 “그냥 버티는(resilient)” 수준을 넘어, 부하가 올 때 더 유연하게 적응하며 강해지는 방향이 탄력적 확장의 목표입니다.
이 부록은 책(2nd Edition, 2023) 이후의 Kubernetes 변화를 운영 관점에서 덧붙인 내용입니다.
- HPA tolerance 필드(Beta, 기본 활성화): 목표값 주변의 작은 변동에는 스케일링을 하지 않도록 하는 “민감도”를
tolerance로 조정할 수 있습니다.
짧은 스파이크가 잦은 서비스에서 불필요한 스케일링을 줄이는 데 도움이 됩니다. (공식 문서 참고)- In-Place Pod Resize(Stable/GA): Pod를 재생성하지 않고도 자원(requests/limits) 변경을 적용할 수 있는 방향으로 기능이 성숙하고 있습니다.
장기적으로는 “VPA 적용 시 eviction 부담”을 줄이는 기반이 될 수 있습니다.
실무 팁
기능의 활성화 여부/제약은 클러스터 설정과 런타임, 정책(Quota/LimitRange) 등에 따라 달라질 수 있으니, 적용 전에는 스테이징에서 반드시 검증하시는 것을 권장드립니다.