오늘 알게 된 건데, Karpenter NodePool의 weight 가지고 spot 우선 + on-demand fallback 구성한 분들 꽤 많을 거다. 우리 팀도 그렇게 쓰고 있었고. 근데 이게 생각만큼 매끄럽게 fallback이 안 되는 케이스가 있다.
며칠 전에 다른 팀 슬랙에서 "spot이 깨졌는데 on-demand로 안 넘어와요" 하는 글을 봤다. 처음엔 NodePool 매칭이 안 맞나 싶었는데, GitHub 이슈를 따라가다 보니 karpenter-provider-aws#8885라는 게 있더라. 올해 1월 말부터 올라온 이슈인데, 아직 진행 중이다.
무슨 상황이냐면
대충 이런 구성을 떠올리면 된다.
# 우선순위 높은 spot 풀
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: spot
spec:
weight: 100
template:
spec:
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ["spot"]
---
# fallback용 on-demand 풀
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: on-demand
spec:
weight: 10
template:
spec:
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ["on-demand"]
weight: 100이 더 높으니까 평소엔 spot이 먼저 뜨고, spot이 안 잡히면 weight: 10인 on-demand로 넘어와야 한다. 공식 문서도 그렇게 설명하고 있고, 실제로 대부분의 경우엔 잘 동작한다.
문제는 EC2 쪽에서 MaxSpotInstanceCountExceeded 같은 계정 단위 한도 에러를 뱉을 때다. 흔히 "instance capacity 부족"으로 뜨는 InsufficientInstanceCapacity도 마찬가지. 이 경우엔 Karpenter가 fallback NodePool로 안 넘어가고 그냥 Pending에 머무는 상황이 보고됐다. 한 시간 넘게 Pod이 안 떠서 결국 수동 개입했다는 케이스도 있었다.
왜 이렇게 동작하나
Karpenter 내부적으로는 EC2 Fleet API가 "안 된다"고 응답하면 그 결과를 약 3분간 캐싱한다. 이게 같은 NodePool 안에서 다른 capacity-type을 시도할 때는 비교적 잘 먹는데, 다른 weight의 NodePool로 넘어가는 경로에서는 이슈가 있어 보인다. 정확한 원인은 아직 이슈에서 토론 중이라 단정하긴 어렵다.
실제로 직접 테스트해본 분 코멘트 보면 spot 풀에 약 500개 정도 Pod이 올라간 시점부터 한도 에러가 나기 시작했고, 그 다음부터 들어온 Pod은 fallback이 안 됐다고 한다. kubectl describe pod을 까보면 MaxSpotInstanceCountExceeded만 계속 떠 있고 on-demand 시도 로그는 안 보인다.
그래서 어떻게 대응하나
완벽한 해결은 아직 없지만, 우리 팀에서 적용한 임시 대응책 몇 가지.
첫째, spot 풀의 limits를 보수적으로 잡는다. spot 한도 가까이 가기 전에 일부러 풀이 다 찼다고 인식하게 만들면, fallback 경로가 평상시에 더 자주 발동한다. 한도 에러가 안 뜨고 단순히 "이 풀에 자리 없음"으로 끝나기 때문에 fallback이 잘 먹는 편이다.
둘째, weight 차이를 너무 크게 두지 않는다. 100 vs 10보다는 100 vs 50처럼 좁혀두면 spot이 꽉 차거나 비싸질 때 자연스럽게 on-demand가 섞여 뜨는 효과가 있다. spot 비중을 조금 양보하는 대신 가용성을 산다고 보면 된다.
셋째, 정말 중요한 워크로드는 ODCR(On-Demand Capacity Reservation) 이나 Capacity Block을 먼저 쓰도록 별도 NodePool을 가장 높은 weight로 둔다. 이건 spot 한도 이슈와는 다른 풀이라 영향을 안 받는다.
마지막으로 모니터링. karpenter_nodeclaims_unscheduled 와 karpenter_pods_state{phase="Pending"} 메트릭에 알림을 걸어두면 fallback이 실패해도 새벽에 늦지 않게 깨워준다. 우리는 5분 임계로 잡아뒀다.
정리
weight 기반 fallback이 만능이라고 생각하고 spot 비중을 99%로 운영하는 건 좀 위험하다. 적어도 2026년 6월 기준으로는 위 이슈가 살아있다. 패치가 들어가도 capacity 한도 같은 외부 요인은 늘 변수라, 다중 NodePool 구조에서도 spot:on-demand 비율은 가용성 관점에서 한 번 더 보수적으로 점검할 만하다.
혹시 fallback 잘 되도록 운영하는 팁 있는 분 있으면 댓글로 알려주세요.
'IT > AWS' 카테고리의 다른 글
| Karpenter v1.5로 올렸더니 새벽에 깨버린 이야기 (0) | 2026.06.13 |
|---|---|
| EKS Pod Identity 도입 가이드 - IRSA에서 갈아타기 전에 (0) | 2026.06.11 |
| EKS Auto Mode 켜고 첫 달 청구서 받고 멘붕한 이야기 (1) | 2026.06.09 |
| NAT Gateway egress 비용 폭탄 맞고 깨달은 것들 (0) | 2026.06.02 |
| Karpenter NodeOverlay로 GPU spot 가격 흔들림 잡아보다 (alpha 도입 보류한 이야기) (0) | 2026.05.29 |