Skip to content
Published on

CPU, Memory, NUMA, HugePages: KubeVirt는 자원 모델을 어떻게 맞추는가

Authors

들어가며

VM 자원 모델은 컨테이너보다 더 까다롭다. 사용자는 guest에 4 vCPU와 16 GiB 메모리를 주고 싶어 하지만, 실제로는 launcher Pod, QEMU 오버헤드, emulator thread, hugepages, NUMA locality까지 함께 고려해야 한다. KubeVirt는 이 간극을 메우기 위해 guest 자원 모델과 Pod 자원 모델을 동시에 관리한다.

이번 글은 staging/src/kubevirt.io/api/core/v1/schema.go, pkg/virt-controller/services/template.go, pkg/virt-launcher/virtwrap/manager.go를 중심으로 이 자원 번역 레이어를 본다.

guest 자원과 Pod 자원은 왜 다를까

컨테이너는 보통 "프로세스가 쓰는 자원"이 곧 Pod 자원이다. 하지만 VM은 다르다.

  • guest가 보는 메모리
  • QEMU와 가상화 인프라가 추가로 쓰는 메모리
  • I/O thread와 emulator thread
  • page table, device emulation, virtio queue overhead

이런 요소 때문에 launcher Pod는 guest 메모리보다 더 많은 메모리를 요청해야 할 수 있다.

즉 KubeVirt가 하지 않으면 스케줄러는 VM을 지나치게 낙관적으로 배치하게 된다.

API 스키마가 이미 이 문제를 드러낸다

schema.go를 보면 CPU와 메모리 관련 필드가 꽤 풍부하다.

  • CPU
  • CPUTopology
  • NUMA
  • Hugepages
  • MemoryOverhead

이는 KubeVirt가 "CPU 몇 개 주세요" 정도의 단순한 추상화에 머물지 않고, 실행 성능과 배치 안정성까지 API로 다루려는 시스템이라는 뜻이다.

launcher Pod 자원은 누가 계산하는가

이 역할은 주로 pkg/virt-controller/services/template.go가 맡는다. 여기서 CalculateMemoryOverhead가 호출되고, launcher Pod에 필요한 실제 자원 request와 limit가 만들어진다.

핵심은 다음이다.

  • guest 메모리만 반영하지 않는다
  • 가상화 인프라 오버헤드를 더한다
  • 네트워크 binding plugin이 요구하는 추가 메모리도 고려할 수 있다
  • hugepages 여부에 따라 Pod 자원 종류 자체가 달라진다

즉 VMI spec는 직접 Pod spec가 되지 않는다. 중간에 자원 보정 단계가 있다.

Memory overhead는 왜 중요한가

schema.go에는 MemoryOverhead 설명이 있고, template.go는 memory overhead를 annotation과 status로도 다룬다. migration 상태에는 target memory overhead도 따로 있다.

이건 매우 중요하다. 예를 들어 guest가 8 GiB만 본다고 해서 launcher Pod도 8 GiB만 요청하면:

  • node pressure에 취약해지고
  • QEMU 또는 부가 thread가 OOM에 걸릴 수 있으며
  • migration target에서도 자원 계산이 어긋날 수 있다

즉 KubeVirt는 "guest memory"와 "launcher envelope memory"를 분리해 본다.

CPU topology는 왜 guest 수치와 다를 수 있는가

KubeVirt의 CPUTopology는 sockets, cores, threads를 표현한다. 하지만 Kubernetes 스케줄러가 보는 것은 결국 launcher Pod의 CPU request와 limit다.

여기서 중요한 경우가 dedicated CPU다. dedicated CPU를 요청하면:

  • CPU pinning이 필요하고
  • launcher Pod는 더 엄격한 자원 보장이 필요하며
  • migration target도 적합한 CPU topology를 가진 노드를 찾아야 한다

manager.goUpdateVCPUs를 보면 dedicated CPU일 때 domain spec와 pod cpuset을 읽어 PinVcpuFlagsPinEmulator를 호출한다. 즉 이건 단순 quota 문제가 아니라 pCPU 배치 문제다.

NUMA는 왜 API에 들어 있을까

schema.goNUMANUMAGuestMappingPassthrough 설명은 매우 의미심장하다. KubeVirt는 guest NUMA topology를 host CPU pinning과 호환되도록 모델링하려고 한다.

이게 중요한 이유는 성능 때문이다.

  • NUMA locality가 맞으면 메모리 접근 지연이 줄어든다
  • CPU와 메모리가 다른 NUMA node에 흩어지면 성능이 흔들릴 수 있다
  • device passthrough와 결합되면 더 민감해진다

즉 KubeVirt는 NUMA를 "고급 옵션"이 아니라, 고성능 VM 운영에서 필수적인 topology constraint로 본다.

HugePages는 무엇이 달라지는가

HugePages를 켜면 메모리가 일반 페이지와 다른 자원 클래스로 취급된다. schema.gotemplate.go는 hugepages page size를 Pod resource로도 반영한다.

이 말은 곧:

  • guest 메모리 정책이 Pod 스케줄링 자원 종류에 직접 영향을 미치고
  • 노드에 해당 hugepage pool이 없으면 스케줄 자체가 안 될 수 있으며
  • free page reporting이나 일부 메모리 기능 동작도 달라질 수 있다

는 뜻이다.

즉 hugepages는 "성능 체크박스"가 아니라 스케줄링과 커널 메모리 모델 전체를 바꾸는 선택이다.

migration과 자원 모델은 어떻게 연결되는가

migration 시 target node는 source와 같은 guest를 수용해야 한다. 그런데 dedicated CPU, NUMA, hugepages, memory overhead가 있으면 target 조건이 훨씬 까다로워진다.

실제로 migration status에는:

  • target node topology
  • target memory overhead

같은 정보가 들어간다. 이는 migration이 단순히 "빈 노드 아무데나"로 가는 작업이 아니라, 같은 성능 특성을 유지할 수 있는 노드로 옮기는 작업임을 보여준다.

자주 하는 오해

오해 1: guest가 8 GiB면 Pod도 8 GiB면 충분하다

아니다. virtualization overhead가 있고, binding plugin이나 부가 기능도 메모리를 더 먹을 수 있다.

오해 2: CPU request만 맞으면 dedicated CPU도 문제없다

아니다. pinning과 topology, cpuset이 맞아야 한다.

오해 3: NUMA와 hugepages는 성능 튜닝용 옵션일 뿐이다

아니다. 스케줄링 조건과 migration 가능성까지 바꾼다.

운영자가 먼저 봐야 할 것

  • guest 메모리와 launcher memory overhead를 구분해서 본다.
  • dedicated CPU라면 cpuset과 pinning 경로를 본다.
  • hugepages 요청이면 노드 hugepage pool을 먼저 확인한다.
  • migration 실패면 target node topology와 target memory overhead를 본다.

마무리

KubeVirt는 VMI의 CPU와 메모리 요청을 그대로 Pod request로 던지지 않는다. 대신 memory overhead를 더하고, dedicated CPU와 NUMA, hugepages를 반영해 launcher Pod와 guest 하드웨어 모델을 함께 맞춘다. 이 구조 덕분에 Kubernetes 스케줄러는 VM을 어느 정도 올바르게 배치할 수 있고, guest는 더 예측 가능한 성능 특성을 얻는다.

다음 글에서는 이런 자원 모델을 실제로 가능하게 만드는 host primitive, 즉 /dev/kvm, namespace, cgroup, TAP, netlink 같은 커널 기술을 살펴보겠다.