- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 들어가며
- 1. KVM: 왜 VM이 "빠르게" 돌 수 있는가
- 2. namespace: 왜 Pod가 VM 실행 샌드박스가 될 수 있는가
- 3. cgroup: VM도 결국 호스트 자원 제약을 받아야 한다
- 4. TAP: guest NIC와 호스트 네트워크를 잇는 핵심 장치
- 5. netlink: 네트워크는 결국 커널 객체 조작이다
- 6. nftables: masquerade binding의 실제 데이터 plane
- 7. VFIO: SR-IOV와 장치 passthrough의 기반
- 8. seccomp와 장치 허용 목록도 커널 문제다
- 왜 Kubernetes만으로는 이 일을 할 수 없을까
- 자주 하는 오해
- 운영자가 기억해야 할 핵심
- 마무리
들어가며
KubeVirt를 깊이 이해하려면 Go controller 코드만 읽어서는 부족하다. 결국 이 시스템이 가능해지는 이유는 리눅스 커널과 호스트 런타임이 제공하는 primitive 덕분이다. KubeVirt는 새로운 하이퍼바이저를 만든 것이 아니라, 기존 커널 기능과 QEMU, libvirt를 Kubernetes 리소스 모델에 엮는 시스템이다.
이번 글에서는 그 기반이 되는 커널 기술을 정리한다.
1. KVM: 왜 VM이 "빠르게" 돌 수 있는가
가장 핵심은 /dev/kvm이다. pkg/virt-handler/node-labeller/util/util.go는 아예 KVMPath = "/dev/kvm"을 상수로 둔다. 이는 KubeVirt가 하드웨어 가상화 가속 가능 여부를 매우 중요하게 본다는 뜻이다.
QEMU만으로도 에뮬레이션은 가능하지만, 성능은 크게 떨어질 수 있다. KVM은 guest의 많은 CPU 실행 경로를 하드웨어 가상화로 넘겨 성능을 끌어올린다.
즉 KubeVirt가 실전 VM 플랫폼처럼 동작하려면 결국 /dev/kvm 접근이 가능해야 한다.
2. namespace: 왜 Pod가 VM 실행 샌드박스가 될 수 있는가
Pod는 단순한 배포 묶음이 아니라 namespace 집합이다.
- network namespace
- mount namespace
- PID namespace
QEMU는 결국 리눅스 프로세스다. 따라서 이 namespace 경계 안에서 실행될 수 있다. 이것이 "VM이 Pod 위에서 돈다"는 말의 가장 현실적인 의미다.
KubeVirt의 virt-chroot 계열 코드를 보면 특정 mount namespace에 들어가 mount나 SELinux 연산을 수행하는 기능이 나온다. 즉 KubeVirt는 namespace를 추상적 개념이 아니라, 실제 운영 도구로 적극 사용한다.
3. cgroup: VM도 결국 호스트 자원 제약을 받아야 한다
VM이라고 해서 host 자원 제약 밖에 있으면 안 된다. QEMU와 관련 thread도 결국 리눅스 프로세스이므로 cgroup 제약을 받아야 한다.
cmd/virt-chroot/cgroup.go, pkg/virt-handler/cgroup/*, vm.go를 보면 KubeVirt가 cgroup v1과 v2 차이, device allow list, cpuset, block device 규칙까지 신경 쓰는 것을 알 수 있다.
즉 KubeVirt는 "Pod request" 수준에서 끝나지 않고, 실제 VM 실행 프로세스에 정확한 cgroup 리소스 제약을 적용하려 한다.
4. TAP: guest NIC와 호스트 네트워크를 잇는 핵심 장치
TAP 장치는 guest가 보는 가상 NIC와 host 또는 Pod 쪽 네트워크를 이어 주는 대표적인 백엔드다. cmd/virt-chroot/tap-device-maker.go와 pkg/network/setup/podnic.go가 이를 잘 보여준다.
guest 관점에서는 virtio-net 같은 가상 NIC가 보이지만, host 쪽에서는 결국 TAP 장치와 bridge, NAT 규칙이 패킷을 이어준다.
즉 TAP은 guest와 Pod namespace 네트워크 사이의 실질적인 문이다.
5. netlink: 네트워크는 결국 커널 객체 조작이다
KubeVirt 네트워크 코드가 netlink를 많이 쓰는 이유는 bridge, 주소, 링크 상태, TAP, MTU 설정이 전부 커널 네트워크 객체이기 때문이다.
예를 들어:
- TAP 생성
- MTU 설정
- bridge 주소 계산
- masquerade gateway와 guest IP 계산
이런 작업은 단순 파일 편집이 아니라 커널 네트워크 상태 조작이다.
즉 KubeVirt networking은 "YAML -> CNI"만의 문제가 아니라, namespace 내부 Linux 네트워크 stack 조작이다.
6. nftables: masquerade binding의 실제 데이터 plane
pkg/network/setup/netpod/masquerade/masquerade.go는 masquerade binding에서 nftables 규칙을 구성한다. 이건 중요한 포인트다.
많은 사용자가 NAT를 추상적으로 생각하지만, 실제로는:
- NAT table
- prerouting
- postrouting
- dnat
- snat
- masquerade
규칙이 커널 패킷 경로에 들어간다.
즉 KubeVirt의 guest egress와 일부 inbound 모델은 userspace 마법이 아니라 커널 packet filtering과 NAT 기능 위에 서 있다.
7. VFIO: SR-IOV와 장치 passthrough의 기반
docs/network/sriov.md와 virtwrap/device/hostdevice 계열 코드를 보면 SR-IOV와 장치 passthrough는 VFIO 모델에 기대고 있다. guest에 장치를 직접 넘기려면 host 커널이 장치를 안전하게 user space hypervisor에 위임할 수 있어야 한다.
그래서 SR-IOV는 단순 네트워크 기능이 아니라:
- IOMMU
- VFIO
- device plugin
- libvirt hostdev 설정
이 함께 맞아야 하는 커널과 하드웨어 기능 집합이다.
8. seccomp와 장치 허용 목록도 커널 문제다
virt-handler는 seccomp 프로필도 설치한다. 또 hotplug block device 경로에서는 cgroup device rule을 조정한다. 이는 "QEMU는 단순 privileged process라서 다 된다"가 아니라, 필요한 syscall과 device 접근만 허용하는 방향으로 시스템을 설계했다는 뜻이다.
즉 커널 primitive는 성능뿐 아니라 보안 경계에서도 핵심이다.
왜 Kubernetes만으로는 이 일을 할 수 없을까
Kubernetes는 Pod를 배치하고 볼륨과 네트워크를 준비해 준다. 하지만:
/dev/kvm을 어떻게 쓸지- TAP을 어떻게 만들지
- libvirt와 QEMU를 어떻게 연결할지
- guest memory와 device state를 어떻게 옮길지
같은 가상화-specific 문제는 직접 풀지 않는다. KubeVirt는 바로 이 틈을 메운다. 다만 밑바탕은 여전히 리눅스 커널 기능이다.
자주 하는 오해
오해 1: KubeVirt는 Kubernetes 내부에 가상화 엔진을 추가한다
아니다. 가상화 엔진 자체는 KVM과 QEMU, libvirt다. KubeVirt는 이를 Kubernetes와 통합한다.
오해 2: Pod 위에서 돌면 커널 기술은 별로 중요하지 않다
반대다. Pod라는 포장지를 쓰더라도 실제 실행은 커널 namespace, cgroup, KVM, netlink, nftables 위에서 이뤄진다.
오해 3: 네트워크와 장치는 대부분 userspace 로직이다
아니다. 중요한 부분은 계속 커널 객체와 커널 정책을 건드린다.
운영자가 기억해야 할 핵심
- VM 문제는 종종 Kubernetes 문제가 아니라 host kernel 문제다.
/dev/kvm, cpuset, cgroup device rule, TAP, nftables 상태를 함께 봐야 한다.- SR-IOV와 VFIO는 하드웨어, BIOS, 커널, CNI, libvirt가 모두 맞아야 한다.
마무리
KubeVirt가 Pod 위에서 VM을 구현할 수 있는 이유는 Kubernetes가 모든 것을 해주기 때문이 아니라, 리눅스 커널이 이미 강력한 가상화와 격리 primitive를 제공하기 때문이다. KVM은 CPU 가속을, namespace와 cgroup은 실행 경계를, TAP과 netlink는 guest 네트워크 연결을, nftables는 NAT를, VFIO는 장치 passthrough를 가능하게 한다. KubeVirt는 바로 이 primitive들을 Kubernetes 리소스 모델 위에서 조합하는 시스템이다.
다음 글에서는 이 커널 경계 위에 놓인 보안 경계, 즉 SELinux, seccomp, device access와 관련된 KubeVirt의 보안 모델을 살펴보겠다.