Post

[Kubernetes] HPA 완전 정리: Pod 오토스케일링 메커니즘과 실무 패턴

HPA (Horizontal Pod Autoscaler)

1. 개요

한 줄 요약: CPU, 메모리 등 메트릭 기반으로 Pod 개수를 자동으로 조정하는 오토스케일링 시스템

언제 사용하나:

  • 트래픽 변동이 큰 애플리케이션 (주간/야간, 이벤트 대응)
  • 비용 최적화 (사용량에 따라 Pod 수 자동 조정)
  • 장애 대응 (부하 급증 시 자동 스케일 아웃)
  • SLA 보장 (응답 시간 유지를 위한 리소스 확보)

관련 기술: Deployment, ReplicaSet, Metrics Server, Prometheus, Custom Metrics


2. 핵심 개념

2.1. HPA 동작 방식

1
Metrics Server → 메트릭 수집 → HPA 계산 → Deployment replicas 조정 → Pod 증가/감소

2.2. 스케일링 공식

1
desiredReplicas = ceil[currentReplicas * (currentMetricValue / targetMetricValue)]

예시:

  • 현재 replicas: 3
  • 현재 CPU 사용률: 80%
  • 목표 CPU 사용률: 50%
  • desiredReplicas = ceil[3 * (80 / 50)] = ceil[4.8] = 5

2.3. 스케일링 조건

  • Scale Out: 현재 메트릭 > 목표값 × (1 + 임계값)
  • Scale In: 현재 메트릭 < 목표값 × (1 - 임계값)
  • 기본 임계값: 10% (targetValue의 ±10% 범위는 무시하여 불필요한 스케일링 방지)

2.4. 지원 메트릭 종류

메트릭 타입설명예시필요 사항
ResourceCPU, 메모리CPU 사용률 50%Metrics Server
PodsPod 메트릭HTTP 요청 수/secCustom Metrics API
Object객체 메트릭Ingress QPSCustom Metrics API
External외부 시스템 메트릭SQS 큐 길이External Metrics API

2.5. 주요 특징

  • 자동화: 수동 개입 없이 리소스 자동 조정
  • 안정성: Scale In 지연 (기본 5분)으로 플래핑 방지
  • 제한 설정: minReplicas, maxReplicas로 범위 제한
  • K8s 1.21: autoscaling/v2 API 사용 (CPU + 메모리 + 커스텀 메트릭 지원)

3. 기본 명령어

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# HPA 목록 확인
kubectl get hpa -n <namespace>

# HPA 상세 확인
kubectl describe hpa <hpa-name> -n <namespace>

# HPA 실시간 모니터링
kubectl get hpa <hpa-name> -n <namespace> --watch

# HPA 빠른 생성 (kubectl 명령어)
kubectl autoscale deployment <deployment-name> \
  --cpu-percent=50 \
  --min=2 \
  --max=10 \
  -n <namespace>

# HPA 이벤트 확인
kubectl get events -n <namespace> --field-selector involvedObject.name=<hpa-name>

# Metrics Server 동작 확인 (HPA 필수 의존성)
kubectl top nodes
kubectl top pods -n <namespace>

HPA 출력 예시:

1
2
3
4
5
NAME      REFERENCE            TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
web-hpa   Deployment/web-app   45%/50%   2         10        3          5d

# TARGETS: 현재값/목표값
# 45%/50% → 현재 CPU 45%, 목표 50% → 스케일링 불필요 상태

4. 실무 패턴

4.1. CPU 기반 HPA (가장 일반적)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-app-hpa
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-app
  minReplicas: 2    # 최소 Pod 수
  maxReplicas: 10   # 최대 Pod 수
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50  # 평균 CPU 50% 목표
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300  # 5분간 안정화 대기
      policies:
      - type: Percent
        value: 50          # 한 번에 50%까지만 감소
        periodSeconds: 60
      - type: Pods
        value: 2           # 한 번에 최대 2개 감소
        periodSeconds: 60
    scaleUp:
      stabilizationWindowSeconds: 0   # 즉시 스케일 아웃
      policies:
      - type: Percent
        value: 100         # 한 번에 100%까지 증가 가능
        periodSeconds: 15
      - type: Pods
        value: 4           # 한 번에 최대 4개 증가
        periodSeconds: 15

Deployment 리소스 설정 (필수):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 2  # HPA가 자동 조정하므로 초기값만 의미
  template:
    spec:
      containers:
      - name: app
        image: nginx:1.21
        resources:
          requests:
            cpu: 100m      # HPA는 requests 기준으로 사용률 계산
            memory: 128Mi
          limits:
            cpu: 200m
            memory: 256Mi

동작 시나리오:

1
2
3
4
1. 트래픽 증가 → CPU 사용률 70% (목표 50% 초과)
2. HPA 계산: ceil[2 * (70/50)] = 3 → replicas 2→3 증가
3. 트래픽 감소 → CPU 사용률 30% (목표 50% 미만)
4. 5분 대기 후 HPA 계산: ceil[3 * (30/50)] = 2 → replicas 3→2 감소

4.2. 메모리 기반 HPA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: memory-hpa
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: memory-app
  minReplicas: 3
  maxReplicas: 15
  metrics:
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 70  # 평균 메모리 70% 목표

메모리는 CPU보다 느리게 증가/감소하므로 OOM 발생 전에 스케일 아웃되도록 목표값을 70% 이하로 설정합니다.

4.3. CPU + 메모리 복합 메트릭

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: multi-metric-hpa
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-server
  minReplicas: 2
  maxReplicas: 20
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 60
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80

여러 메트릭이 설정된 경우 가장 높은 replicas 값을 선택합니다.

1
2
3
CPU 60% 기준 → replicas: 5
메모리 80% 기준 → replicas: 8
→ 결과: replicas 8 적용 (더 많은 리소스 확보)

4.4. 커스텀 메트릭 (HTTP 요청 수)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: custom-metric-hpa
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-app
  minReplicas: 2
  maxReplicas: 50
  metrics:
  - type: Pods
    pods:
      metric:
        name: http_requests_per_second
      target:
        type: AverageValue
        averageValue: "100"  # Pod당 평균 100 req/s 목표

Prometheus Adapter 설치 및 애플리케이션에서 http_requests_per_second 메트릭 노출이 필요합니다.

4.5. 외부 메트릭 (AWS SQS 큐 길이)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: sqs-hpa
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: worker
  minReplicas: 1
  maxReplicas: 100
  metrics:
  - type: External
    external:
      metric:
        name: sqs_queue_length
        selector:
          matchLabels:
            queue: my-queue
      target:
        type: AverageValue
        averageValue: "30"  # Pod당 처리할 메시지 수
1
2
SQS 큐에 300개 메시지 → 300 / 30 = replicas 10
메시지 소진 → replicas 1로 감소

4.6. 시간대별 최소 replicas 조정 (CronJob 활용)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# 주간 시간대 (09:00): minReplicas 증가
apiVersion: batch/v1
kind: CronJob
metadata:
  name: scale-up-morning
  namespace: default
spec:
  schedule: "0 9 * * 1-5"  # 평일 09:00
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: kubectl
            image: bitnami/kubectl:latest
            command:
            - /bin/sh
            - -c
            - |
              kubectl patch hpa web-app-hpa -n default \
                --type=merge -p '{"spec":{"minReplicas":5}}'
          restartPolicy: OnFailure
---
# 야간 시간대 (18:00): minReplicas 감소
apiVersion: batch/v1
kind: CronJob
metadata:
  name: scale-down-evening
  namespace: default
spec:
  schedule: "0 18 * * 1-5"  # 평일 18:00
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: kubectl
            image: bitnami/kubectl:latest
            command:
            - /bin/sh
            - -c
            - |
              kubectl patch hpa web-app-hpa -n default \
                --type=merge -p '{"spec":{"minReplicas":2}}'
          restartPolicy: OnFailure

5. 트러블슈팅

5.1. 실무 디버깅 순서

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Step 1: HPA 상태 확인
kubectl get hpa web-app-hpa -n default
# TARGETS: <unknown>/50% → 메트릭 수집 실패

# Step 2: Metrics Server 확인
kubectl top pods -n default
# Error from server → Metrics Server 재시작
kubectl rollout restart deployment metrics-server -n kube-system

# Step 3: Pod resources 확인
kubectl get pod -n default -o yaml | grep -A 5 "resources:"
# requests 없음 → Deployment 수정

# Step 4: HPA 재생성
kubectl delete hpa web-app-hpa -n default
kubectl apply -f hpa.yaml

# Step 5: 실시간 모니터링
kubectl get hpa web-app-hpa -n default --watch

5.2. 추가 디버깅 명령어

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# HPA 이벤트 확인
kubectl describe hpa <hpa-name> -n <namespace>
# Events:
#   Warning  FailedGetResourceMetric  unable to get metrics for resource cpu

# HPA 계산 결과 확인
kubectl get hpa <hpa-name> -n <namespace> -o yaml
# status:
#   currentMetrics: 현재 메트릭 값
#   desiredReplicas: 계산된 목표 replicas

# HPA가 Deployment를 제어하는지 확인
kubectl get deployment <deployment-name> -n <namespace> -o yaml | grep -A 3 replicas

# Metrics Server 로그 확인
kubectl logs -n kube-system deployment/metrics-server -f

5.3. 흔한 실수 7가지

1. 리소스 requests 미설정

1
2
3
4
5
6
7
❌ Deployment에 resources.requests 없음
→ HPA가 <unknown> 표시, 스케일링 안 됨

✅ 반드시 requests 설정
   resources:
     requests:
       cpu: 100m

2. Metrics Server 미설치

1
2
3
4
5
❌ kubectl top nodes 실행 안 됨
→ HPA 메트릭 수집 불가

✅ 설치 확인
   kubectl get deployment metrics-server -n kube-system

3. Deployment replicas 수동 변경

1
2
3
4
❌ HPA 사용 중 Deployment replicas를 직접 변경
→ HPA가 즉시 덮어써서 혼란 발생

✅ HPA 사용 시 minReplicas / maxReplicas만 조정

4. 목표값을 너무 낮게 설정

1
2
3
4
❌ CPU target: 20%
→ 항상 maxReplicas까지 증가

✅ 50~70% 권장 (버스트 대응 여유 확보)

5. Scale Down 속도 너무 빠름

1
2
3
4
❌ stabilizationWindowSeconds: 0 (scaleDown)
→ 트래픽 변동 시 Pod 생성/삭제 반복 (플래핑)

✅ 300초 (5분) 권장

6. minReplicas를 0으로 설정

1
2
3
4
❌ minReplicas: 0
→ Pod가 모두 종료되면 트래픽 처리 불가

✅ minReplicas: 1 이상 유지

7. HPA와 VPA 동시 사용

1
2
3
4
❌ 같은 Deployment에 HPA + VPA 동시 적용
→ 충돌 발생, 예측 불가능한 동작

✅ HPA 또는 VPA 중 하나만 사용 (HPA 권장)

6. 운영 참고사항

6.1. 권장 설정값

설정권장값이유
minReplicas2 이상가용성 확보
maxReplicas노드 수 × 3노드당 여유 공간
CPU target50~70%버스트 대응 여유
메모리 target70~80%OOM 방지
scaleDown stabilizationWindowSeconds300 (5분)플래핑 방지
scaleUp stabilizationWindowSeconds0빠른 대응

6.2. HPA vs VPA vs Cluster Autoscaler

도구역할권장 조합
HPAPod 개수 조정 (Horizontal)✅ 주 사용
VPAPod 리소스 크기 조정 (Vertical)실험적, HPA와 병행 불가
Cluster Autoscaler노드 개수 조정HPA와 함께 사용 권장

6.3. Prometheus 모니터링 쿼리

# HPA 현재 replicas 수
kube_horizontalpodautoscaler_status_current_replicas

# HPA 목표 replicas 수
kube_horizontalpodautoscaler_status_desired_replicas

# desired와 current가 10분 이상 다르면 알림
abs(kube_hpa_status_current_replicas - kube_hpa_status_desired_replicas) > 0

6.4. 금융권 환경 고려사항

  • 중요 서비스: minReplicas: 3 이상 (다중 AZ 배포 고려)
  • 이벤트 대비: maxReplicas를 평소의 3~5배로 설정
  • 야간 배치: HPA 비활성화 또는 minReplicas 축소 (CronJob 활용)
  • 커스텀 메트릭 활용: HTTP 요청 수, 큐 길이, DB 연결 수, 비즈니스 메트릭 (주문 수, 결제 건수)

6.5. HyperCloud 환경 참고

Metrics Server가 기본 설치되어 있어 별도 설치 없이 CPU/메모리 기반 HPA를 바로 사용할 수 있습니다. 커스텀 메트릭 사용 시에는 Prometheus Adapter 별도 설치가 필요합니다.


참고 자료

This post is licensed under CC BY 4.0 by the author.

Comments powered by Disqus.