Kubernetes HPA 악순환으로 인한 클러스터 장애

김유경·2025년 6월 10일

들어가며

쿠버네티스 클러스터에서 파드가 생성되지 않고, 계속해서 새로운 파드의 생성과 삭제를 반복하는 문제가 발생했습니다. 처음에는 단순한 리소스 부족으로 판단했지만, 실제로는 HPA(Horizontal Pod Autoscaler)와 etcd 간의 악순환이 원인이었습니다.

✏️ 이 글에서는 해당 장애의 원인과 트러블슈팅 과정을 기록합니다.


초기 증상

파드 스케줄링 실패

kubectl describe pod user-service-797cd76868-dbrph -n dev-user-service

출력 결과

Warning  FailedScheduling  84s   default-scheduler  0/5 nodes are available: 
1 Insufficient memory, 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }, 
3 Insufficient cpu. preemption: 0/5 nodes are available: 
1 Preemption is not helpful for scheduling, 4 No preemption victims found for incoming pod.

초기 판단

일부 노드는 메모리와 CPU가 부족하고, 컨트롤 플레인 노드는 테인트 설정으로 인해 스케줄링 대상에서 제외되었습니다. 해당 문제는 일반적인 리소스 부족 현상으로 보였습니다.


리소스 사용량 분석

1) 노드별 리소스 확인

kubectl top nodes

출력 결과

NAME                CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%   
host-10-10-16-248   1448m        72%    2741Mi          71%       
host-10-10-17-210   1752m        87%    2723Mi          71%       
host-10-10-17-228   838m         41%    4069Mi          51%       
host-10-10-17-253   346m         17%    4801Mi          61%       
host-10-10-19-191   1457m        72%    4724Mi          60%       

분석

컨트롤플레인 노드(host-10-10-17-210)의 CPU 사용률이 87%로 매우 높았습니다.

2) dev-user-service 파드 리소스 확인

kubectl top pods -n dev-user-service

출력 결과

NAME                            CPU(cores)   MEMORY(bytes)   
user-service-797cd76868-5xfqx   133m         110Mi           
user-service-797cd76868-dbrph   8m           334Mi           
user-service-797cd76868-hmddh   300m         284Mi           
user-service-797cd76868-msr85   302m         291Mi           

분석

일부 파드가 300m 이상의 CPU를 사용하며 비교적 높은 부하를 보이고 있었습니다. 전체적으로 워커 노드의 리소스는 여유가 있었지만, 스케줄링 실패가 반복된 주요 원인은 컨트롤 플레인 노드의 과도한 부하일 가능성이 높다고 판단했습니다.


첫 번째 해결 시도: 모니터링 스택 중지

모니터링 시스템이 많은 리소스를 쓰고 있어, 관련 컴포넌트들을 일시적으로 중지했습니다.

# 모니터링 스택 스케일 다운
kubectl get deployments -n dev-monitoring -o name | xargs -I {} kubectl scale {} --replicas=0 -n dev-monitoring
kubectl get statefulsets -n dev-monitoring -o name | xargs -I {} kubectl scale {} --replicas=0 -n dev-monitoring

# Falco 보안 모니터링 컴포넌트 중지
kubectl scale deployment -n falco-security --all --replicas=0
kubectl delete daemonset -n falco-security --all

리소스 사용량 확인

kubectl top nodes

출력 결과

NAME                CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%   
host-10-10-16-248   718m         35%    1655Mi          43%       
host-10-10-17-210   1611m        80%    2636Mi          69%       
host-10-10-17-228   1273m        63%    3874Mi          49%       
host-10-10-17-253   282m         14%    4427Mi          56%       
host-10-10-19-191   1086m        54%    4356Mi          55%       

분석

모니터링 스택 제거 이후, 대부분의 워커 노드에서는 CPU 및 메모리 사용률이 눈에 띄게 감소했습니다. 하지만 컨트롤 플레인 노드(host-10-10-17-210)는 여전히 80% 이상의 CPU 사용률을 유지하고 있어, 근본적인 문제가 해결되지 않았음을 알 수 있었습니다.


문제 악화: 컨트롤 플레인 과부하

리소스를 정리했음에도 불구하고 파드 스케줄링 문제는 계속되었습니다.

kubectl top nodes

출력 결과

NAME                CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%   
host-10-10-16-149   1641m        82%    1264Mi          33%       
host-10-10-16-248   1541m        77%    1463Mi          38%       
host-10-10-17-210   1823m        91%    2648Mi          69%       
host-10-10-17-228   1578m        78%    3326Mi          42%       
host-10-10-17-253   430m         21%    3672Mi          46%       
host-10-10-19-191   910m         45%    3911Mi          49%       

⚠️ 컨트롤 플레인 CPU 91% 도달

노드를 추가해도 근본적인 해결이 되지 않았고, 오히려 전체 클러스터의 대부분의 파드가 생성되지 않는 현상까지 발생했습니다.


컨트롤 플레인 분석

1) API 서버 응답 확인

kubectl get nodes --v=6

출력 결과

I0609 14:46:07.575430 3110342 round_trippers.go:553] GET https://10.10.17.210:6443/api/v1/nodes?limit=500 200 OK in 17 milliseconds

분석

API 서버는 요청에 정상적으로 응답하고 있었으며, 응답 속도도 큰 문제가 없어 보였습니다.

2) 컨트롤 플레인 컴포넌트 상태 확인

kubectl get pods -n kube-system | grep -E "(api|controller|scheduler|etcd)"

출력 결과

etcd-host-10-10-17-210                       1/1     Running   0              9d
kube-apiserver-host-10-10-17-210             1/1     Running   1 (6d7h ago)   9d
kube-controller-manager-host-10-10-17-210    1/1     Running   18 (13h ago)   9d
kube-scheduler-host-10-10-17-210             1/1     Running   17 (13h ago)   9d

분석

kube-controller-manager와 kube-scheduler가 각각 18회, 17회 재시작된 것이 확인되었습니다.

3) etcd 성능 확인

kubectl logs -n kube-system etcd-host-10-10-17-210 --tail=20

출력 결과

{"level":"warn","ts":"2025-06-09T14:45:03.529176Z","caller":"v3rpc/interceptor.go:197","msg":"request stats","start time":"2025-06-09T14:45:02.873387Z","time spent":"655.538204ms","remote":"127.0.0.1:57964","response type":"/etcdserverpb.KV/Txn"}

{"level":"warn","ts":"2025-06-09T14:45:19.523664Z","caller":"v3rpc/interceptor.go:197","msg":"request stats","start time":"2025-06-09T14:45:18.734664Z","time spent":"788.756718ms","remote":"127.0.0.1:36246","response type":"/etcdserverpb.KV/Txn"}

{"level":"warn","ts":"2025-06-09T14:45:53.506663Z","caller":"v3rpc/interceptor.go:197","msg":"request stats","start time":"2025-06-09T14:45:52.816751Z","time spent":"689.842973ms","remote":"127.0.0.1:36246","response type":"/etcdserverpb.KV/Txn"}

분석

정상적인 etcd 응답 시간은 100ms 이하가 이상적이지만, 현재는 요청마다 600~800ms의 지연이 발생하고 있었습니다.

etcd는 쿠버네티스의 중앙 데이터 저장소로, 클러스터 내 모든 오브젝트의 상태 정보(Pod, Service, ConfigMap 등)를 저장합니다. API 서버는 etcd를 통해 클러스터 상태를 조회하고 변경하기 때문에, etcd가 느려지면 컨트롤플레인을 포함한 전체 시스템의 응답성에 영향을 미치게 됩니다.


원인 발견: HPA 악순환

etcd 로그를 자세히 분석해보니, twp-service와 관련된 이벤트가 비정상적으로 폭증하고 있었고, 이것이 etcd 성능 저하의 직접적인 원인임을 발견했습니다.

1) 문제 서비스 식별

etcd 로그에는 아래와 같은 패턴이 반복적으로 나타났습니다.

"request content":"compare:<target:MOD key:\"/registry/events/dev-twp-service/twp-service-5649d66c74.18476710f9922751\""
"request content":"compare:<target:MOD key:\"/registry/services/endpoints/dev-twp-service/twp-service\""
"request content":"compare:<target:MOD key:\"/registry/endpointslices/dev-twp-service/twp-service-w6t2l\""

분석

twp-service가 지속적으로 etcd에 이벤트를 생성하고 있었고, 이로 인해 etcd가 과부하에 빠지고 있었습니다.

2) twp-service 상태 확인

kubectl get pods -n dev-twp-service

출력 결과

NAME                              READY   STATUS    RESTARTS   AGE
dev-redis-lock-85f48688cc-zj62c   1/1     Running   0          5m11s
twp-service-5649d66c74-42fdp      1/1     Running   0          88s
twp-service-5649d66c74-4glxc      1/1     Running   0          5m11s
twp-service-5649d66c74-bwqkf      1/1     Running   0          89s
twp-service-5649d66c74-ztkfn      1/1     Running   0          5m11s

분석

파드 상태는 모두 Running이었지만, AGE를 보면 짧은 간격으로 반복 생성되고 있는 상황임을 확인할 수 있었습니다.

3) 이벤트 히스토리 확인

kubectl get events -n dev-twp-service --sort-by='.lastTimestamp' | tail -10

출력 결과

94s         Normal    SuccessfulDelete                     replicaset/twp-service-5649d66c74         Deleted pod: twp-service-5649d66c74-bl4px
92s         Normal    SuccessfulRescale                    horizontalpodautoscaler/twp-service-hpa   New size: 4; reason: cpu resource utilization (percentage of request) above target
92s         Normal    ScalingReplicaSet                    deployment/twp-service                    Scaled up replica set twp-service-5649d66c74 to 4 from 2
89s         Normal    SuccessfulCreate                     replicaset/twp-service-5649d66c74         Created pod: twp-service-5649d66c74-42fdp

분석

이벤트 로그를 보면, 2~3초 간격으로 파드 삭제, HPA 스케일 업, 파드 생성 이벤트가 반복되고 있음을 확인할 수 있습니다.

즉, twp-service는 CPU 사용률이 HPA의 기준을 초과하면서 스케일 업 → 파드 생성 → 부하 집중 → 다시 스케일 업이라는 순환 구조에 빠져 있었고, 이로 인해 etcd에는 초당 수차례의 트랜잭션 요청이 쏟아지는 상황이 발생하고 있었습니다.


HPA 악순환 메커니즘

1) 초기 상황

클러스터 전반에 리소스 부족이 발생한 상태였습니다.

  • 컨트롤 플레인 노드 CPU 사용률: 91%
  • 워커 노드 CPU 사용률: 평균 70~80%

2) HPA 트리거 발생

twp-service의 CPU 사용률이 HPA의 target을 초과
→ HPA: CPU 사용률이 여전히 높다고 판단하고 스케일 업을 시도

3) 악순환 시작

하지만 실제로는 다음과 같은 메커니즘이 작동하고 있었습니다.

  • HPA가 파드 수를 2개에서 4개로 스케일 업 시도
  • 스케줄러는 워커 노드에 충분한 리소스를 확인하고 스케줄링을 결정
  • API 서버는 etcd에 파드 정보를 저장하려고 하지만, etcd 응답 지연(600~800ms) 발생
  • 이 지연 동안 HPA는 주기적으로 메트릭을 다시 수집
  • CPU 사용률이 여전히 target을 초과한 것으로 판단해 또다시 스케일 업을 시도

결국, 스케줄링 결정은 정상적으로 이루어졌지만 etcd의 반영 속도가 느려 HPA가 계속해서 중복 트리거되는 무한 루프에 빠졌습니다.

4) etcd 과부하

  • 반복적인 파드 생성/삭제/업데이트 이벤트로 etcd에 트랜잭션 폭주
  • 결과적으로 모든 Kubernetes API 호출이 느려짐

5) 전체 시스템 마비

  • 신규 파드 생성 실패
  • 일부 서비스는 응답하지 않거나 중단
  • 클러스터 전반에 장애 발생

해결 과정

HPA 확인 및 제거

kubectl get hpa -A

출력 결과

NAMESPACE          NAME               TARGETS   MINPODS   MAXPODS   REPLICAS
dev-twp-service    twp-service-hpa    85%/70%   2         10        4
dev-user-service   user-service-hpa   45%/70%   2         8         3

분석

twp-service가 지속적으로 target(70%)을 초과하며 스케일 업을 반복 중이었고, 이로 인해 위의 악순환이 발생한 것이었습니다.

# HPA 제거
kubectl delete hpa twp-service-hpa -n dev-twp-service
kubectl delete hpa user-service-hpa -n dev-user-service

결과 확인

HPA를 제거한 뒤, 다시 노드 리소스 상태를 확인했습니다.

kubectl top nodes

출력 결과

NAME                CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%   
host-10-10-16-149   892m         44%    1156Mi          30%       
host-10-10-16-248   1102m        55%    1344Mi          35%       
host-10-10-17-210   1243m        62%    2145Mi          56%       
host-10-10-17-228   1089m        54%    2987Mi          38%       
host-10-10-17-253   278m         13%    3201Mi          41%       
host-10-10-19-191   756m         37%    3456Mi          44%       

🎉 컨트롤플레인 노드(host-10-10-17-210)의 CPU 사용률이 91% → 62%로 안정화되었고, 전체 클러스터의 부하도 눈에 띄게 감소했습니다.

etcd 로그 확인

kubectl logs -n kube-system etcd-host-10-10-17-210 --tail=10

“request took too long” 경고 메시지가 더 이상 나타나지 않으며, etcd 응답도 정상으로 회복된 것을 확인했습니다.


마무리

HPA는 편리한 자동 확장 도구지만, 클러스터 전체 리소스 상황을 고려하지 않은 설정은 오히려 장애를 유발할 수 있습니다. 특히, etcd와 같은 핵심 컴포넌트에 부하를 집중시키면, 클러스터 전체가 느려지거나 마비되는 결과를 초래할 수 있습니다.

이번 장애의 핵심은 워커 노드에는 리소스가 있었지만, etcd 병목으로 인해 스케줄링 프로세스 전체가 느려져서 HPA가 이를 인지하지 못하고 계속 스케일 업을 시도한 것이었습니다.

HPA 개선 방안

  • HPA 설정 시 클러스터 용량 고려 - maxReplicas 제한
  • Stabilization Window 설정 - 급격한 스케일링 방지

😶 이번 장애를 통해 쿠버네티스의 복잡한 상호작용과 etcd 성능의 중요성을 다시 한 번 깨달았습니다.

0개의 댓글