infra
Platform

모듈 맵

[Kubernetes] HPA(Horizontal Pod Autoscaler) 메트릭 기반 파드 확장

0 / 29 완료

펼치기
0 / 29 완료0%

쿠버네티스 & GitOps · 12 / 29

[Kubernetes] HPA(Horizontal Pod Autoscaler) 메트릭 기반 파드 확장

CPU 사용률 기반으로 파드 수를 자동으로 늘리고 줄이는 HPA를 구성합니다

🚨INCIDENT ALERT
HIGH

이벤트 페이지 트래픽이 평소의 10배로 뛰자 운영팀이 수동으로 kubectl scale을 반복하고 있습니다. 사람의 판단 속도로는 급격한 부하 변화와 야간 트래픽을 안정적으로 따라가기 어렵습니다. HPA는 메트릭을 기준으로 Pod 수를 자동 조절해 온콜 부담을 줄입니다.

블랙프라이데이 당일 오전 10시, 이벤트 페이지에 트래픽이 몰리기 시작했습니다. 평소의 10배 요청이 들어오는데 파드는 3개뿐이고 응답 시간은 계속 늘어납니다. 팀원이 수동으로 kubectl scale deployment를 실행해 파드를 20개로 늘렸지만, 5시간 뒤 트래픽이 줄었을 때는 다시 수동으로 줄여야 했습니다. 만약 HPA가 설정되어 있었다면 이 모든 과정이 자동으로 일어났을 겁니다.

HPA(Horizontal Pod Autoscaler)는 파드의 리소스 사용량이나 커스텀 메트릭을 기반으로 Deployment나 ReplicaSet의 파드 수를 자동으로 조절합니다. CPU 사용률이 목표값을 넘으면 파드를 추가하고, 내려가면 줄입니다. 이 자동화가 없으면 운영팀은 항상 모니터링 화면 앞에 붙어 있어야 하며, 새벽에도 알람에 반응해야 합니다. HPA는 "트래픽에 알아서 대응하는 시스템"을 만드는 첫 번째 단계입니다.

이번 챕터에서 배울 것
  • 1metrics-server를 설치하고 동작 원리를 설명할 수 있다
  • 2kubectl autoscale과 YAML로 HPA 리소스를 생성할 수 있다
  • 3스케일 업·다운 동작 과정을 이해할 수 있다
  • 4HPA 상태를 읽고 트러블슈팅할 수 있다
  • 5안정화 윈도우와 스케일링 정책을 커스텀할 수 있다
  • 6메모리 기반 스케일링과 커스텀 메트릭을 적용할 수 있다
실습 환경 준비
metrics-server 설치 확인
kubectl get deployment metrics-server -n kube-system 2>/dev/null || echo 'NOT INSTALLED'
metrics-server 설치 (검토한 고정 릴리스만)
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.7.2/components.yaml
노드 메트릭 수집 확인 (30초 대기)
kubectl top nodes
실습용 네임스페이스 생성
kubectl create namespace hpa-demo
💡개념

metrics-server: HPA의 눈

HPA를 만들었는데 kubectl get hpa에서 TARGETS가 계속 <unknown>/50%로 표시된다면, metrics-server가 없기 때문입니다. HPA는 스케일링 결정을 내리기 위해 실시간 CPU 사용량이 필요하지만 그 데이터를 스스로 수집하지 않습니다. metrics-server가 각 노드의 kubelet에서 리소스 사용량을 수집하고 Metrics API로 제공해야 비로소 HPA가 동작합니다. 이 의존 관계를 모르면 HPA 설정은 올바른데 왜 스케일이 안 되는지 원인을 찾지 못합니다.

HPA 제어 루프 — Pod 사용량을 kubelet/cAdvisor가 수집→metrics-server가 Metrics API로 집계→HPA Controller가 15초마다 필요 파드 수 = ceil(현재파드수×현재사용률/목표사용률) 계산→Deployment replicas 조정. metrics-server 미설치·CPU requests 미설정 시 TARGETS가 unknown으로 동작 불가확대

파드 → kubelet(cAdvisor) → metrics-server → Metrics API → HPA 컨트롤러
Kubernetes
# metrics-server 설치 (로컬 클러스터에서는 TLS 검증 비활성화 필요할 수 있음)
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.7.2/components.yaml

# 로컬 Kind/Minikube 클러스터용: TLS 검증 비활성화 패치
kubectl patch deployment metrics-server -n kube-system \
  --type='json' \
  -p='[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]'

# 설치 확인 (30초~1분 소요)
kubectl rollout status deployment/metrics-server -n kube-system

# 메트릭 수집 확인
kubectl top nodes
# NAME          CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
# kind-worker   55m          1%     512Mi           26%

kubectl top pods -A
# NAMESPACE     NAME                     CPU(cores)   MEMORY(bytes)
# kube-system   coredns-xxx              5m           18Mi
🔍실행 후 확인할 것
  • kubectl get hpa에서 TARGETS 열 먼저 확인 — "5%/50%" 형식이면 정상(현재/목표), "<unknown>/50%"이면 metrics-server 미설치 또는 파드에 CPU requests 미설정
  • REPLICAS 수치 기준: minReplicas 이상 maxReplicas 이하여야 정상. 부하 중에도 maxReplicas에 고정되면 노드 리소스 부족으로 더 이상 스케일 불가 — kubectl describe node로 Allocatable 확인
  • TARGETS 사용률이 목표치 초과인데 REPLICAS가 안 늘면 → HPA 스케일 업 쿨다운(기본 3분) 중이거나 maxReplicas 도달. kubectl describe hpa <name>의 Events에서 "SuccessfulRescale" 또는 "DesiredReplicas" 메시지로 판단

부하에 따라 파드 수가 자동으로 조정되는 원리

💡개념

부하가 오르면 파드 수가 자동으로 느는 법 — HPA 제어 루프 6단계

HPA를 걸어 두면 트래픽이 몰릴 때 파드가 알아서 늘고, 빠지면 줄어듭니다. 하지만 이건 마법이 아니라 기본 15초마다 도는 제어 루프의 결과입니다 — 메트릭을 읽고, 공식으로 필요한 파드 수를 계산하고, 범위로 자른 뒤, Deployment의 replicas를 고쳐 씁니다. 이 루프의 각 단계를 알면 "왜 안 늘지", "목표를 넘었는데 왜 그대로지"를 정확한 지점에서 진단할 수 있습니다.

TEXT
[HPA 컨트롤러]  기본 15초 주기(--horizontal-pod-autoscaler-sync-period)
   │
   ① metrics-server에서 대상 파드들의 CPU/메모리 수집
   │      metrics-server 없으면 여기서 실패 → TARGETS 가 unknown
   │
   ② 사용률 = 현재 사용량 / 파드의 resources.requests
   │      requests 없으면 분모가 없어 계산 불가 → 역시 unknown
   │
   ③ desiredReplicas = ceil(현재 replica × 현재값 / 목표값)
   │      (목표 대비 ±10% 관용 구간이면 그대로 둠)
   │
   ④ min/max로 클램프 → minReplicas ≤ 결과 ≤ maxReplicas
   │
   ⑤ 스케일 업: 즉시 반영 / 스케일 다운: 안정화 윈도우(기본 5분) 후 반영
   │
   ⑥ Deployment 의 spec.replicas 갱신 → ReplicaSet이 파드 증감
   ▼
[결과]  파드 수가 목표 사용률에 수렴 (노드가 아니라 '파드 수'를 조정)

각 단계에서 무슨 일이 일어나고, 막히면 어떤 증상인가:

단계하는 일여기서 막히면
① 메트릭 수집15초마다 Metrics API로 대상 파드의 실제 사용량을 읽는다metrics-server 미설치·비정상이면 수집 실패 → TARGETS가 <unknown>/50%로 굳고 스케일 불가
② 사용률 계산사용량을 파드의 requests로 나눠 퍼센트를 낸다requests 미설정이면 분모가 없어 계산 불가 → 역시 <unknown>. requests가 너무 낮으면 사용률이 부풀려져 과잉 확장
③ 목표 수 계산ceil(현재 replica × 현재값/목표값)으로 필요 수 산출목표 대비 ±10%(관용) 안이면 무반응 — 목표 50%에 52%는 그대로 둔다
④ 범위 클램프min·max 사이로 자른다부하가 높아도 maxReplicas에 닿으면 더 못 늘림 → maxReplicas 도달 알람이 필요
⑤ 방향별 타이밍업은 즉시, 다운은 안정화 윈도우로 지연부하가 빠졌는데 파드가 안 주는 건 정상 — 5분 관찰 후 축소(flapping 방지)
⑥ replicas 갱신계산 결과를 Deployment에 써서 파드를 늘리고 줄인다노드 자원이 부족하면 새 파드가 Pending — HPA는 파드 수만 늘릴 뿐 노드는 못 늘림

핵심은 HPA가 조정하는 대상이 '노드'가 아니라 '파드 수'라는 것입니다 — 사용률이 목표를 넘으면 파드를 더 찍어내지만, 그 파드를 올릴 노드 여유가 없으면 새 파드는 Pending에 걸립니다. 노드까지 자동으로 늘리는 건 HPA가 아니라 Cluster Autoscaler의 몫입니다. 그리고 이 계산의 두 축 — metrics-server(수집)와 resources.requests(사용률의 분모) — 중 하나만 없어도 루프는 ①②에서 <unknown>으로 멈춥니다.

진단은 루프의 입력부터. kubectl get hpa로 TARGETS가 <unknown>인지 실제 값인지 보고(입력이 들어오는지 판정), <unknown>이면 metrics-server 상태와 파드 requests를 확인합니다. 값은 정상인데 REPLICAS가 기대와 다르면 kubectl describe hpa의 Events에서 SuccessfulRescale·목표 계산 로그와 안정화 윈도우 대기를 읽고, kubectl top pod로 HPA가 본 실제 사용량이 맞는지 대조합니다.

💡개념

HPA 생성: 기본 CPU 기반 스케일링

이벤트 트래픽이 몰릴 것을 예상해 HPA를 미리 설정했는데 막상 부하가 들어와도 파드가 늘어나지 않는다면, CPU requests가 설정되지 않았을 가능성이 높습니다. HPA는 "현재 CPU 사용량 / CPU requests"로 사용률을 계산하는데 requests가 없으면 비율 계산 자체가 불가능합니다. 반대로 requests가 너무 낮게 설정되면 실제 부하가 낮아도 HPA가 과도하게 스케일 업해 비용이 낭비됩니다. HPA 설정 시 minReplicas, maxReplicas, 목표 사용률을 서비스 특성에 맞게 조율하는 것이 실무 운영의 핵심입니다.

HPA 스케일 아웃/인 — CPU 사용률이 목표(예: 50%)를 초과하면 파드를 늘리고(scale-out), 낮아지면 줄임(scale-in). 스케일 업은 즉시 반응, 스케일 다운은 기본 5분 안정화 윈도우로 flapping(파드 반복 증감)을 방지. minReplicas/maxReplicas로 범위 제한확대

YAML
# php-apache-deployment.yaml
# 부하 테스트에 자주 쓰이는 예시 이미지
apiVersion: apps/v1
kind: Deployment
metadata:
  name: php-apache
  namespace: hpa-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: php-apache
  template:
    metadata:
      labels:
        app: php-apache
    spec:
      containers:
      - name: php-apache
        image: registry.k8s.io/hpa-example
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: "200m"    # HPA 계산 기준값 (필수!)
            memory: "128Mi"
          limits:
            cpu: "500m"
            memory: "256Mi"
---
apiVersion: v1
kind: Service
metadata:
  name: php-apache
  namespace: hpa-demo
spec:
  ports:
  - port: 80
  selector:
    app: php-apache
Kubernetes
kubectl apply -f php-apache-deployment.yaml

# 방법 1: kubectl autoscale (빠른 생성)
kubectl autoscale deployment php-apache \
  -n hpa-demo \
  --cpu-percent=50 \
  --min=1 \
  --max=10

# 방법 2: YAML로 생성 (권장, GitOps 관리 가능)
cat <<EOF | kubectl apply -f -
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache-hpa
  namespace: hpa-demo
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50   # CPU 사용률 50% 목표
EOF

# HPA 상태 확인
kubectl get hpa -n hpa-demo
# NAME              REFERENCE              TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
# php-apache-hpa    Deployment/php-apache   3%/50%    1         10        1          30s

TARGETS 컬럼 읽는 법: 현재사용률/목표사용률. 3%/50%는 현재 3%를 쓰고 있고 목표는 50%라는 의미입니다.

💡개념

스케일링 동작 과정과 안정화 윈도우

트래픽이 잠깐 치솟았다 내려갈 때마다 파드가 늘었다 줄었다를 반복하면 파드 시작/종료 오버헤드가 오히려 서비스 안정성을 해칩니다. 이 "플래핑" 문제를 막기 위해 HPA는 스케일 다운에 기본 5분 안정화 윈도우를 적용합니다. 스케일 업은 즉각 반응해야 하지만 스케일 다운은 신중해야 한다는 운영 원칙이 반영된 설계입니다. 안정화 윈도우와 스케일링 정책을 커스텀하면 서비스 특성에 맞는 민감도를 조율할 수 있습니다.

필요 파드 수 = ceil(현재파드수 × (현재사용률 / 목표사용률))

예: 파드 1개, 현재 CPU 150%, 목표 50%
→ ceil(1 × (150 / 50)) = ceil(3) = 3개

스케일 다운이 느린 이유는 안정화 윈도우 때문입니다.

YAML
# 스케일링 정책 커스텀
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache-hpa-custom
  namespace: hpa-demo
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache
  minReplicas: 2    # 최소 2개 유지 (HA 보장)
  maxReplicas: 20
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 60
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 0   # 즉시 스케일 업
      policies:
      - type: Percent
        value: 100                    # 한 번에 최대 100% 증가
        periodSeconds: 15
    scaleDown:
      stabilizationWindowSeconds: 300 # 5분 안정화 후 스케일 다운
      policies:
      - type: Pods
        value: 2                      # 한 번에 최대 2개씩 감소
        periodSeconds: 60

실습: 부하 테스트로 HPA 동작 확인

로컬 터미널
# 터미널 1: HPA 상태 실시간 모니터링
watch kubectl get hpa php-apache-hpa -n hpa-demo

# 터미널 2: 부하 생성 (무한 HTTP 요청)
kubectl run load-generator \
  --image=busybox:1.36 \
  --restart=Never \
  -n hpa-demo \
  -- /bin/sh -c "while true; do wget -q -O- http://php-apache.hpa-demo.svc.cluster.local; done"

# 터미널 1에서 변화 관찰 (약 1-2분 소요)
# NAME              REFERENCE              TARGETS    MINPODS   MAXPODS   REPLICAS
# php-apache-hpa    Deployment/php-apache   3%/50%    1         10        1
# php-apache-hpa    Deployment/php-apache   142%/50%  1         10        1    ← 급등
# php-apache-hpa    Deployment/php-apache   142%/50%  1         10        3    ← 스케일 업
# php-apache-hpa    Deployment/php-apache   72%/50%   1         10        4
# php-apache-hpa    Deployment/php-apache   53%/50%   1         10        5

# 파드 수 변화 확인
kubectl get pods -n hpa-demo -w

# 부하 중단 (터미널 2에서) — 아래 DangerBlock 확인 후 실행
위험 명령어이 명령은 의도적으로 부하를 멈추는 정리 단계입니다. 그러나 현재 컨텍스트가 실수로 프로덕션을 가리키고 있다면 동일 이름의 파드를 삭제할 수 있습니다. 부하 파드가 삭제된 후에도 HPA는 약 5분간의 안정화 윈도우를 기다리므로 즉시 스케일 다운되지 않습니다.

부하 생성 파드 삭제 — HPA 스케일 다운 트리거

안전한 실행 조건: kubectl config current-context 로 개발 클러스터인지 확인. kubectl get pod -n hpa-demo 로 load-generator 파드가 실습용인지 확인 후 실행하세요.

실행 전 반드시 확인

  • kubectl config current-context 로 현재 컨텍스트가 개발 클러스터(minikube 등)인지 확인
  • kubectl get pod load-generator -n hpa-demo 로 삭제 대상 파드 확인
kubectl delete pod load-generator -n hpa-demo

위 항목을 모두 확인한 후 복사할 수 있습니다

Kubernetes
kubectl delete pod load-generator -n hpa-demo

# 약 5분 후 파드가 다시 줄어듦 (안정화 윈도우)
# 스케일 다운 이벤트 확인
kubectl describe hpa php-apache-hpa -n hpa-demo | grep -A 5 "Events"

HPA를 만들었는데 며칠이 지나도 파드 수가 변하지 않습니다. kubectl get hpa 결과를 보면 TARGETS 컬럼이 <unknown>/50%로 표시됩니다.

Kubernetes
# 증상 확인
kubectl get hpa -n hpa-demo
# NAME              REFERENCE              TARGETS         MINPODS   MAXPODS   REPLICAS
# php-apache-hpa    Deployment/php-apache   <unknown>/50%  1         10        1

# 1단계: HPA 이벤트 확인
kubectl describe hpa php-apache-hpa -n hpa-demo | tail -20
# Events:
#   Warning  FailedGetResourceMetric  2m  horizontal-pod-autoscaler
#            unable to get metrics for resource cpu: unable to fetch metrics from resource metrics API

# 2단계: metrics-server 설치 여부 확인
kubectl get pods -n kube-system | grep metrics-server
# (아무 출력도 없음 — 미설치)

# 또는 설치는 됐지만 비정상
# metrics-server-xxx   0/1   CrashLoopBackOff   5   10m

# 3단계-A: metrics-server 설치
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.7.2/components.yaml

# 3단계-B: 로컬 클러스터(Kind/Minikube)라면 TLS 패치 추가
kubectl patch deployment metrics-server -n kube-system \
  --type='json' \
  -p='[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]'

# 4단계: metrics-server 정상화 확인 (1-2분 소요)
kubectl rollout status deployment/metrics-server -n kube-system

kubectl top nodes   # 이게 나와야 정상
# NAME          CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%

# 5단계: HPA 상태 재확인
kubectl get hpa -n hpa-demo
# NAME              REFERENCE              TARGETS   MINPODS   MAXPODS   REPLICAS
# php-apache-hpa    Deployment/php-apache   3%/50%   1         10        1
# ↑ <unknown>가 실제 값으로 바뀜

# 추가: requests 미설정 케이스
# 만약 metrics-server는 정상인데 여전히 unknown이면
kubectl get pod -n hpa-demo -o jsonpath='{.items[0].spec.containers[0].resources}'
# {}  ← requests가 없음! CPU requests를 설정해야 HPA가 동작함

원인 요약: HPA의 <unknown> 문제는 99%가 (1) metrics-server 미설치/비정상, (2) 파드에 CPU requests 미설정, 이 두 가지입니다. 두 가지를 순서대로 확인하면 빠르게 해결됩니다.

심화 — HPA는 '즉시'가 아니다: 지연 사슬과 관측 반응

💡개념

심화: HPA가 늦게 반응하는 이유 — 지연 사슬·관용·준비성

metrics-server가 붙고 공식대로 계산돼도 HPA가 부하 급증에 곧바로 반응하는 건 아닙니다. HPA는 미래를 예측하는 게 아니라 관측한 값에 반응하는 제어 루프라, 그 반응까지 여러 단계의 지연이 겹칩니다. 이 지연의 출처를 알아야 스파이크성 트래픽에서 HPA만 믿다 낭패 보지 않습니다.

  • 지연 사슬: 컨테이너가 CPU를 태움 → kubelet/cAdvisor가 표본을 모음 → metrics-server가 수십 초 해상도로 집계 → HPA 컨트롤러가 기본 15초 주기로 읽어 계산 → 새 파드가 스케줄·이미지 풀·기동·Ready. 이 사슬 전체가 더해져 급증 시점부터 실제 처리 능력이 늘 때까지 1~2분 이상 걸릴 수 있습니다. HPA는 "즉시"가 아닙니다.
  • 관용(tolerance): 목표 대비 실제 비율이 기본 ±10% 안이면 HPA는 아무것도 하지 않습니다. 목표 50%에서 52%는 그대로 둡니다. 자잘한 변동에 출렁이지 않게 만든 의도된 무반응 구간입니다.
  • 준비성 게이팅: 아직 Ready가 아니거나 방금 뜬 파드는 평균 계산에서 제외·보정됩니다. 덕분에 콜드스타트 CPU 스파이크가 곧장 과잉 스케일업으로 번지진 않지만, 반대로 CPU requests를 너무 낮게 잡으면 사용률이 부풀려져 과잉 확장이 날 수 있습니다.
  • 메모리 기반 HPA의 함정: 많은 런타임이 한 번 늘어난 힙을 OS에 잘 반환하지 않아, 부하가 빠져도 메모리 사용률이 잘 안 내려갑니다. 그래서 memory 타깃 HPA는 축소가 거의 안 일어나기도 합니다 — 확장 트리거로는 CPU나 커스텀 지표가 대체로 더 낫습니다.

정리하면 HPA는 "예측"이 아니라 "관측 후 반응"입니다. 예고된 급증(정산·오픈런)은 HPA에만 맡기지 말고 minReplicas 상향이나 예약 스케일링으로 미리 바닥을 높여 둡니다.

상황: 이벤트 오픈 순간 요청이 10배로 뛰었습니다. HPA는 정상 설정돼 있었지만, 초반 1~2분간 기존 파드가 포화돼 타임아웃·5xx가 터졌고, 파드 증설은 그 사태가 한창일 때 뒤늦게 시작됐습니다.

원인: HPA는 관측 기반 반응 루프라 본질적으로 지연이 있습니다. 메트릭 수집·집계·15초 주기 계산에 더해, 새 파드가 스케줄→이미지 풀→기동→Ready가 되어 실제로 트래픽을 받기까지 또 시간이 걸립니다. "급증 시점"과 "증설된 용량이 실제로 도는 시점" 사이의 이 공백에 장애가 난 것입니다. HPA 설정 자체엔 문제가 없었습니다.

진단: kubectl describe hpa의 이벤트 타임스탬프와 요청 급증 시각을 겹쳐 봅니다. 급증 후 첫 스케일업 이벤트까지의 간격, 그리고 새 파드가 Ready가 된 시각까지의 추가 간격을 각각 재면 지연이 "감지"에서 왔는지 "기동"에서 왔는지 나뉩니다. 이미지 풀 시간과 프로브 initialDelaySeconds도 함께 확인합니다.

해결: 예고된 급증은 HPA에만 의존하지 않습니다 — 이벤트 전 minReplicas를 미리 올리거나(수동·예약) 바닥 용량을 확보합니다. scaleUp behavior를 더 공격적으로(짧은 periodSeconds·큰 percent 정책) 잡아 반응을 앞당기고, 이미지 프리풀·가벼운 기동·적절한 readiness로 새 파드가 빨리 트래픽을 받게 합니다. 근본적으로 CPU보다 앞서 움직이는 선행 지표(대기열 길이·초당 요청 수)가 있으면 그걸 커스텀 지표로 삼아 더 일찍 늘립니다.

💼
실무 맥락
현업 패턴

시나리오: 프로덕션 API 서버에 HPA 도입

월말 정산이 있는 서비스를 운영 중입니다. 평소에는 파드 3개로 충분한데 매월 1일 새벽에 트래픽이 10배 이상 몰려 수동으로 스케일을 조절하고 있습니다. HPA로 이 작업을 자동화하려고 합니다.

Kubernetes
# 1단계: 현재 리소스 설정 확인 및 requests 추가
kubectl get deployment api-server -n production \
  -o jsonpath='{.spec.template.spec.containers[0].resources}'

# requests가 없다면 먼저 추가
kubectl set resources deployment/api-server \
  -n production \
  --requests=cpu=200m,memory=256Mi \
  --limits=cpu=1000m,memory=512Mi

# 2단계: HPA 생성 (YAML 파일로 관리 권장)
cat <<EOF > api-hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-server-hpa
  namespace: production
  annotations:
    description: "월말 정산 트래픽 대응용 HPA"
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-server
  minReplicas: 3    # 평소 최솟값 (HA)
  maxReplicas: 30   # 월말 최대 예상 × 1.5
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 60
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 60   # 1분 안정화 후 스케일 업
    scaleDown:
      stabilizationWindowSeconds: 600  # 10분 안정화 후 스케일 다운
EOF

kubectl apply -f api-hpa.yaml

# 3단계: 월말 이벤트 전 부하 테스트로 스케일링 검증
kubectl run load-test \
  --image=grafana/k6 \
  --restart=Never \
  -n production \
  -- run - <<'K6SCRIPT'
import http from 'k6/http';
export let options = { vus: 100, duration: '5m' };
export default function() { http.get('http://api-server/health'); }
K6SCRIPT

watch kubectl get hpa api-server-hpa -n production

# 4단계: 알람 설정 (HPA가 maxReplicas에 도달하면 알람)
# Prometheus AlertManager 또는 클라우드 알람으로 설정
# kube_horizontalpodautoscaler_status_current_replicas == kube_horizontalpodautoscaler_spec_max_replicas

실무 포인트: maxReplicas에 도달하면 HPA는 더 이상 스케일 업을 못 합니다. 이 상황이 되면 사람이 개입해야 하므로, maxReplicas 도달 시 알람을 반드시 설정해두세요. Cluster Autoscaler와 함께 사용하면 노드 자체도 자동으로 늘릴 수 있습니다.

실습 단계
1

metrics-server 설치 및 동작 확인

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.7.2/components.yaml kubectl rollout status deployment/metrics-server -n kube-system kubectl top nodes

예상 출력

NAME          CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
minikube      120m         3%     800Mi           41%
2

CPU requests가 설정된 Deployment 배포

kubectl create namespace hpa-demo kubectl apply -f - <<EOF apiVersion: apps/v1 kind: Deployment metadata: name: php-apache namespace: hpa-demo spec: replicas: 1 selector: matchLabels: app: php-apache template: metadata: labels: app: php-apache spec: containers: - name: php-apache image: registry.k8s.io/hpa-example resources: requests: cpu: '200m' EOF kubectl get deployment php-apache -n hpa-demo

예상 출력

NAME         READY   UP-TO-DATE   AVAILABLE   AGE
php-apache   1/1     1            1           15s
3

HPA 생성 및 상태 확인

kubectl autoscale deployment php-apache \ -n hpa-demo \ --cpu-percent=50 \ --min=1 \ --max=10 kubectl get hpa -n hpa-demo

예상 출력

NAME              REFERENCE              TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
php-apache        Deployment/php-apache   3%/50%    1         10        1          30s
4

부하 생성으로 스케일 업 트리거

kubectl run load-generator \ --image=busybox:1.36 --restart=Never -n hpa-demo \ -- /bin/sh -c 'while true; do wget -q -O- http://php-apache.hpa-demo.svc.cluster.local; done' sleep 90 kubectl get hpa -n hpa-demo

예상 출력

NAME         REFERENCE              TARGETS     MINPODS   MAXPODS   REPLICAS
php-apache   Deployment/php-apache   142%/50%    1         10        3
5

부하 제거 후 스케일 다운 확인 (약 5분 소요)

kubectl delete pod load-generator -n hpa-demo kubectl describe hpa php-apache -n hpa-demo | grep -A5 'Events'

예상 출력

Events:
  Normal  SuccessfulRescale  5m   horizontal-pod-autoscaler  New size: 1; reason: All metrics below target

핵심 요약

항목설명
HPA 전제 조건metrics-server 설치 + 파드에 CPU requests 설정
스케일 업즉각 반응 (stabilizationWindowSeconds: 0 권장)
스케일 다운기본 5분 대기 (flapping 방지)
TARGETS: unknownmetrics-server 미설치 or requests 미설정
minReplicasHA를 위해 최소 2 이상 권장
maxReplicas노드 용량 + 비용 고려해 현실적으로 설정

명령어·단축키 빠른 참조

이 모듈에서 다룬 HPA·metrics-server 관련 kubectl 명령을 실전 옵션과 함께 모았습니다.

명령어/단축키용도자주 쓰는 예
kubectl autoscale빠르게 HPA 생성kubectl autoscale deploy php-apache --cpu-percent=50 --min=1 --max=10
kubectl get hpaTARGETS(현재/목표)·REPLICAS 확인kubectl get hpa -n hpa-demo (unknown이면 metrics/requests 문제)
kubectl describe hpa스케일 이벤트·실패 원인kubectl describe hpa php-apache | grep -A5 Events
kubectl top노드·파드 실제 사용량kubectl top nodes, kubectl top pods -A
kubectl set resourcesrequests/limits 설정(HPA 전제)kubectl set resources deploy/api --requests=cpu=200m,memory=256Mi
kubectl rollout statusmetrics-server 기동 대기kubectl rollout status deploy/metrics-server -n kube-system
kubectl patch deploymentmetrics-server TLS 검증 끄기(로컬)... --type=json -p='[{"op":"add",...,"value":"--kubelet-insecure-tls"}]'
watch kubectl get hpa스케일 동작 실시간 관찰watch kubectl get hpa php-apache-hpa -n hpa-demo
kubectl get pods -w파드 증감 실시간 추적kubectl get pods -n hpa-demo -w
kubectl apply -f (autoscaling/v2)behavior 등 세밀 HPA(GitOps)kubectl apply -f api-hpa.yaml (scaleUp/scaleDown 커스텀)

관련 모듈로 더 깊이:

다음 모듈 vpa-autoscaling에서는 파드 수가 아닌 CPU·메모리 크기를 자동으로 조정하는 VPA를 다룹니다. HPA와의 차이점, Off/Auto 모드 선택 기준, HPA와 병행 사용 시 충돌을 피하는 설정을 익힙니다.

지식 확인

퀴즈 — 8문제

Q1

HPA가 동작하기 위한 필수 전제 조건은 무엇인가?

Q2

HPA의 스케일 다운이 스케일 업보다 천천히 동작하는 이유는?

Q3

kubectl get hpa 출력에서 TARGETS 컬럼이 '<unknown>/50%'로 표시된다면 가장 먼저 확인해야 할 것은?

Q4

트래픽이 잠깐 떨어졌다 다시 오르는데 HPA가 파드를 즉시 줄이지 않는다. 이 동작의 이름과 이유는?

Q5

HPA의 targetCPUUtilization이 50%이고 현재 파드 2개의 평균 CPU가 90%다. HPA는 대략 몇 개로 스케일하려 하는가?

Q6

로컬 Kind/Minikube에서 metrics-server를 설치했는데 kubectl top nodes가 동작하지 않는다. 본문이 언급한 흔한 원인은?

Q7

[심화] HPA와 metrics-server 설정이 모두 정상인데도 트래픽이 순간 급증하면 HPA 대응이 항상 몇십 초에서 몇 분 늦다. 이 지연의 근본 성격으로 가장 정확한 것은?

Q8

[심화] 정산일마다 트래픽이 10배로 튀는데 그 첫 1~2분에 HPA 증설이 늦어 5xx가 난다. HPA 설정 자체는 정상이다. 가장 효과적인 대비책은?

0 / 8 답변

🧪 실습으로 확인하기

HPA — CPU 기반 오토스케일링

중급

Horizontal Pod Autoscaler(HPA)를 구성해 CPU 사용량이 70%를 초과할 때 Pod를 자동으로 늘리고, 부하가 줄면 다시 줄이는 오토스케일링 동작을 직접 확인한다.

45📋 4단계💻 직접 환경
실습 시작하기 →

이것도 배워보세요