콘텐츠로 이동
Study NoteCKA

오토스케일링

부하에 따라 개수를 바꾼다

지금까지 Deployment의 replicas는 사람이 정한 고정값이었다. 부하는 시간에 따라 변하는데 선언은 안 변하니, 피크에 맞추면 평시에 낭비고 평시에 맞추면 피크에 죽는다. 오토스케일러는 지표를 보고 선언(spec) 자체를 고쳐 쓰는 컨트롤러다 — 시작하기 전에의 “선언된 상태 ↔ 실제 상태를 좁히는 루프” 위에, 선언 쪽을 갱신하는 루프가 하나 더 얹힌다.

HPA — Pod 개수

Horizontal Pod Autoscaler. 기본 내장. 커리큘럼이 말하는 건 사실상 이것.

VPA — Pod 크기

Vertical Pod Autoscaler. requests/limits를 조정. 별도 설치 — CRD(CustomResourceDefinition — 새 리소스 종류를 추가하는 확장, CRD)로 깔린다.

Cluster Autoscaler — 노드 개수

Pending Pod이 있으면 노드를 늘린다. 클라우드 제공자별 설치.

셋은 계층이 다르다. 차례로 물려 있다.

부하가 늘면 HPA 가 Pod 을 늘리고 자리가 없으면 Cluster Autoscaler 가 노드를 늘리며 VPA 는 Pod 하나의 크기를 키우는 다른 축이라는 관계
이름무엇을 늘리나어디에 있나
HPA (Horizontal Pod Autoscaler)Pod 개수기본 내장
VPA (Vertical Pod Autoscaler)Pod의 requests/limits별도 설치
Cluster Autoscaler노드 개수클라우드 제공자별 설치

“현재 지표”를 판단하려면 사용량 데이터가 필요한데, 코어 Kubernetes에는 사용량을 재는 컴포넌트가 없다 — etcd에 있는 것은 spec과 status지, CPU 사용률이 아니다. 그 구멍을 메우는 애드온이 metrics-server다.

HPA는 메트릭이 없으면 아무것도 하지 않는다.

터미널 창
kubectl top nodes
kubectl top pods
kubectl top pods --containers
kubectl top pod web --sort-by=memory
error: Metrics API not available

이 에러가 나오면 metrics-server가 없거나 죽어 있는 것이다.

터미널 창
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
kubectl get deploy metrics-server -n kube-system
kubectl get apiservice v1beta1.metrics.k8s.io
kubelet cAdvisor 의 지표가 metrics-server 를 거쳐 metrics.k8s.io API 로 올라가 HPA 컨트롤러와 kubectl top 이 쓰는 경로
  • 출발점은 각 노드 kubelet에 내장된 cAdvisor(Container Advisor — 컨테이너 사용량 수집기)다 — 이름만 알면 된다
  • metrics-server는 APIService로 등록된다 (metrics.k8s.io) — APIService는 kube-apiserver에 외부 API 그룹을 이어 붙이는 확장점이라, kubectl top도 HPA도 별도 통로 없이 평범한 API 호출로 동작한다. 그래서 진단도 kubectl get apiservice로 한다
  • 메모리에만 저장한다. 과거 데이터가 없다 — 모니터링 도구가 아니다
  • 장기 메트릭이나 커스텀 메트릭이 필요하면 Prometheus + adapter를 쓴다 — 깊게 팔 필요는 없다, 이름만 알아두자
터미널 창
kubectl autoscale deploy web --min=2 --max=10 --cpu=70%
kubectl get hpa
kubectl describe hpa web

--cpu=70%는 requests 대비 평균 사용률 70%를 뜻한다. 옛 자료의 --cpu-percent=70은 v1.35에서도 동작하지만 deprecated로 표시되어 있다(kubectl autoscale --help로 확인).

명령 한 줄이면 대부분 끝나지만, autoscaling/v2 YAML을 직접 써야 하는 문제라면 공식 HorizontalPodAutoscaler Walkthrough에서 매니페스트를 복사해 오는 게 정석이다.

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
HPA 가 현재 개수 × 현재지표 / 목표지표 를 올림해 목표 replicas 를 정하고 tolerance 로 진동을 막는 계산

목표 개수 = ceil( 현재 개수 × (현재 지표 / 목표 지표) )

예: 현재 3개, CPU 평균 사용률 90%, 목표 70% → 3 × (90 / 70) = 3.86 → 올림 → 4개

  • 비율이 0.9~1.1 사이면 움직이지 않는다 (tolerance) — 진동 방지
  • 기본 15초마다 평가한다 (컨트롤러 매니저의 --horizontal-pod-autoscaler-sync-period)
터미널 창
kubectl get hpa
# NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
# web Deployment/web cpu: 45%/70% 2 10 3 5m
HPA 의 TARGETS 표시가 정상 · unknown · none 일 때 각각 무엇을 확인해야 하는지
TARGETS 표시뜻
45%/70%정상 동작 중
<unknown>/70%메트릭을 못 읽는다 — metrics-server 또는 requests 누락
<none>대상 워크로드를 못 찾는다
터미널 창
kubectl describe hpa web # Conditions 와 Events 를 본다
# Conditions:
# AbleToScale True ReadyForNewScale
# ScalingActive True ValidMetricFound
# ScalingLimited False DesiredWithinRange

CPU 하나로는 안 잡히는 부하가 있다 — 메모리가 먼저 차는 워크로드, 큐 길이나 요청 수가 먼저 튀는 워크로드. 그래서 메트릭을 여러 개 걸 수 있다.

metrics:
- 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"
여러 메트릭의 계산 결과 중 가장 큰 값을 택해 확장하고 축소는 전부 여유가 있어야 한다는 규칙
  • 여러 메트릭이 있으면 각각 계산해서 가장 큰 값을 택한다
  • 즉 하나라도 넘치면 늘어난다. 축소는 전부 여유가 있어야 한다
  • type: Pods 같은 커스텀 메트릭은 adapter가 있어야 돌아간다 — 깊게 팔 필요는 없다. 시험 대비로는 Resource(CPU·메모리) 메트릭이면 충분하다

계산식대로만 움직이면 지표가 출렁일 때마다 replicas도 출렁인다 — 확장은 즉시가 좋지만, 축소가 성급하면 트래픽이 다시 튈 때 그대로 맞는다. behavior는 이 방향별 속도를 정한다.

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: 60
scaleUp 은 stabilizationWindow 0 으로 빠르게 scaleDown 은 300 으로 천천히 움직이고 selectPolicy Disabled 는 그 방향을 아예 막는다
  • 기본은 “빠르게 늘리고 천천히 줄인다” — 축소 안정화 창이 300초다
  • selectPolicy: Disabled 로 두면 그 방향으로는 아예 안 움직인다
  • 세부 필드까지 외울 항목은 아니다 — 기본값의 방향성(빠른 확장·느린 축소)이 핵심이다
  • kubectl autoscale에는 behavior를 넣는 옵션이 없다. 뼈대를 --dry-run=client -o yaml로 뽑아 spec.behavior를 직접 더한다 — 실전 과제에서 연습한다

시험 비중 낮음 둘 다 기본 내장이 아니라 별도 설치물이라 시험 클러스터에 없다. 설치·설정을 묻는 문제로 나오기는 어렵고, “이 상황에 무엇이 필요한가”를 가르는 데 쓴다 — Pod이 부족하면 HPA, Pod 하나가 작으면 VPA, 노드가 부족하면 CA.

  • Pod의 requests/limits를 자동 조정
  • 별도 설치(CRD). 기본 내장이 아니다
  • 모드(updateMode): Off — 계산만 하고 추천값을 status에 적어둔다(사람이 보고 반영), Initial — Pod이 새로 생길 때만 값을 넣는다, Auto — 실행 중인 Pod에도 적용한다
  • 예전에는 적용에 Pod 재생성이 필요했다 → in-place resize(v1.35 GA) 로 개선되는 중 (Pod)
HPA 가 붙은 Deployment 를 kubectl scale 로 바꿔도 다음 평가 주기에 계산값으로 되돌아가고 HPA 삭제나 minReplicas 변경만 유지되는 흐름

HPA는 scale 서브리소스가 있는 리소스면 무엇이든 대상이 된다 — Deployment, ReplicaSet, StatefulSet. DaemonSet은 안 된다(개수를 노드가 정하므로).

scale 서브리소스는 “개수만 읽고 쓰는 전용 창구”다 (/apis/apps/v1/.../web/scale). HPA는 대상이 Deployment인지 StatefulSet인지 몰라도 이 창구로 replicas만 바꾸면 된다 — 그래서 커스텀 리소스(CRD)도 scale만 열어두면 HPA로 스케일된다.

  • HPA = Pod 개수, VPA = Pod 크기, Cluster Autoscaler = 노드 개수
  • metrics-server가 없으면 kubectl top도 HPA도 죽는다. 이것부터 확인
  • 계산식: ceil(현재 × 현재지표/목표지표), 0.9~1.1은 무시(tolerance)
  • averageUtilization은 requests 기준. requests가 없으면 <unknown>
  • 여러 메트릭이면 가장 큰 결과를 택한다
  • 기본 동작은 빠른 확장 / 5분 안정화 후 축소
  • HPA가 있으면 kubectl scale은 무의미하다