작년 이맘때까지 우리 EKS 클러스터는 Cluster Autoscaler로 잘 돌아가고 있었다. 노드 그룹 세팅도 안정적이었고, 크게 불만도 없었다. 그런데 반년 전쯤 트래픽 패턴이 바뀌면서 상황이 달라졌다. 낮에는 몰리고 밤에는 뚝 떨어지는 변동 폭이 커졌고, 갑자기 배포되는 배치 잡도 늘었다. 그때부터 노드가 이상하게 많이 뜨기 시작했고, 청구서를 볼 때마다 한숨이 나왔다.
결국 Karpenter로 옮겼다. 최근에 v1이 정식으로 나오면서 API도 정리됐고, 실전에 쓸 만하다는 얘기가 많아진 시점이었다. 옮기고 나서 두 달쯤 지난 지금, 그 비교를 정리해두려고 한다.
스케줄링 철학이 다르다
이게 제일 큰 차이다. Cluster Autoscaler는 노드 그룹 단위로 사고한다. 어떤 파드가 pending이면 "이 노드 그룹을 하나 늘려도 되나?"를 판단하고 ASG에 desired capacity를 올린다. 그러면 EC2가 만들어지고, 그 위에 파드가 스케줄된다. 각 노드 그룹은 사전에 정의된 instance type 리스트를 갖는다.
Karpenter는 완전히 다르게 생각한다. Pending 파드가 있으면 그 파드의 요구사항(CPU, 메모리, 아키텍처, taint tolerance 등)을 보고 "이 파드에 딱 맞는 EC2 인스턴스가 뭘까?"를 실시간으로 결정한다. NodePool에서 허용한 범위 안에서 그 순간 가장 적합한 인스턴스 타입을 골라 launch한다.
말로 하면 사소해 보이지만 결과는 크다. Cluster Autoscaler는 노드 그룹을 미리 설계하고 그 안에서만 움직이는 반면, Karpenter는 워크로드에 맞춰 노드 shape 자체를 매번 다시 계산한다.
실제로 비용이 얼마나 줄었나
이 부분이 궁금해서 옮기기 전에 좀 재봤다. 우리 팀은 마이그레이션 전후로 node 수가 대략 25% 줄었다. 업계 벤치마크 자료를 보면 보통 20~35% 감소가 나온다고 하는데, 우리도 그 범위 안에 들어왔다.
무엇 때문일까? 두 가지다.
첫째, bin-packing. Karpenter는 consolidation이라는 기능이 있어서, 워크로드가 줄면 파드를 다른 노드로 옮기고 빈 노드를 정리한다. Cluster Autoscaler에도 scale-down 로직이 있긴 한데, 파드를 옮기는 게 아니라 "완전히 비어야만" 노드를 내린다. 그래서 실 프로덕션에서는 파편화된 노드가 꽤 오래 남는다.
둘째, 인스턴스 타입 다양성. 예를 들어 4 vCPU / 8Gi 파드 한 개가 튀어나왔을 때, Cluster Autoscaler는 노드 그룹에 정의된 m5.xlarge 같은 걸 띄운다. Karpenter는 그 순간 spot 시장을 보고 r6i.large가 더 싸면 그걸 띄운다. 매번의 선택이 조금씩 유리한 쪽으로 기울면서 결국 큰 차이가 난다.
Spot 처리 방식의 차이
Spot을 진지하게 쓰는 팀이라면 이 차이가 크다.
Cluster Autoscaler에서는 spot을 쓰려면 별도 ASG를 만들고, mixed instance policy를 걸어 인스턴스 다양성을 확보한다. spot 회수가 발생하면 다른 spot으로 대체되지만, 그 흐름 전체가 ASG 설정에 의존한다.
Karpenter는 NodePool에서 capacity-type: [spot, on-demand] 하나만 선언하면 끝난다. spot으로 프로비저닝을 시도하고, 실패하면 on-demand로 fallback한다. Interruption 처리도 EventBridge로 알림을 받아서 파드를 사전에 다른 노드로 미리 옮겨준다. 이게 상당히 매끄러웠다.
그럼 Cluster Autoscaler는 언제 쓰나
내 결론부터 말하면, GKE라면 Cluster Autoscaler다. Karpenter가 GKE에서는 아직 정식 지원이 아니라서 선택지가 없다.
그리고 규제 산업처럼 인스턴스 타입을 특정 목록으로 제한해야 하는 경우도 Cluster Autoscaler가 더 편하다. 물론 Karpenter도 NodePool에서 제한 걸 수 있지만, "어떤 상황에서 어떤 타입이 뜰지"를 완전히 예측하고 싶다면 노드 그룹 방식이 더 명시적이다.
또 하나, 워크로드 패턴이 정말 predictable하고 homogeneous하다면 Karpenter의 이점이 크지 않다. 이런 팀은 Cluster Autoscaler로 이미 최적화가 잘 돼 있을 가능성이 높다.
마이그레이션 팁
가장 무섭게 들었던 얘기가 "한번에 갈아엎지 마라"였는데 실제로 해보니 정말 그렇다. 우리는 이렇게 했다.
- Karpenter를 Cluster Autoscaler와 나란히 설치한다. 처음엔 Karpenter NodePool의 리소스 상한을 아주 낮게 잡는다.
- 새로운 워크로드부터 Karpenter로 흘려보낸다.
nodeSelector나 taint로 명시적으로 분리한다. - 안정성이 확인되면 기존 노드 그룹의 desired를 서서히 줄이고, 파드가 Karpenter 노드로 재스케줄되는 걸 확인한다.
- 노드 그룹을 완전히 비운 뒤 Cluster Autoscaler를 제거한다.
각 단계마다 롤백이 가뉥하다는 게 중요하다. 갑자기 뭔가 이상하면 다시 Cluster Autoscaler 쪽으로 웨이트를 옮기면 되니까.
한 가지 삽질 포인트를 남기자면, PDB(PodDisruptionBudget)를 잘 걸어두지 않으면 consolidation이 서비스에 영향을 줄 수 있다. Karpenter는 상대적으로 파드를 자주 옮기기 때문에, PDB가 없으면 예상 못 한 순간에 파드가 재시작된다. 우리도 이걸로 한 번 놀랐다.
그래서
우리 팀 상황에서는 Karpenter가 맞았다. 트래픽 변동이 크고, 인스턴스 타입에 특별한 제약도 없고, spot을 적극적으로 쓰고 싶었으니까. 25% 노드 감소는 예상보다 큰 숫자였고, 프로비저닝 속도가 45~60초로 빨라진 건 배포 경험 자체를 바꿨다.
그런데 만약 GKE였다면? 아니면 워크로드가 지금보다 훨씬 안정적이었다면? 굳이 옮겼을까 싶다. 도구 선택은 결국 컨텍스트 문제라는 뻔한 결론이지만, 이번엔 정말 그랬다.
혹시 마이그레이션 고민 중인 분 있으면 댓글로 상황 공유해주시면 좋겠다. 우리도 아직 튜닝 중이다.
태그: Karpenter, ClusterAutoscaler, EKS, Kubernetes, 오토스케일링, DevOps
'IT > Kubernets' 카테고리의 다른 글
| KEDA 도입 가이드 - HPA만으로는 부족했던 순간들 (0) | 2026.08.21 |
|---|---|
| Native sidecar 마이그레이션, 이거 하나만 조심하면 된다 (0) | 2026.08.20 |
| kube-scheduler Preemption 내부 동작, 왜 내 PriorityClass는 예상대로 안 미나 (0) | 2026.08.19 |
| In-place Pod Resize, GA는 됐지만 우리 팀은 아직 조심스럽게 쓴다 — 내부 동작과 함정 (0) | 2026.08.16 |
| Karpenter consolidation 내부 동작 파헤치기 — 노드가 사라지기까지 (0) | 2026.08.14 |