Deployment에 HPA를 설정했는데 트래픽이 몰려도 Pod 수가 그대로입니다.
kubectl get hpa를 확인하면 TARGETS 열에<unknown>/50%이 표시되거나, 분명히 CPU가 높은데 replicas가 변하지 않습니다. HPA가 동작하지 않는 원인은 대부분 메트릭 수집 실패, resource requests 누락, 설정 오류 중 하나입니다.
핵심 요약
| 원인 | 증상 | 확인 방법 |
|---|---|---|
| metrics-server 미설치/장애 | TARGETS: <unknown> |
kubectl top nodes 응답 여부 |
| resource requests 미설정 | TARGETS: <unknown>, missing request 이벤트 |
Pod spec에 requests 필드 확인 |
| HPA minReplicas = maxReplicas | replicas 변동 없음 | kubectl get hpa MIN/MAX 값 비교 |
| Deployment replicas 필드 충돌 | apply 시 원래 수로 되돌아감 | manifest에서 spec.replicas 제거 여부 |
| autoscaling API 버전 문제 | HPA 생성 실패 또는 필드 무시 | kubectl api-versions 확인 |
| stabilization window | scale-down이 5분간 지연 | kubectl describe hpa Events |
| ScaleTargetRef 불일치 | REFERENCE 없음 또는 에러 | kubectl describe hpa scaleTargetRef |
1. HPA 동작 원리 요약
HPA는 Controller Manager 안에서 동작하는 컨트롤 루프입니다. 기본 15초 간격으로 메트릭을 조회하고, 현재 값과 목표 값의 비율을 계산해서 replica 수를 조정합니다.
스케일링 공식:
desiredReplicas = ceil(currentReplicas × (currentMetricValue / desiredMetricValue))
예를 들어, 현재 CPU 사용률이 80%이고 목표가 50%라면: ceil(2 × (80 / 50)) = ceil(3.2) = 4 → Pod를 4개로 늘립니다.
이 과정에서 메트릭 수집, 계산, 스케일링 결정 중 어느 단계에서든 문제가 생기면 HPA는 동작하지 않습니다.
2. 원인 1: metrics-server가 없거나 동작하지 않음
가장 흔한 원인입니다. HPA가 CPU/메모리 메트릭을 기반으로 스케일링하려면 metrics-server가 클러스터에 설치되어 있어야 합니다. metrics-server는 각 노드의 kubelet에서 리소스 사용량을 수집하고, metrics.k8s.io API를 통해 제공합니다.
증상
$ kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS
my-app Deployment/app <unknown>/50% 2 10 2
TARGETS 열에 <unknown>이 표시됩니다.
진단 명령어
# metrics-server가 설치되어 있는지 확인
kubectl get deployment metrics-server -n kube-system
# metrics API가 응답하는지 확인
kubectl top nodes
# API 서비스 등록 상태 확인
kubectl get apiservice v1beta1.metrics.k8s.io -o yaml
kubectl top nodes가 error: Metrics API not available 또는 error: metrics not available yet를 반환하면 metrics-server 문제입니다.
해결 방법
매니지드 Kubernetes를 사용하는 경우:
| 플랫폼 | 기본 설치 여부 | 확인/활성화 방법 |
|---|---|---|
| EKS | 기본 미설치 | kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml |
| AKS | 기본 설치됨 | kubectl get pods -n kube-system -l k8s-app=metrics-server |
| GKE | 기본 설치됨 | 자동 관리, 별도 조치 불필요 |
EKS에서 metrics-server 설치:
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
설치 후에도 동작하지 않는 경우 — metrics-server Pod 로그를 확인합니다:
kubectl logs -n kube-system deployment/metrics-server
흔한 에러: x509: cannot validate certificate — kubelet TLS 인증서를 검증하지 못하는 경우입니다. 테스트 환경에서는 --kubelet-insecure-tls 옵션으로 우회할 수 있지만, 운영 환경에서는 인증서를 올바르게 구성해야 합니다.
3. 원인 2: Pod에 resource requests가 설정되지 않음
HPA가 CPU 사용률(utilization) 기반으로 스케일링할 때, 사용률은 현재 사용량 / requests 값으로 계산됩니다. requests가 없으면 분모가 없어서 사용률을 계산할 수 없습니다.
증상
$ kubectl describe hpa my-app
...
Conditions:
Type Status Reason Message
---- ------ ------ -------
ScalingActive False FailedGetMetrics the HPA was unable to compute the replica count: missing request for cpu
진단 명령어
# Pod의 resource requests 확인
kubectl get pod <pod-name> -o jsonpath='{.spec.containers[*].resources.requests}'
출력이 비어 있으면 requests가 설정되지 않은 것입니다.
해결 방법
Deployment spec에 resource requests를 추가합니다:
spec:
containers:
- name: app
resources:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
주의할 점:
- 모든 컨테이너에 requests를 설정해야 합니다. 사이드카 컨테이너(예: Istio proxy, log collector)에 requests가 없으면 동일한 문제가 발생합니다.
- requests 값은 실제 사용량 기반으로 설정해야 합니다. 너무 높으면 사용률이 낮게 계산되어 스케일 업이 안 되고, 너무 낮으면 불필요한 스케일링이 발생합니다.
4. 원인 3: minReplicas와 maxReplicas 설정 오류
minReplicas = maxReplicas
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
spec:
minReplicas: 3
maxReplicas: 3 # 스케일링 불가
이 경우 HPA는 항상 3개를 유지합니다. 스케일 업도, 스케일 다운도 일어나지 않습니다. 의도적인 경우가 아니라면 maxReplicas를 minReplicas보다 크게 설정해야 합니다.
maxReplicas가 너무 낮음
목표 사용률이 50%인데 현재 Pod 2개가 90%를 사용 중이라면, 공식에 따라 4개가 필요합니다. 하지만 maxReplicas가 3이면 3개까지만 스케일됩니다. 이후에도 부하가 높으면 HPA 이벤트에 DesiredWithinRange 메시지가 나타납니다.
진단 명령어
kubectl get hpa my-app -o jsonpath='{.spec.minReplicas}/{.spec.maxReplicas}'
5. 원인 4: scaleTargetRef 불일치
HPA의 scaleTargetRef가 실제 존재하는 Deployment/StatefulSet과 이름이 다르면 스케일링 대상을 찾지 못합니다.
증상
$ kubectl describe hpa my-app
...
Reference: Deployment/my-apps # 오타: my-apps vs my-app
...
Conditions:
Type Status Reason Message
ScalingActive False FailedGetScale the HPA controller was unable to get the target's current scale
진단 명령어
# HPA가 참조하는 대상 확인
kubectl get hpa my-app -o jsonpath='{.spec.scaleTargetRef}'
# 실제 Deployment 이름과 비교
kubectl get deployment -n <namespace>
해결 방법
HPA의 scaleTargetRef.name을 실제 리소스 이름과 일치시킵니다. namespace도 동일해야 합니다.
6. 원인 5: Deployment manifest에 spec.replicas가 남아있음
Deployment YAML에 spec.replicas가 명시되어 있으면, kubectl apply를 실행할 때마다 HPA가 조정한 replica 수가 원래 값으로 되돌아갑니다.
시나리오
- HPA가 Pod를 5개로 스케일 업
- 개발자가 이미지 버전을 변경하고
kubectl apply -f deployment.yaml실행 - manifest에
replicas: 2가 있으므로 2개로 줄어듦 - HPA가 다시 계산해서 5개로 늘림 → 불필요한 thrashing 발생
해결 방법
HPA를 사용하는 Deployment에서는 spec.replicas 필드를 제거합니다:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
# replicas: 2 ← 제거
selector:
matchLabels:
app: my-app
template:
...
주의: spec.replicas를 제거하면 기본값 1이 적용될 수 있습니다. 제거 전에 HPA가 먼저 활성화되어 있어야 안전합니다.
7. 원인 6: autoscaling API 버전 문제
Kubernetes 1.26부터 autoscaling/v2beta2가 제거되었습니다. 현재 안정 API는 autoscaling/v2입니다.
| API 버전 | 상태 | 비고 |
|---|---|---|
autoscaling/v1 |
사용 가능 | CPU만 지원, 기본 기능만 |
autoscaling/v2 |
안정 (v1.23+) | CPU, 메모리, 커스텀 메트릭, behavior 지원 |
autoscaling/v2beta2 |
제거 (v1.26+) | v2로 마이그레이션 필요 |
증상
error: resource mapping not found for name: "my-app" namespace: "" from "hpa.yaml":
no matches for kind "HorizontalPodAutoscaler" in version "autoscaling/v2beta2"
진단 명령어
# 클러스터에서 지원하는 API 버전 확인
kubectl api-versions | grep autoscaling
해결 방법
autoscaling/v2를 사용합니다:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
8. 원인 7: stabilization window와 tolerance
HPA가 동작하지 않는 것처럼 보이지만, 실제로는 의도적인 지연일 수 있습니다.
scale-down stabilization window
기본값은 5분(300초) 입니다. 메트릭이 목표 이하로 내려가도 5분 동안은 scale-down하지 않습니다. 이는 메트릭 변동으로 인한 불필요한 축소를 방지하기 위한 설계입니다.
tolerance (허용 오차)
기본 tolerance는 10% 입니다. 현재 메트릭 값과 목표 값의 비율이 1.0 ± 0.1 범위 안에 있으면 스케일링을 하지 않습니다.
예: 목표 CPU 50%, 현재 CPU 54% → 비율 1.08 → tolerance 범위 내 → 스케일링 안 함.
Kubernetes 1.33에서 HPAConfigurableTolerance feature gate가 Alpha로 도입되었고, 1.35에서 Beta로 승격되었습니다. spec.behavior.scaleUp.tolerance와 spec.behavior.scaleDown.tolerance 필드로 방향별 tolerance를 개별 설정할 수 있습니다. 예를 들어 스케일 업은 tolerance 0(즉시 반응), 스케일 다운은 tolerance 0.05(5%)로 설정하여 불필요한 축소를 줄일 수 있습니다.
진단 방법
kubectl describe hpa my-app
Events 섹션에서 스케일링 이벤트 발생 시각과 SuccessfulRescale 메시지를 확인합니다. 이벤트가 아예 없다면 메트릭 수집 문제이고, 이벤트가 있지만 간격이 긴 경우 stabilization window 영향입니다.
9. 원인 8: 커스텀 메트릭 어댑터 미설치
CPU/메모리 이외의 메트릭(RPS, 큐 깊이 등)으로 스케일링하려면 커스텀 메트릭 어댑터가 필요합니다. custom.metrics.k8s.io 또는 external.metrics.k8s.io API를 제공하는 어댑터가 없으면 HPA가 메트릭을 조회할 수 없습니다.
대표적인 커스텀 메트릭 어댑터
| 어댑터 | 설명 |
|---|---|
| Prometheus Adapter | Prometheus 메트릭을 Kubernetes API로 노출 |
| KEDA | 이벤트 기반 오토스케일링, 다양한 소스 지원 |
| Datadog Cluster Agent | Datadog 메트릭 기반 스케일링 |
진단 명령어
# 커스텀 메트릭 API 등록 여부
kubectl get apiservice v1beta1.custom.metrics.k8s.io
kubectl get apiservice v1beta1.external.metrics.k8s.io
등록된 API 서비스가 없거나 상태가 False면 어댑터가 설치되지 않았거나 장애 상태입니다.
10. 원인 9: Node 리소스 부족으로 스케줄링 실패
HPA가 replica 수를 늘리기로 결정해도, 새 Pod를 배치할 노드가 없으면 실제로 Pod가 생성되지 않습니다. HPA 자체는 정상이지만 결과적으로 스케일 업이 되지 않는 것처럼 보입니다.
증상
$ kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS
my-app Deployment/app 85%/50% 2 10 5
$ kubectl get pods | grep Pending
my-app-7d9c8-xxxxx 0/1 Pending 0 2m
HPA는 10개까지 스케일을 결정했지만, 일부 Pod가 Pending 상태에 머물러 있습니다.
진단 명령어
# Pending Pod의 이벤트 확인
kubectl describe pod <pending-pod-name>
# Events: FailedScheduling - Insufficient cpu/memory
# 노드 리소스 상태 확인
kubectl top nodes
kubectl describe nodes | grep -A 5 "Allocated resources"
해결 방법
- Cluster Autoscaler 또는 Karpenter 활성화: 노드 풀을 자동으로 확장
- 노드 리소스 requests 합산이 용량을 초과하지 않도록 Pod requests 조정
- maxReplicas를 현재 클러스터 용량에 맞게 설정
11. 실무 진단 플로우차트
HPA가 동작하지 않을 때 아래 순서로 확인합니다.
Step 1: kubectl get hpa 확인
kubectl get hpa -n <namespace>
- TARGETS에
<unknown>→ Step 2로 - TARGETS에 숫자가 있지만 REPLICAS 변동 없음 → Step 4로
Step 2: 메트릭 수집 확인
kubectl top nodes
kubectl top pods -n <namespace>
- 에러 발생 → metrics-server 확인 (원인 1)
- 정상 응답 → Step 3으로
Step 3: resource requests 확인
kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.spec.containers[*].resources.requests}'
- 비어 있음 → resource requests 추가 (원인 2)
- 값이 있음 → 사이드카 컨테이너 포함 모든 컨테이너 확인
Step 4: HPA 상세 확인
kubectl describe hpa <hpa-name> -n <namespace>
- Conditions의 ScalingActive가 False → scaleTargetRef, API 버전 확인 (원인 5, 7)
- AbleToScale가 False → min/max 설정 확인 (원인 3)
- Events에 스케일링 이력 있지만 5분 이내 → stabilization window (원인 7)
12. 운영 환경에서의 HPA 설정 권장사항
resource requests 설계
resources:
requests:
cpu: "200m" # 평상시 사용량 기준
memory: "256Mi"
limits:
cpu: "1000m"
memory: "512Mi"
requests는 평상시 사용량의 60~80% 수준으로 설정합니다. 이렇게 하면 부하가 약간만 올라도 사용률이 목표를 초과하여 스케일 업이 트리거됩니다.
HPA 설정 예시
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
behavior:
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 15
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 10
periodSeconds: 60
설계 의도:
| 설정 | 값 | 이유 |
|---|---|---|
| averageUtilization | 60% | 버스트 대응 여유분 확보 |
| scaleUp stabilization | 0초 | 부하 증가 시 즉시 스케일 업 |
| scaleDown stabilization | 300초 | 불필요한 축소로 인한 서비스 불안정 방지 |
| scaleDown rate | 10%/분 | 점진적 축소로 thrashing 방지 |
CPU vs 메모리 메트릭 선택
| 기준 | CPU | 메모리 |
|---|---|---|
| 적합한 워크로드 | API 서버, 연산 중심 앱 | 대부분 부적합 |
| 스케일 특성 | 부하에 따라 오르내림 | 올라가면 잘 안 내려옴 (GC 의존) |
| 권장 여부 | 일반적으로 권장 | 단독 사용 비권장 |
메모리 메트릭 단독으로 HPA를 구성하면, JVM 기반 앱처럼 GC 전까지 메모리를 반환하지 않는 워크로드에서 무의미한 스케일 업이 발생할 수 있습니다. 메모리 기반 스케일링이 필요하면 CPU 메트릭과 함께 사용하고, OOMKilled 방지는 VPA나 limits 설정으로 처리하는 것이 일반적입니다.
마무리
HPA가 동작하지 않는 원인은 대부분 세 가지로 좁힐 수 있습니다:
- 메트릭 수집 실패 — metrics-server 미설치 또는 장애
- 계산 불가 — resource requests 미설정
- 설정 오류 — scaleTargetRef 불일치, min=max, API 버전 문제
kubectl describe hpa의 Conditions와 Events를 먼저 확인하면 원인을 빠르게 좁힐 수 있습니다. 메트릭이 정상인데도 스케일링이 느리다면 stabilization window와 tolerance 설정을 점검합니다.
Kubernetes 아키텍처 기본 구조와 HPA가 어떤 컴포넌트를 통해 동작하는지 이해하면, 문제 발생 시 어느 레이어를 확인해야 하는지 판단이 빨라집니다.
'Kubernetes' 카테고리의 다른 글
| EKS vs AKS vs GKE: 매니지드 Kubernetes 비교 (0) | 2026.06.06 |
|---|---|
| Kubernetes RBAC란 무엇인가: Role, ClusterRole, Binding으로 권한 설계하기 (0) | 2026.06.01 |
| Kubernetes Service 종류: ClusterIP, NodePort, LoadBalancer, Ingress 비교 (0) | 2026.05.31 |
| Kubernetes 아키텍처 기본 구조: Control Plane과 Worker Node (0) | 2026.05.31 |