IT/Kubernets

Karpenter vs Cluster Autoscaler, 우리 팀이 옮긴 이유

gfrog 2026. 8. 20. 06:17

작년 이맘때까지 우리 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로 이미 최적화가 잘 돼 있을 가능성이 높다.

마이그레이션 팁

가장 무섭게 들었던 얘기가 "한번에 갈아엎지 마라"였는데 실제로 해보니 정말 그렇다. 우리는 이렇게 했다.

  1. Karpenter를 Cluster Autoscaler와 나란히 설치한다. 처음엔 Karpenter NodePool의 리소스 상한을 아주 낮게 잡는다.
  2. 새로운 워크로드부터 Karpenter로 흘려보낸다. nodeSelector나 taint로 명시적으로 분리한다.
  3. 안정성이 확인되면 기존 노드 그룹의 desired를 서서히 줄이고, 파드가 Karpenter 노드로 재스케줄되는 걸 확인한다.
  4. 노드 그룹을 완전히 비운 뒤 Cluster Autoscaler를 제거한다.

각 단계마다 롤백이 가뉥하다는 게 중요하다. 갑자기 뭔가 이상하면 다시 Cluster Autoscaler 쪽으로 웨이트를 옮기면 되니까.

한 가지 삽질 포인트를 남기자면, PDB(PodDisruptionBudget)를 잘 걸어두지 않으면 consolidation이 서비스에 영향을 줄 수 있다. Karpenter는 상대적으로 파드를 자주 옮기기 때문에, PDB가 없으면 예상 못 한 순간에 파드가 재시작된다. 우리도 이걸로 한 번 놀랐다.

그래서

우리 팀 상황에서는 Karpenter가 맞았다. 트래픽 변동이 크고, 인스턴스 타입에 특별한 제약도 없고, spot을 적극적으로 쓰고 싶었으니까. 25% 노드 감소는 예상보다 큰 숫자였고, 프로비저닝 속도가 45~60초로 빨라진 건 배포 경험 자체를 바꿨다.

그런데 만약 GKE였다면? 아니면 워크로드가 지금보다 훨씬 안정적이었다면? 굳이 옮겼을까 싶다. 도구 선택은 결국 컨텍스트 문제라는 뻔한 결론이지만, 이번엔 정말 그랬다.

혹시 마이그레이션 고민 중인 분 있으면 댓글로 상황 공유해주시면 좋겠다. 우리도 아직 튜닝 중이다.


태그: Karpenter, ClusterAutoscaler, EKS, Kubernetes, 오토스케일링, DevOps