TT Lab
요금제

한국어

시작하기
블로그

블로그

학생 VM 이 뜨기까지 2: KubeVirt 안쪽 — VM 은 왜 파드 안에서 도는가

상태: 초안 (2026-10-16), 공식 문서 + 일부 실측. 구성요소 설명은 KubeVirt 저장소의 구성요소 문서와 사용자 안내서를 2026-10-16 에 열어 확인했습니다. 버전은 KubeVirt v1.9.0 입니다. 「실측」 표시가 붙은 값은 TT Lab 의 실습 VM 에서 잰 것입니다. 작성 규칙: 실측 데이터가 기본이고, 못 잰 것은 「미실측」, 문서에서 찾지 못한 것은 「미확인」으로 표시합니다.

학생 VM 이 뜨기까지 2: KubeVirt 안쪽

목차

1편의 ⑥ 「VM → VMI → 파드 → QEMU」 를 엽니다.

1. VirtualMachine 과 VirtualMachineInstance

KubeVirt 를 처음 보면 비슷한 이름의 객체 둘에서 헷갈립니다.

VirtualMachine (VM) VirtualMachineInstance (VMI)
뜻 「이런 VM 이 있고, 켜 둘지 말지」 라는 바라는 상태 지금 실제로 돌고 있는 실행 하나
수명 지울 때까지 남는다 VM 을 끄면 사라지고, 켜면 새로 생긴다
비유 디플로이먼트 파드

TT Lab 백엔드는 VM 만 만듭니다. 매니페스트에 running: true 를 적어 만들자마자 켜게 합니다. KubeVirt 에는 같은 일을 더 세밀하게 정하는 runStrategy(Always·RerunOnFailure·Once·Manual·Halted)가 있고 둘은 함께 쓸 수 없습니다. 코드 주석은 running 을 사용 중단 예정으로 적어 두었지만, 실행 전략 안내서에서는 그 문장을 찾지 못했습니다(미확인). 이미 도는 VM 과 동작을 맞추려고 아직 바꾸지 않았습니다. 상태를 볼 때는 VMI 를 읽습니다. VMI 가 없으면 「켜지는 중」, VM 까지 없으면 「사라짐」 으로 판단합니다.

2. 네 구성요소

VM 한 대 = 파드 하나 안의 QEMU 프로세스 컨트롤 플레인 kube-apiserver virt-api virt-controller 검증·기본값·서브리소스 객체를 보고 만든다 VM 켜 둘지 VMI 지금 도는 것 파드 virt-launcher 노드 (KVM 이 되는 곳) virt-handler 데몬셋 · 노드마다 VMI 를 켜고 끈다 kubelet 파드를 띄운다 virt-launcher 파드 virt-launcher (감시·신호 전달) libvirtd (도메인 관리) QEMU 프로세스 게스트 OS · systemd · root /dev/kvm 으로 하드웨어 가속 볼륨: 컨테이너 디스크 · emptyDisk PVC · cloud-init Secret 실측(2 vCPU · 4Gi VM): 파드 요청 CPU 200m · 메모리 4372Mi vCPU 하나에 CPU 0.1 개(할당 비율 기본 10), 메모리는 게스트 + 약 280Mi 파드라서 공짜로 얻는 것: 스케줄링 · 자원 요청 · 파드 네트워크 · 정책
그림: VM 한 대는 파드 하나 안의 QEMU 프로세스다

KubeVirt 저장소의 구성요소 문서가 설명하는 역할을 요약하면 이렇습니다.

만드는 순서는 문서에 일곱 단계로 나와 있습니다. VMI 가 만들어지면 virt-controller 가 파드를 만들고, 스케줄러가 노드에 앉히고, 파드가 시작되면 virt-controller 가 VMI 에 노드 이름을 적고, 그때부터 그 노드의 virt-handler 가 넘겨받아 파드 안의 libvirtd 에게 도메인을 만들게 합니다. 1편의 실측(Pending 0초 → Scheduled 10초 → Running 20초)은 이 사이를 잰 것입니다.

3. 왜 VM 을 파드 안에 넣나

처음에는 이상해 보입니다. VM 이 컨테이너보다 무거운 격리인데 왜 그것을 다시 컨테이너 안에 넣을까요. 답은 「쿠버네티스가 이미 잘하는 일을 다시 만들지 않으려고」 입니다. TT Lab 에서 실제로 덕을 본 것을 꼽으면 이렇습니다.

  1. 스케줄링과 자원 계산. VM 의 CPU·메모리는 파드의 자원 요청이 되어 스케줄러가 그대로 계산합니다. 2 vCPU·4Gi VM 하나의 파드 요청을 재 보니 CPU 200m, 메모리 4372Mi 였습니다(실측, 2026-08-29). vCPU 하나에 CPU 0.1개만 요청하는 것은 KubeVirt 의 cpuAllocationRatio 기본값이 10이기 때문이고(사용자 안내서 「Resources requests and limits」), 메모리는 게스트 4Gi 에 약 280Mi 의 오버헤드가 붙었습니다.
  2. 네트워크와 정책. 게스트는 파드 네트워크를 그대로 씁니다(masquerade). 그래서 실습 파드에 쓰던 네트워크 정책을 VM 에도 같은 방식으로 겁니다. 정책이 고르는 대상은 VM 이 아니라 virt-launcher 파드의 라벨입니다. 실제 네트워크 엔드포인트가 그 파드이기 때문입니다(6편).
  3. 볼륨. 게스트의 디스크는 파드의 볼륨입니다. PVC 를 붙이는 일, 노드 로컬 임시 디렉터리를 만드는 일, Secret 을 넣는 일을 쿠버네티스가 합니다(3·4편).
  4. 수명. 파드가 지워지면 VM 도 끝나고, 파드에 딸린 임시 볼륨도 함께 사라집니다. 회수가 쉬워집니다(5편).

대가도 있습니다.

4. KVM: 하드웨어 가속

게스트는 QEMU 가 KVM(/dev/kvm)을 써서 하드웨어 가속으로 돌립니다. KubeVirt 는 KVM 이 되는 노드에 장치 플러그인 자원(devices.kubevirt.io/kvm)을 내놓고, virt-launcher 파드가 그 자원을 요청합니다. 그래서 KVM 이 안 되는 노드에는 VM 이 앉지 않습니다.

게스트 안에서 또 가상화를 돌려야 하는 실습(VM 안에서 VM 을 띄우는 실습)은 CPU 모델을 host-passthrough 로 바꿉니다. 기본 CPU 모델은 하드웨어 가상화 플래그를 감추기 때문에, 그대로 두면 게스트 안의 QEMU 가 소프트웨어 에뮬레이션으로만 돌아 부팅이 몇 분씩 걸립니다. host-passthrough 를 켜니 게스트 안에 /dev/kvm 이 생기고 lscpu 에 가상화 플래그가 보였습니다(실측, 2026-08-29). 대가는 마이그레이션입니다. 노드마다 CPU 모델이 다르면 옮길 수 없습니다. 실습 VM 은 어차피 옮기지 않으므로 받아들이되, 필요 없는 실습에는 켜지 않습니다.

5. 게스트 안에서 명령을 못 돌린다

파드에는 exec 가 있어 백엔드가 파드 안에서 채점 명령을 돌립니다. KubeVirt 의 VMI 서브리소스에는 console·vnc·portforward·guestosinfo 같은 것은 있어도 exec 가 없습니다(실측으로 서브리소스 목록을 확인). 게스트는 별개의 운영체제이고, 그 안에서 명령을 돌리는 일은 게스트에 무언가가 있어야만 가능하기 때문입니다.

그래서 TT Lab 은 게스트에 작은 채점 에이전트를 심었습니다(1편 ③). 학생의 셸은 시리얼 콘솔(console 서브리소스)로 엽니다. SSH 를 열지 않아도 되니 접속 경로가 하나 줄어듭니다. 실제로 시제품에서 SSH 를 아예 끈 채로도 채점이 됐습니다.

6. 실제로 겪은 일: 기능 게이트 하나에 VM 이 전혀 뜨지 않았다

KubeVirt v1.9.0 을 처음 깔았을 때 VM 이 하나도 뜨지 않았습니다. virt-launcher 파드가 이런 오류로 죽었습니다.

exec: "/container-disk-binary/usr/bin/container-disk": no such file or directory

컨테이너 런타임 설정이 망가진 줄 알았지만 원인은 다른 데 있었습니다. KubeVirt 1.9 가 베타 단계의 기능 게이트를 기본으로 켜면서 ImageVolume 이 저절로 켜졌습니다. 이 기능은 컨테이너 디스크를 파드의 이미지 볼륨으로 붙이는데, 쿠버네티스 1.34 쪽은 그 게이트가 꺼져 있어서 API 서버가 이미지 볼륨과 그 마운트를 조용히 지웠습니다. 파드는 거부되지 않고 받아들여지므로 어디에도 경고가 남지 않습니다. 실행 중인 파드의 스펙에서 이미지 볼륨이 비어 있는 것을 보고서야 확정했습니다. 컨테이너 런타임도 두 번째 관문이었습니다. 이미지 볼륨을 지원하는 것은 containerd 2.1 부터라, 쿠버네티스 게이트만 켰다면 조용한 삭제가 마운트 실패로 바뀌었을 뿐입니다.

KubeVirt 쪽 게이트를 꺼서 예전 방식(빈 디렉터리와 복사용 초기화 컨테이너)으로 돌렸습니다. 이 설정은 KubeVirt 의 사용자 정의 리소스에 들어가므로 KubeVirt 를 올릴 때마다 다시 확인해야 합니다. 글을 쓰는 날에도 꺼진 게이트 목록에 ImageVolume 이 그대로 있는 것을 읽어서 확인했습니다.

교훈은 이렇습니다. 「파드 안의 VM」 은 쿠버네티스와 KubeVirt 와 컨테이너 런타임, 세 버전의 교집합 위에 섭니다. 하나만 올리면 다른 둘과의 약속이 조용히 깨질 수 있습니다.

7. 한계

티티 한마디. VM 을 파드 안에 넣는 게 처음엔 「상자 안에 더 큰 상자」 같지만, 덕분에 스케줄링도 네트워크 정책도 볼륨도 쿠버네티스가 대신 해 줘요. 대신 버전 셋이 맞물려 돌아간다는 걸 꼭 기억하세요. 하나만 올렸다가 VM 이 조용히 안 뜰 수 있어요!

참고

문서는 모두 2026-10-16 에 열람했습니다.

로그인하면 좋아요를 누를 수 있습니다

댓글

아직 댓글이 없습니다.

로그인하면 댓글을 쓸 수 있습니다