Skip to content
Published on

[가상화] 06. KubeVirt: 쿠버네티스 위에서 VM 실행하기

Authors

들어가며

컨테이너와 가상머신(VM)은 서로 대체재가 아닌 보완재입니다. 레거시 애플리케이션, Windows 워크로드, 커널 수준 커스터마이징이 필요한 경우에는 여전히 VM이 필수적입니다. KubeVirt는 쿠버네티스 API를 확장하여 VM을 Pod처럼 관리할 수 있게 해주는 프로젝트입니다.

KubeVirt란?

KubeVirt는 쿠버네티스 네이티브 VM 오케스트레이션 솔루션입니다. 쿠버네티스 API를 확장하여 VM 생명주기를 kubectl로 관리할 수 있습니다.

핵심 특징

  • 쿠버네티스 CRD(Custom Resource Definition)로 VM 정의
  • 기존 쿠버네티스 인프라(네트워킹, 스토리지, 모니터링) 재활용
  • 컨테이너와 VM이 동일 클러스터에서 공존
  • libvirt/QEMU/KVM 기반의 검증된 가상화 스택 활용

CNCF 프로젝트 현황

KubeVirt는 CNCF(Cloud Native Computing Foundation)의 주요 프로젝트입니다.

항목상세
CNCF 레벨Incubating (Graduation 신청 중)
도입 기업41개 이상
CNCF 순위Top 20 프로젝트
GitHub 스타5,000+
주요 사용 기업Red Hat, NVIDIA, ARM, CoreWeave

아키텍처 상세

KubeVirt의 전체 아키텍처를 살펴보겠습니다.

+------------------------------------------------------------------+
|                    Kubernetes Control Plane                        |
|  +------------+  +----------------+  +-------------------------+  |
|  | API Server |  | etcd           |  | Controller Manager      |  |
|  +------+-----+  +----------------+  +-------------------------+  |
|         |                                                         |
|  +------v------------------+                                      |
|  | virt-api                |  <-- API 확장, 유효성 검증           |
|  | (Deployment)            |                                      |
|  +------+------------------+                                      |
|         |                                                         |
|  +------v------------------+                                      |
|  | virt-controller         |  <-- VM/VMI 감시, 생명주기 관리      |
|  | (Deployment)            |                                      |
|  +-------------------------+                                      |
+------------------------------------------------------------------+

+------------------------------------------------------------------+
|                    Worker Node                                     |
|  +-------------------------+                                      |
|  | virt-handler            |  <-- 노드 수준 DaemonSet             |
|  | (DaemonSet)             |                                      |
|  +------+------------------+                                      |
|         |                                                         |
|  +------v------------------+  +-------------------------------+   |
|  | virt-launcher Pod       |  | virt-launcher Pod             |   |
|  |  +------------------+   |  |  +-------------------------+  |   |
|  |  | libvirt          |   |  |  | libvirt                 |  |   |
|  |  |  +------------+  |   |  |  |  +-------------------+  |  |   |
|  |  |  | QEMU/KVM   |  |   |  |  |  | QEMU/KVM         |  |  |   |
|  |  |  | (VM 1)     |  |   |  |  |  | (VM 2)           |  |  |   |
|  |  |  +------------+  |   |  |  |  +-------------------+  |  |   |
|  |  +------------------+   |  |  +-------------------------+  |   |
|  +-------------------------+  +-------------------------------+   |
+------------------------------------------------------------------+

컴포넌트 상세

virt-api

API 서버의 확장 포인트로, VM 관련 API 요청을 처리합니다.

  • Admission Webhook을 통한 VM 스펙 유효성 검증
  • Subresource API 제공 (start, stop, restart, migrate)
  • VNC/Console 프록시 엔드포인트

virt-controller

클러스터 수준 Deployment로, VM과 VMI 리소스를 감시합니다.

  • VM CRD 변경 감지 및 VMI 생성/삭제
  • virt-launcher Pod 스케줄링 요청
  • 라이브 마이그레이션 오케스트레이션
  • VM 상태 동기화

virt-handler

노드 수준 DaemonSet으로, 실제 VM 생명주기를 관리합니다.

  • libvirt와 직접 통신
  • VM 도메인 XML 생성 및 적용
  • 노드 수준 네트워킹 설정
  • 디바이스 핫플러그 처리

virt-launcher

개별 VM마다 생성되는 Pod입니다.

  • libvirt 데몬 실행
  • QEMU/KVM 프로세스 관리
  • VM 콘솔 접근 제공
  • Pod 종료 시 VM 정리(cleanup)

CRD (Custom Resource Definitions)

VirtualMachine (VM)

VM은 가상머신의 선언적 정의입니다. Pod에 대한 Deployment와 유사한 역할을 합니다.

apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: my-vm
  namespace: default
spec:
  running: true
  template:
    metadata:
      labels:
        app: my-vm
    spec:
      domain:
        cpu:
          cores: 2
        memory:
          guest: 4Gi
        devices:
          disks:
            - name: rootdisk
              disk:
                bus: virtio
            - name: cloudinitdisk
              disk:
                bus: virtio
          interfaces:
            - name: default
              masquerade: {}
      networks:
        - name: default
          pod: {}
      volumes:
        - name: rootdisk
          dataVolume:
            name: my-vm-dv
        - name: cloudinitdisk
          cloudInitNoCloud:
            userData: |
              #cloud-config
              hostname: my-vm
              ssh_authorized_keys:
                - ssh-rsa AAAA...

VirtualMachineInstance (VMI)

VMI는 실행 중인 VM 인스턴스를 나타냅니다. Pod와 유사하게, 실제 실행 상태를 반영합니다.

apiVersion: kubevirt.io/v1
kind: VirtualMachineInstance
metadata:
  name: my-vmi
spec:
  domain:
    cpu:
      cores: 1
    memory:
      guest: 2Gi
    devices:
      disks:
        - name: rootdisk
          disk:
            bus: virtio
  volumes:
    - name: rootdisk
      containerDisk:
        image: quay.io/kubevirt/fedora-cloud-container-disk-demo:latest

VirtualMachineInstanceReplicaSet

동일한 VMI를 여러 개 복제하여 실행합니다.

apiVersion: kubevirt.io/v1
kind: VirtualMachineInstanceReplicaSet
metadata:
  name: my-vmirs
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web-vm
  template:
    metadata:
      labels:
        app: web-vm
    spec:
      domain:
        cpu:
          cores: 1
        memory:
          guest: 1Gi
        devices:
          disks:
            - name: rootdisk
              disk:
                bus: virtio
      volumes:
        - name: rootdisk
          containerDisk:
            image: quay.io/kubevirt/fedora-cloud-container-disk-demo:latest

VirtualMachineInstanceMigration

VMI를 다른 노드로 라이브 마이그레이션합니다.

apiVersion: kubevirt.io/v1
kind: VirtualMachineInstanceMigration
metadata:
  name: migration-job
spec:
  vmiName: my-vmi

CDI (Containerized Data Importer)

CDI는 VM 디스크 이미지를 쿠버네티스 PVC로 가져오는 컴포넌트입니다.

DataVolume CRD

apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
  name: ubuntu-dv
spec:
  source:
    http:
      url: 'https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img'
  storage:
    accessModes:
      - ReadWriteOnce
    resources:
      requests:
        storage: 10Gi
    storageClassName: local-path

다양한 이미지 소스

CDI는 여러 소스에서 디스크 이미지를 가져올 수 있습니다.

+------------------+     +-------+     +------------------+
| HTTP/HTTPS URL   | --> |       |     |                  |
+------------------+     |       |     |                  |
                         |       |     |                  |
+------------------+     |  CDI  | --> |  PersistentVolume|
| Container Registry| --> |       |     |  Claim (PVC)     |
+------------------+     |       |     |                  |
                         |       |     |                  |
+------------------+     |       |     |                  |
| S3 Bucket        | --> |       |     |                  |
+------------------+     +-------+     +------------------+
| oVirt / VMware   | -->
+------------------+

컨테이너 레지스트리에서 가져오기

apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
  name: registry-dv
spec:
  source:
    registry:
      url: 'docker://quay.io/kubevirt/fedora-cloud-container-disk-demo:latest'
  storage:
    accessModes:
      - ReadWriteOnce
    resources:
      requests:
        storage: 5Gi

S3에서 가져오기

apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
  name: s3-dv
spec:
  source:
    s3:
      url: 's3://my-bucket/images/rhel9.qcow2'
      secretRef: s3-credentials
  storage:
    accessModes:
      - ReadWriteOnce
    resources:
      requests:
        storage: 20Gi

네트워킹

기본 Pod 네트워크

기본적으로 VM은 Pod 네트워크를 사용합니다. masquerade 모드가 권장됩니다.

spec:
  domain:
    devices:
      interfaces:
        - name: default
          masquerade: {}
  networks:
    - name: default
      pod: {}

Multus를 통한 다중 네트워크

Multus CNI를 사용하면 VM에 여러 네트워크 인터페이스를 연결할 수 있습니다.

apiVersion: k8s.cni.cncf.io/v1
kind: NetworkAttachmentDefinition
metadata:
  name: br-vlan100
spec:
  config: |
    {
      "cniVersion": "0.3.1",
      "type": "bridge",
      "bridge": "br-vlan100",
      "vlan": 100,
      "ipam": {
        "type": "host-local",
        "subnet": "10.100.0.0/24"
      }
    }
---
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: multi-net-vm
spec:
  running: true
  template:
    spec:
      domain:
        devices:
          interfaces:
            - name: default
              masquerade: {}
            - name: vlan100
              bridge: {}
      networks:
        - name: default
          pod: {}
        - name: vlan100
          multus:
            networkName: br-vlan100

스토리지

VM 디스크는 PVC(PersistentVolumeClaim)를 통해 관리됩니다.

스토리지 옵션 비교

스토리지 유형용도지속성
PVC영구 디스크영구
DataVolumeCDI를 통한 이미지 임포트영구
containerDisk읽기 전용 부팅 이미지임시
emptyDisk임시 데이터임시
cloudInitNoCloud초기 설정 데이터임시

라이브 마이그레이션

라이브 마이그레이션은 VM을 중단 없이 다른 노드로 이동하는 기능입니다.

요구 사항

  • ReadWriteMany(RWX) 접근 모드의 PVC
  • 공유 스토리지 (Ceph, NFS 등)
  • 소스/대상 노드 간 동일한 CPU 기능 세트

마이그레이션 실행

# kubectl로 마이그레이션 시작
kubectl virt migrate my-vm

# 또는 Migration CRD 생성
cat <<EOF | kubectl apply -f -
apiVersion: kubevirt.io/v1
kind: VirtualMachineInstanceMigration
metadata:
  name: migration-my-vm
spec:
  vmiName: my-vm
EOF

# 마이그레이션 상태 확인
kubectl get vmim migration-my-vm -o yaml

마이그레이션 정책 설정

apiVersion: migrations.kubevirt.io/v1alpha1
kind: MigrationPolicy
metadata:
  name: high-priority-policy
spec:
  bandwidthPerMigration: 1Gi
  completionTimeoutPerGiB: 800
  allowAutoConverge: true
  selectors:
    namespaceSelector:
      matchLabels:
        migration-policy: high-priority

설치 가이드

Operator 설치

# 최신 버전 확인
export KUBEVIRT_VERSION=$(curl -s https://api.github.com/repos/kubevirt/kubevirt/releases/latest | grep tag_name | cut -d '"' -f 4)

# Operator 배포
kubectl apply -f "https://github.com/kubevirt/kubevirt/releases/download/$KUBEVIRT_VERSION/kubevirt-operator.yaml"

# KubeVirt CR 생성
kubectl apply -f "https://github.com/kubevirt/kubevirt/releases/download/$KUBEVIRT_VERSION/kubevirt-cr.yaml"

# 설치 완료 대기
kubectl wait kv kubevirt -n kubevirt --for=condition=Available --timeout=300s

virtctl CLI 설치

# virtctl 다운로드
curl -L -o virtctl \
  "https://github.com/kubevirt/kubevirt/releases/download/$KUBEVIRT_VERSION/virtctl-$KUBEVIRT_VERSION-linux-amd64"
chmod +x virtctl
sudo mv virtctl /usr/local/bin/

CDI 설치

export CDI_VERSION=$(curl -s https://api.github.com/repos/kubevirt/containerized-data-importer/releases/latest | grep tag_name | cut -d '"' -f 4)

kubectl apply -f "https://github.com/kubevirt/containerized-data-importer/releases/download/$CDI_VERSION/cdi-operator.yaml"
kubectl apply -f "https://github.com/kubevirt/containerized-data-importer/releases/download/$CDI_VERSION/cdi-cr.yaml"

실전 예제: Ubuntu VM 생성

apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
  name: ubuntu-22-04
spec:
  source:
    http:
      url: 'https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img'
  storage:
    accessModes:
      - ReadWriteOnce
    resources:
      requests:
        storage: 20Gi
---
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: ubuntu-server
  labels:
    app: ubuntu-server
spec:
  running: true
  template:
    metadata:
      labels:
        app: ubuntu-server
    spec:
      domain:
        cpu:
          cores: 2
        memory:
          guest: 4Gi
        devices:
          disks:
            - name: rootdisk
              disk:
                bus: virtio
            - name: cloudinitdisk
              disk:
                bus: virtio
          interfaces:
            - name: default
              masquerade: {}
      networks:
        - name: default
          pod: {}
      volumes:
        - name: rootdisk
          dataVolume:
            name: ubuntu-22-04
        - name: cloudinitdisk
          cloudInitNoCloud:
            userData: |
              #cloud-config
              hostname: ubuntu-server
              user: ubuntu
              password: changeme
              chpasswd:
                expire: false
              ssh_authorized_keys:
                - ssh-rsa AAAA...your-key
              packages:
                - qemu-guest-agent
              runcmd:
                - systemctl enable --now qemu-guest-agent

유스케이스

1. 하이브리드 컨테이너/VM 워크로드

마이크로서비스(컨테이너)와 레거시 모놀리스(VM)를 하나의 클러스터에서 운영합니다.

2. 레거시 애플리케이션 마이그레이션

VMware, OpenStack 등에서 실행 중인 기존 VM을 쿠버네티스로 점진적으로 이전합니다.

3. Windows 워크로드

.NET Framework 애플리케이션이나 Active Directory 서버를 쿠버네티스 클러스터에서 실행합니다.

4. 개발/테스트 환경

다양한 OS 환경을 빠르게 프로비저닝하고 테스트에 활용합니다.

마치며

KubeVirt는 컨테이너와 VM의 경계를 허물어 통합 인프라 관리를 가능하게 합니다. CNCF 프로젝트로서 활발한 커뮤니티 지원을 받고 있으며, Red Hat OpenShift Virtualization의 핵심 기술이기도 합니다.

다음 글에서는 NVIDIA GPU Operator를 통해 쿠버네티스에서 GPU를 자동으로 관리하는 방법을 알아보겠습니다.


퀴즈: KubeVirt 이해도 점검

Q1. KubeVirt에서 VM의 선언적 정의를 담당하는 CRD는?

A) VirtualMachineInstance B) VirtualMachine C) VirtualMachineInstanceReplicaSet D) VirtualMachineInstanceMigration

정답: B) VirtualMachine - Deployment와 유사하게 VM의 원하는 상태(desired state)를 선언합니다.


Q2. virt-launcher의 역할은?

A) 클러스터 수준에서 VM 리소스를 감시 B) API 요청 유효성 검증 C) 개별 VM마다 생성되는 Pod로 libvirt/QEMU 실행 D) 노드 수준에서 libvirt와 통신

정답: C) virt-launcher는 각 VM에 대해 하나의 Pod로 생성되며, 내부에서 libvirt와 QEMU/KVM 프로세스를 관리합니다.


Q3. CDI의 DataVolume이 지원하지 않는 이미지 소스는?

A) HTTP/HTTPS URL B) 컨테이너 레지스트리 C) Git 리포지토리 D) S3 버킷

정답: C) Git 리포지토리는 CDI 소스로 지원되지 않습니다. HTTP, Registry, S3, oVirt, VMware가 지원됩니다.


Q4. 라이브 마이그레이션의 필수 요구 사항은?

A) ReadWriteOnce PVC B) ReadWriteMany PVC + 공유 스토리지 C) emptyDisk 볼륨 D) containerDisk 볼륨

정답: B) 라이브 마이그레이션은 소스/대상 노드에서 동시에 접근 가능한 공유 스토리지(RWX)가 필요합니다.