노드 오토스케일러와 스케줄러는 왜 서로 다른 답을 내는가?

결론부터 말하면, 오토스케일러는 "클러스터 전체 여유 CPU"가 아니라 "스케줄러 제약을 만족하는 노드가 있는가"를 본다. 이 두 질문이 다르기 때문에 파드가 Pending 상태로 남거나, 노드를 늘려도 배치가 풀리지 않는 상황이 생긴다. 이번 분석에서는 스케줄러 제약 → 오토스케일 판단 → 런타임 초기화 → 네트워크 경로, 이 네 계층을 분리해 어디서 지연이 생기고 어디서 해결되는지를 뜯어본다.

  • 노드 증설 여부를 가르는 것은 전체 여유 자원이 아니라 nodeSelector·nodeAffinity·taint/toleration·topology spread 같은 배치 조건이다[nodeAffinity, taint, topology spread 기준]
  • 오토스케일링 지연(스케줄러 감지→노드 선택→부팅→kubelet/CNI/이미지 풀)은 애플리케이션 지연과 별개로 누적되며, 이 구간에서는 런타임 선택이 전체 병목을 못 가린다
  • WASM은 AoT 컴파일 조건에서 콜드스타트를 최대 16% 줄이지만, 인터프리터 방식·고동시성 조건에서는 컨테이너보다 느릴 수 있다
  • eBPF 기반 네트워킹(Cilium)은 패킷 전달·정책 처리 비용을 줄이지만, 배치 실패(Pending) 자체는 해결하지 못한다
  • 세 계층(스케줄링·런타임·네트워킹)의 병목을 분리해 측정하지 않으면 단일 벤치마크 수치가 실제 서비스 지연을 설명하지 못한다

이 글이 다루는 범위는 Kubernetes 기본 스케줄러 플러그인(NodeResourcesFit, NodeAffinity, PodTopologySpread, InterPodAffinity)과 Cluster Autoscaler·Karpenter 계열 오토스케일러, 컨테이너/WASM 런타임 콜드스타트, eBPF 기반 CNI까지다. GPU 스케줄링이나 멀티클러스터 연합 스케줄링은 다루지 않는다.

스케줄러 제약이 노드 증설 판단을 어떻게 비트는가?

스케줄러가 파드를 특정 노드 풀에만 배치하도록 강제하면, 오토스케일러는 일반 노드가 아니라 조건을 만족하는 풀을 증설해야 한다. 가장 흔한 충돌 조건은 podAntiAffinity와 topology spread다. 파드를 가용영역·노드·랙 단위로 분산시키도록 강제하면, 노드 수가 부족한 순간 파드는 Pending 상태가 되고 오토스케일러가 새 노드를 추가한다. 문제는 반대 방향에서 생긴다. 제약이 지나치게 강하면 새 노드를 추가해도 조건을 만족하지 못해 파드가 계속 Pending 상태로 남을 수 있다.

예를 들어 3개 가용영역에 각각 1개씩만 배치하도록 강제하는 topology spread를 걸어두고, 해당 가용영역의 노드 풀이 인스턴스 타입 재고 문제로 증설되지 않으면, 오토스케일러는 다른 가용영역에 노드를 아무리 늘려도 그 파드를 배치할 수 없다. 이 경우 로그상으로는 "노드가 추가됐는데 파드가 여전히 Pending"이라는, 운영자 입장에서 가장 헷갈리는 상태가 남는다. 스케줄러 제약과 노드 풀 구성을 같이 설계하지 않으면 오토스케일러는 맹목적으로 노드만 늘리는 역할에 그친다.

파드가 Pending 상태에서 소비하는 시간은 어디에 쌓이는가?

전체 지연은 스케줄러 감지, 오토스케일러의 노드 풀 선택, 클라우드 인스턴스 부팅, kubelet·CNI·이미지 풀 완료까지 순차적으로 쌓인다. 이 경로 중 어느 하나라도 느리면 뒷단의 런타임 최적화는 체감되지 않는다. 즉 WASM의 빠른 초기화만으로는 전체 콜드스타트를 해결할 수 없다. 노드 프로비저닝이 병목이면 런타임 선택의 효과는 그 뒤에 묻힌다.

실무에서 재현 조건을 기록할 때는 이 구간을 통째로 "지연"이라고 뭉뚱그리지 말고 단계별로 쪼개야 한다. 스케줄러가 파드를 Pending으로 표시한 시각, 오토스케일러가 스케일업을 트리거한 시각, 클라우드 인스턴스가 Running 상태가 된 시각, kubelet이 Ready를 보고한 시각, 이미지 풀이 끝난 시각을 각각 기록하면 어느 구간이 실제 병목인지 드러난다. 인스턴스 타입이 희소하거나 쿨다운 설정이 길면 노드 부팅 구간이 전체 지연의 대부분을 차지하는 경우가 흔하다.

런타임을 바꾸면 이 지연이 실제로 줄어드는가?

줄어들 수는 있지만 조건부다. 2025년 Lumos 연구는 AoT 컴파일 WASM 이미지가 컨테이너보다 최대 30배 작고, 콜드스타트 지연을 최대 16% 줄였다고 보고했다. 다만 같은 연구에서 인터프리터 방식 WasmEdge는 워밍 상태 지연이 30~55배 높았고, I/O 직렬화 오버헤드는 7~10배 높았다. 높은 동시성 조건의 인터프리터 WASM은 컨테이너보다 최대 27배 높은 지연과 약 2배 낮은 처리량을 보였다. "WASM = 저지연"이라는 일반화는 AoT·인터프리터·동시성 수준을 섞어 말할 때 생기는 오류다.

2025년 WAMR과 crun 통합 연구는 기존 WASM 런타임 대비 컨테이너당 메모리를 11~78% 줄였고, 6개 런타임 중 4개보다 컨테이너 시작 시간이 빨랐다. Python 컨테이너 대비로는 메모리 최소 16%, 시작 시간 3~18% 감소가 보고됐다. HybridServe 연구는 Wasmtime·Wasmer·WasmEdge를 비교해 WASM이 콜드스타트를 최대 88.1%, 이미지 크기를 최대 99.17% 줄일 수 있지만, 계산 중심 작업에서는 실행 시간이 36.15% 느리고 전력 소비가 9.26% 높다고 보고했다. 짧은 작업이 폭증하는 서버리스·엣지 워크로드에는 WASM을, 지속 실행·계산 집약 작업에는 컨테이너를 쓰는 하이브리드 정책이 합리적인 이유가 여기에 있다.

실측에서 네트워킹 계층은 얼마나 차이를 만드는가?

Cilium 공식 벤치마크는 100Gbps로 연결된 두 베어메탈 노드에서 컨테이너 간 통신을 측정했고, eBPF 기반 경로가 정책 적용과 네트워크 네임스페이스 전달을 수행하면서도 iptables 기준 경로보다 높은 성능을 낼 수 있다고 설명한다(Cilium Benchmark).

Azure CNI powered by Cilium의 eBPF host routing 실험은 조건이 구체적이다. AKS Kubernetes 1.33, Ubuntu 24.04, 16코어 노드에서 netperf의 TCP_STREAM을 20초씩 실행했고, 지연은 TCP_RR로 측정했다(Azure CNI powered by Cilium). 같은 노드의 Pod-to-Pod 처리량은 약 30% 개선됐고, 작은 메시지의 노드 간 트래픽에서는 최대 3배 차이가 나타났으며, 트랜잭션 처리량은 약 27% 증가했다.

2026년 기준 비교 자료는 Calico 3.28, Cilium 1.16, Flannel을 대상으로 다음 수치를 제시한다.

CNI 평균 지연 처리량 CPU 사용률
Calico 3.28 약 2.8ms 8.4Gbps –
Cilium 1.16 약 1.6ms 9.2Gbps 31%
Flannel 약 1.1ms 9.5Gbps –

Cilium은 처리량·지연에서 앞섰지만 CPU 사용률이 31%로 측정됐다. 이 수치는 해당 자료의 실험 환경에 한정된 결과이며, 모든 클러스터에 그대로 적용할 근거는 아니다.

세 계층을 동시에 최적화하면 무엇을 얻고 무엇을 잃는가?

얻는 것은 지연 단계별 개선이고, 잃는 것은 운영 복잡도다. 스케줄러 정책을 완화하면 Pending 빈도는 줄지만 가용영역 분산이나 장애 격리 수준이 낮아진다. WASM을 서버리스 경로에 투입하면 콜드스타트와 이미지 크기는 줄지만, 계산 집약 작업으로 트래픽 패턴이 바뀌면 HybridServe 실험처럼 실행 시간이 36.15% 느려지고 전력 소비가 9.26% 높아지는 구간에 들어갈 수 있다. eBPF host routing을 도입하면 패킷 전달 지연은 줄지만, CPU 사용률이 올라가는 조합(Cilium 31%)이 함께 따라올 수 있다.

또한 런타임과 CNI를 동시에 교체하면 재현 조건이 늘어 장애 원인을 역추적하기 어려워진다. 스케줄러 제약, 오토스케일러 쿨다운, 런타임 버전, CNI 버전 중 어느 하나만 바꿔도 지연 수치가 달라지므로, 세 계층을 한 번에 바꾸는 변경은 벤치마크 재현성을 떨어뜨린다는 비용이 따른다.

이 하이브리드 정책은 언제 쓰고 언제 쓰지 않아야 하는가?

짧은 요청이 간헐적으로 폭증하는 서버리스·엣지 워크로드, 그리고 Pending 빈도가 노드 풀 부족이 아니라 콜드스타트 지연에서 비롯되는 경우에는 WASM 경로와 eBPF host routing을 함께 적용할 근거가 있다. HybridServe 평가에서는 Azure Functions 트레이스 기준 WASM-only 대비 평균 응답 시간이 43.11% 줄었고, 컨테이너-only 대비 콜드스타트 지연이 91.9% 감소했다.

반대로 지속 실행·계산 집약 작업이 중심이거나, Pending의 원인이 topology spread·nodeAffinity 불일치처럼 순수 배치 문제인 경우에는 런타임이나 네트워킹을 손대도 효과가 없다. 이 경우 먼저 스케줄러 제약과 노드 풀 구성을 재검토해 배치 가능성 자체를 넓히는 작업이 선행돼야 한다. 세 계층 중 어느 것이 실제 병목인지 모른 채 런타임이나 CNI부터 바꾸는 순서는 비용만 늘리고 지연은 그대로 남기는 경우가 많다.

핵심 정리

  • 오토스케일러는 전체 여유 자원이 아니라 스케줄러 제약을 만족하는 노드 풀 존재 여부로 증설을 판단한다
  • podAntiAffinity·topology spread가 과도하면 노드를 늘려도 Pending이 풀리지 않을 수 있다
  • WASM의 콜드스타트 이점은 AoT 컴파일·낮은 동시성 조건에 한정되며, 인터프리터·고동시성 조건에서는 컨테이너보다 느릴 수 있다
  • eBPF(Cilium)는 패킷 전달·정책 처리 지연을 줄이지만 배치 실패는 해결하지 않는다
  • 스케줄링·런타임·네트워킹 세 계층을 분리해 측정해야 단일 벤치마크 수치의 실제 적용 범위를 판단할 수 있다

자주 묻는 질문

Pending 파드가 늘었을 때 가장 먼저 확인할 계층은?

스케줄러 이벤트 로그에서 Pending 사유(Insufficient cpu, node(s) didn't match Pod's node affinity/selector, didn't satisfy existing pods anti-affinity rules)를 먼저 확인해야 한다. 런타임이나 네트워킹보다 배치 조건 불일치가 원인인 경우가 더 흔하며, 이 단계를 건너뛰고 런타임을 교체하면 원인을 놓친다.

WASM과 컨테이너를 같은 클러스터에서 함께 운영할 때 스케줄러 설정은 어떻게 달라지나?

별도의 RuntimeClass로 WASM 워크로드를 구분하고, 짧은 실행 시간이 예상되는 파드에는 더 낮은 리소스 요청량과 별도 노드 풀을 지정하는 방식이 쓰인다. 다만 이 구성이 추가되면 오토스케일러가 확인해야 할 노드 풀 조합이 늘어나므로, 스케일업 쿨다운과 인스턴스 타입 재고를 함께 재검토해야 한다.

eBPF host routing을 도입하면 기존 iptables 기반 CNI 설정을 바로 제거해도 되나?

벤치마크 수치는 특정 커널 버전·노드 사양·링크 속도 조건에 한정되므로, 운영 환경의 커널 버전과 노드 사양이 실험 조건과 다르면 같은 개선폭을 기대하기 어렵다. 전환 전에는 동일한 부하 조건에서 p50·p95·p99 지연과 CPU 사용률을 함께 재측정하는 과정이 필요하다.

더 알아보기

컨테이너 오케스트레이션·런타임: 스케줄링부터 네트워킹까지 — 이 주제의 종합 가이드