HPA가 생각대로 동작하지 않을 때: 흔한 설정 실수 6가지
HPA를 걸어 뒀는데 트래픽이 몰려도 안 늘어나거나, 늘어나긴 하는데 이미 장애가 난 뒤거나, 하루 종일 늘었다 줄었다를 반복합니다. HPA의 개념(HPA/VPA/Cluster Autoscaler의 구분)은 K8s 중급 #6에서 다뤘고, 이 글은 실무에서 실제로 걸리는 설정 실수를 증상별로 정리합니다.
먼저 상태 확인 명령부터 봅니다. HPA 문제의 진단은 대부분 이 한 줄에서 시작합니다.
$ kubectl describe hpa api-server
...
Metrics: resource cpu on pods (as a percentage of request): <unknown> / 70%
Conditions:
AbleToScale True
ScalingActive False FailedGetResourceMetric
Events:
Warning FailedGetResourceMetric unable to get metrics for resource cpu1. 지표를 못 읽는 상태: <unknown>
#
위 출력처럼 현재 값이 <unknown>이면 HPA는 아무 판단도 못 하고 멈춰 있는 상태입니다. 두 가지가 대부분입니다. metrics-server가 없거나 죽어 있는 경우(kubectl top pod가 실패하면 이쪽), 그리고 다음 항목인 requests 미설정입니다.
2. requests가 없어서 퍼센트를 계산할 수 없음 #
CPU averageUtilization: 70은 “requests 대비 70%“라는 뜻입니다. 분모가 requests이므로, 컨테이너에 CPU requests가 없으면 HPA는 퍼센트를 계산할 수 없습니다. limits만 적고 requests를 빼먹은 매니페스트가 전형적인 원인입니다.
- 확인: 대상 Deployment의 모든 컨테이너(사이드카 포함)에 CPU requests가 있는지 봅니다. 사이드카 하나만 빠져도 계산이 깨집니다.
- 처방: requests를 설정합니다. 값을 정하는 기준은 다음 글에서 다룹니다.
같은 이유로, 타깃 퍼센트의 의미도 requests 기준입니다. requests 500m에 타깃 70%면 350m에서 스케일이 시작됩니다. limits(예: 2코어) 기준이라고 착각하면 “왜 벌써 늘어나지?“라는 반대 방향의 오해가 생깁니다.
3. min/max 경계에 걸려 있음 #
증상이 “안 늘어난다"라면 가장 싱거운 원인부터 배제합니다. 이미 maxReplicas에 도달해 있는 경우입니다. kubectl get hpa에서 REPLICAS가 MAXPODS와 같다면 설정이 아니라 용량 계획의 문제입니다. 반대로 minReplicas가 커서 스케일다운이 안 되는 것을 “다운이 고장났다"고 오해하는 경우도 있습니다.
4. 반응이 느림: 급증 트래픽과 스케일업 지연 #
HPA는 즉각 반응하지 않습니다. 지표 수집 주기, HPA 평가 주기(기본 15초), 새 Pod의 기동 시간(이미지 풀 + 애플리케이션 스타트 + readiness 통과)이 더해져, 트래픽 급증에서 실제 용량 확보까지는 분 단위가 걸립니다. 초 단위 스파이크는 HPA로 못 막습니다.
- 처방: 기동이 느린 앱은 스케일업을 공격적으로(behavior의 scaleUp 정책으로 한 번에 여러 개), 평시 여유분을 minReplicas로 확보합니다. 예측 가능한 피크(정시 이벤트)는 CronJob 등으로 선제 확장하고, 근본적으로는 Pod 기동 시간 자체(이미지 크기, readiness 설계는 K8s 중급 #5 참고)를 줄이는 것이 스케일링 반응성의 핵심입니다.
5. 플래핑: 늘었다 줄었다를 반복 #
레플리카가 늘어나면 Pod당 부하가 내려가 지표가 타깃 아래로 떨어지고, 그래서 줄이면 다시 타깃 위로 올라가는 진동입니다. HPA에는 이를 막는 안정화 윈도우(기본: 스케일다운 5분)가 있지만, 타깃을 너무 빡빡하게 잡았거나(예: 90%) 지표가 원래 출렁이는 워크로드에서는 기본값으로 부족합니다.
- 처방:
behavior.scaleDown.stabilizationWindowSeconds를 늘리고, 다운 속도를 정책으로 제한합니다(예: 1분에 10%씩). 타깃도 지표의 자연 변동 폭보다 여유 있게 잡습니다.
6. 다른 컨트롤러와의 충돌 #
HPA가 늘려 놓으면 몇 분 뒤 원래대로 돌아가 있는 증상은, 대부분 다른 무언가가 replicas를 되돌리고 있는 것입니다. 매니페스트에 replicas를 명시해 둔 채 GitOps(ArgoCD 등)가 sync하는 구성이 단골입니다. HPA가 5로 올리면 GitOps가 “선언과 다르다"며 2로 되돌립니다. VPA를 같은 지표(CPU)에 auto 모드로 함께 걸어 둔 경우도 서로 간섭합니다.
- 처방: HPA를 쓰는 워크로드는 매니페스트에서
replicas필드를 제거하거나 GitOps 쪽에서 해당 필드를 ignore 처리합니다. VPA는 권고 모드로 두거나 대상 지표를 분리합니다.
덧붙여: CPU만 보는 스케일링의 한계 #
설정이 다 맞아도, 병목이 CPU가 아니면 HPA는 헛돕니다. 메모리가 병목인 워크로드, 커넥션 수나 큐 길이가 실제 부하 지표인 워크로드(웹훅 소비자, 작업 큐)는 CPU 70%에 도달하기 전에 이미 느려집니다. 이 경우 커스텀 지표(초당 요청 수, 큐 깊이) 기반 스케일링이나 이벤트 기반 오토스케일러(KEDA)가 맞는 도구입니다. 무엇이 병목인지는 서버가 느린 이유 시리즈의 진단 순서가 그대로 적용됩니다.
정리 #
- 진단은
kubectl describe hpa에서 시작합니다.<unknown>이면 metrics-server와 requests부터 봅니다. - 타깃 퍼센트는 requests 대비입니다. requests가 없으면 HPA는 동작하지 않고, 사이드카 하나만 빠져도 깨집니다.
- HPA의 반응은 분 단위입니다. 초 단위 스파이크는 minReplicas 여유와 기동 시간 단축으로 대비합니다.
- 플래핑은 안정화 윈도우와 다운 정책으로, GitOps의 replicas 되돌림은 필드 제거·ignore로 풉니다.
- CPU가 병목이 아닌 워크로드는 커스텀 지표나 KEDA로 스케일 기준 자체를 바꿉니다.