HPA — Pod 개수
Horizontal Pod Autoscaler. 기본 내장. 커리큘럼이 말하는 건 사실상 이것.
부하에 따라 개수를 바꾼다
HPA — Pod 개수
Horizontal Pod Autoscaler. 기본 내장. 커리큘럼이 말하는 건 사실상 이것.
VPA — Pod 크기
Vertical Pod Autoscaler. requests/limits를 조정. 별도 설치(CRD).
Cluster Autoscaler — 노드 개수
Pending Pod이 있으면 노드를 늘린다. 클라우드 제공자별 설치.
셋은 계층이 다르다. 차례로 물려 있다.
flowchart LR
LOAD["부하 증가"] --> HPA["HPA<br/>Pod 개수를 늘린다"]
HPA --> Q{"노드에 자리가<br/>있는가"}
Q -->|"있다"| OK["새 Pod 이 뜬다 ✅"]
Q -->|"없다"| PEND["Pod 이 Pending"]
PEND --> CA["Cluster Autoscaler<br/>노드를 늘린다"]
CA --> OK
VPA["VPA<br/>Pod 하나의 크기를 키운다"] -.->|"다른 축이다"| HPA
classDef key fill:#dbeafe,stroke:#2563eb,color:#1e3a8a
classDef ok fill:#dcfce7,stroke:#16a34a,color:#14532d
classDef warn fill:#fef3c7,stroke:#d97706,color:#78350f
classDef mute fill:#f1f5f9,stroke:#94a3b8,color:#334155
class HPA,CA key
class OK ok
class PEND warn
class LOAD,Q,VPA mute
| 이름 | 무엇을 늘리나 | 어디에 있나 |
|---|---|---|
| HPA (Horizontal Pod Autoscaler) | Pod 개수 | 기본 내장 |
| VPA (Vertical Pod Autoscaler) | Pod의 requests/limits | 별도 설치 |
| Cluster Autoscaler | 노드 개수 | 클라우드 제공자별 설치 |
HPA는 메트릭이 없으면 아무것도 하지 않는다.
kubectl top nodeskubectl top podskubectl top pods --containerskubectl top pod web --sort-by=memoryerror: Metrics API not available이 에러가 나오면 metrics-server가 없거나 죽어 있는 것이다.
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yamlkubectl get deploy metrics-server -n kube-systemkubectl get apiservice v1beta1.metrics.k8s.ioflowchart LR
K["kubelet<br/>cAdvisor"] --> MS["metrics-server<br/>메모리에만 저장"]
MS -->|"metrics.k8s.io<br/>APIService 등록"| API["kube-apiserver"]
API --> HPA["HPA 컨트롤러"]
API --> TOP["kubectl top"]
HPA -->|"replicas 조정"| D["Deployment"]
PROM["장기·커스텀 메트릭이 필요하면<br/>Prometheus + adapter"] -.-> API
classDef key fill:#dbeafe,stroke:#2563eb,color:#1e3a8a
classDef warn fill:#fef3c7,stroke:#d97706,color:#78350f
classDef mute fill:#f1f5f9,stroke:#94a3b8,color:#334155
class MS key
class PROM warn
class K,API,HPA,TOP,D mute
metrics.k8s.io) — 그래서 kubectl top이 동작한다kubectl autoscale deploy web --min=2 --max=10 --cpu-percent=70kubectl get hpakubectl describe hpa webapiVersion: autoscaling/v2kind: HorizontalPodAutoscalermetadata: name: webspec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: web minReplicas: 2 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70flowchart LR
M["현재 지표<br/>CPU 평균 90%"] --> C["ceil( 현재 개수 × 현재지표 / 목표지표 )"]
T["목표 지표<br/>70%"] --> C
R["현재 3개"] --> C
C --> CALC["3 × 90/70 = 3.86"] --> UP["올림 → 4개"]
TOL["비율이 0.9 ~ 1.1 이면<br/>움직이지 않는다 · tolerance"] -.->|"진동 방지"| C
classDef key fill:#dbeafe,stroke:#2563eb,color:#1e3a8a
classDef ok fill:#dcfce7,stroke:#16a34a,color:#14532d
classDef warn fill:#fef3c7,stroke:#d97706,color:#78350f
classDef mute fill:#f1f5f9,stroke:#94a3b8,color:#334155
class C key
class UP ok
class TOL warn
class M,T,R,CALC mute
목표 개수 = ceil( 현재 개수 × (현재 지표 / 목표 지표) )
예: 현재 3개, CPU 평균 사용률 90%, 목표 70% → 3 × (90 / 70) = 3.86 → 올림 → 4개
--horizontal-pod-autoscaler-sync-period)kubectl get hpa# NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE# web Deployment/web cpu: 45%/70% 2 10 3 5mflowchart TD
T{"TARGETS 표시"}
T -->|"45%/70%"| OK["정상 동작 중 ✅"]
T -->|"unknown/70%"| U{"원인 둘 중 하나"}
U --> U1["① kubectl top pods 가 되는가<br/>→ metrics-server 확인"]
U --> U2["② Deployment 에 resources.requests.cpu 가 있는가<br/>→ 없으면 계산 불가"]
T -->|"none"| N["대상 워크로드를 못 찾는다<br/>scaleTargetRef 확인"]
classDef ok fill:#dcfce7,stroke:#16a34a,color:#14532d
classDef bad fill:#fee2e2,stroke:#dc2626,color:#7f1d1d
classDef warn fill:#fef3c7,stroke:#d97706,color:#78350f
classDef mute fill:#f1f5f9,stroke:#94a3b8,color:#334155
class OK ok
class N bad
class U1,U2 warn
class T,U mute
| TARGETS 표시 | 뜻 |
|---|---|
45%/70% |
정상 동작 중 |
<unknown>/70% |
메트릭을 못 읽는다 — metrics-server 또는 requests 누락 |
<none> |
대상 워크로드를 못 찾는다 |
kubectl describe hpa web # Conditions 와 Events 를 본다# Conditions:# AbleToScale True ReadyForNewScale# ScalingActive True ValidMetricFound# ScalingLimited False DesiredWithinRangemetrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70 - type: Resource resource: name: memory target: type: AverageValue # 절대값으로도 가능 averageValue: 500Mi - type: Pods # 커스텀 메트릭 (adapter 필요) pods: metric: name: http_requests_per_second target: type: AverageValue averageValue: "1000"flowchart LR
M1["CPU 계산 → 4개"] --> MAX{"가장 큰 값을 택한다"}
M2["메모리 계산 → 6개"] --> MAX
M3["커스텀 계산 → 3개"] --> MAX
MAX --> R["6개로 확장"]
NOTE["하나라도 넘치면 늘어난다<br/>축소는 전부 여유가 있어야 한다"] -.- MAX
classDef key fill:#dbeafe,stroke:#2563eb,color:#1e3a8a
classDef ok fill:#dcfce7,stroke:#16a34a,color:#14532d
classDef mute fill:#f1f5f9,stroke:#94a3b8,color:#334155
class MAX key
class R ok
class M1,M2,M3,NOTE mute
spec: behavior: scaleUp: stabilizationWindowSeconds: 0 # 즉시 늘린다 policies: - type: Percent value: 100 # 한 번에 최대 2배 periodSeconds: 15 - type: Pods value: 4 # 또는 한 번에 최대 4개 periodSeconds: 15 selectPolicy: Max scaleDown: stabilizationWindowSeconds: 300 # 5분간 관찰 후 축소 (기본값) policies: - type: Percent value: 10 periodSeconds: 60flowchart LR
UP["scaleUp<br/>stabilizationWindow 0"] --> F["빠르게 늘린다 ⚡"]
DOWN["scaleDown<br/>stabilizationWindow 300"] --> S["5분 관찰 후 천천히 줄인다 🐢"]
DIS["selectPolicy: Disabled"] -.->|"그 방향으로는 아예 안 움직인다"| BOTH["scaleUp 또는 scaleDown"]
classDef ok fill:#dcfce7,stroke:#16a34a,color:#14532d
classDef warn fill:#fef3c7,stroke:#d97706,color:#78350f
classDef mute fill:#f1f5f9,stroke:#94a3b8,color:#334155
class F ok
class S warn
class UP,DOWN,DIS,BOTH mute
selectPolicy: Disabled 로 두면 그 방향으로는 아예 안 움직인다Off(추천만) / Initial / Autoflowchart LR
S["kubectl scale deploy web --replicas=8"] --> HPA["HPA 가 붙어 있다"]
HPA -->|"다음 평가 주기 · 15초"| BACK["계산값으로 되돌린다 ❌"]
FIX1["HPA 를 지운다"] -.-> OK["수동 스케일이 유지된다"]
FIX2["minReplicas 를 바꾼다"] -.-> OK
classDef bad fill:#fee2e2,stroke:#dc2626,color:#7f1d1d
classDef ok fill:#dcfce7,stroke:#16a34a,color:#14532d
classDef mute fill:#f1f5f9,stroke:#94a3b8,color:#334155
class BACK bad
class OK ok
class S,HPA,FIX1,FIX2 mute
HPA는 scale 서브리소스가 있는 리소스면 무엇이든 대상이 된다
— Deployment, ReplicaSet, StatefulSet. DaemonSet은 안 된다(개수를 노드가 정하므로).
kubectl top도 HPA도 죽는다. 이것부터 확인ceil(현재 × 현재지표/목표지표), 0.9~1.1은 무시(tolerance)averageUtilization은 requests 기준. requests가 없으면 <unknown>kubectl scale은 무의미하다