Skip to content

Split View: 디스크와 볼륨은 어떻게 VM에 붙는가

|

디스크와 볼륨은 어떻게 VM에 붙는가

들어가며

컨테이너 워크로드에서는 볼륨이 Pod에 마운트되면 일이 거의 끝난다. 그러나 VM은 다르다. guest 입장에서는 단순한 파일 마운트가 아니라 가상 디스크 장치가 보여야 한다. 따라서 KubeVirt의 스토리지 계층은 Pod 볼륨 모델과 guest 디스크 모델 사이를 이어 주는 번역 계층이 된다.

이번 글에서는 container disk, PVC, DataVolume, hostDisk, generated volume, hotplug volume이 어떤 경로로 guest에 붙는지 본다.

가장 중요한 사실: 스토리지는 두 번 해석된다

KubeVirt에서 스토리지는 최소 두 단계를 거친다.

  1. Kubernetes가 Pod 수준에서 volume source를 준비한다.
  2. KubeVirt가 이를 guest-visible disk로 재해석한다.

즉 "PVC가 launcher Pod에 보인다"와 "guest 안에 디스크가 생긴다"는 같은 문장이 아니다.

어떤 볼륨 타입들이 있는가

schema.go와 converter, storage 관련 패키지를 보면 자주 등장하는 타입은 다음과 같다.

  • PersistentVolumeClaim
  • DataVolume
  • ContainerDisk
  • HostDisk
  • CloudInitNoCloud
  • CloudInitConfigDrive
  • ConfigMap
  • Secret
  • ServiceAccount
  • hotplug volume

이들은 guest 관점에서 모두 같은 디스크가 아니다. 어떤 것은 영구 데이터용이고, 어떤 것은 부팅 메타데이터용이며, 어떤 것은 migration 중 복사 대상조차 아니다.

container disk는 왜 특별한가

cmd/virt-launcher/virt-launcher.gopkg/virt-handler/container-disk를 보면 container disk는 전용 로컬 디렉터리와 mounter를 통해 준비된다. 이는 OS 이미지 자체를 컨테이너 이미지 레이어처럼 배포하려는 KubeVirt 특유의 패턴이다.

장점은 배포가 간편하다는 점이다. 단점은 일반 PVC 기반 persistent root disk와는 수명 주기가 다르다는 점이다.

즉 container disk는 "컨테이너처럼 전달되는 VM 디스크 이미지"라고 보면 된다.

PVC와 DataVolume은 어떻게 다뤄지는가

PVC

PVC는 이미 Kubernetes가 잘 아는 영구 저장소 모델이다. KubeVirt는 이를 Pod에 붙인 다음 guest 디스크로 연결한다.

DataVolume

DataVolume은 CDI와 연결된 higher-level abstraction이다. 보통 이미지를 import하거나 clone한 뒤 최종적으로 PVC 형태의 저장소를 제공한다.

virt-controller가 DataVolume 준비 상태도 함께 보는 이유가 여기에 있다. guest 디스크 attach는 결국 Pod에 attach 가능한 스토리지가 준비되어야 가능하기 때문이다.

converter는 volume source를 disk source로 바꾼다

앞 글에서 본 것처럼, converter는 volumesdisks를 결합한다. 이때 storage 쪽에서 중요한 것은 실제 source path와 mode를 결정하는 것이다.

예를 들면 같은 PVC라도:

  • filesystem 기반이면 파일 경로를 참조할 수 있고
  • block mode면 장치 파일처럼 다뤄야 한다

이 차이는 guest 디스크 attach 방식과 migration 가능성에도 영향을 준다.

generated volume은 왜 따로 취급되는가

live-migration-source.goclassifyVolumesForMigration를 보면 generated volume이라는 분류가 있다. 여기에는 다음이 포함된다.

  • config map
  • secret
  • downward API
  • service account
  • cloud-init
  • container disk

이런 볼륨은 일반 shared PVC와 다르게 guest 부팅 보조 정보이거나 생성형 데이터다. migration 때도 같은 방식으로 취급하면 안 된다.

즉 KubeVirt는 디스크를 단순히 "storage냐 아니냐"가 아니라:

  • shared volume
  • generated volume
  • local volume to migrate

같은 더 세밀한 클래스로 나눈다.

local disk와 shared disk의 차이가 왜 중요한가

live migration 관점에서 이 차이는 결정적이다.

shared disk

양쪽 노드가 같은 저장소를 볼 수 있으면 디스크 자체를 복사할 필요가 없다. 메모리 상태와 실행 상태만 옮기면 된다.

local disk

source 노드에만 있는 데이터라면 migration 중에 디스크 내용도 옮겨야 한다. 이때 block migration 또는 volume migration 문제가 생긴다.

live-migration-source.go는 이런 볼륨 분류를 바탕으로 어떤 디스크가 실제 복사 대상인지 계산한다.

hotplug volume은 왜 더 복잡한가

일반 볼륨은 VM 시작 전에 준비하면 되지만, hotplug는 실행 중 guest에 새로운 디스크를 넣는 문제다.

여기서는:

  • VMI spec 변경 감지
  • launcher Pod 또는 attachment Pod 보조
  • node-side mount
  • libvirt 장치 추가

같은 단계가 연쇄적으로 필요하다. pkg/storage/hotplug, pkg/virt-handler/hotplug-disk가 이 영역의 핵심이다.

즉 hotplug는 storage 문제이면서 동시에 runtime device update 문제다.

virt-launcher 초기화 코드가 보여주는 스토리지 현실

virt-launcher.goinitializeDirs는 여러 디스크 디렉터리를 준비한다.

  • cloud-init
  • ignition
  • container disk
  • hotplug disk
  • config map disk
  • secret disk
  • service account disk

이 목록만 봐도 KubeVirt에서 "디스크"라는 말이 단순 블록 스토리지보다 훨씬 넓은 의미를 가진다는 것을 알 수 있다. guest는 이들을 각각 부팅 디스크, 메타데이터 디스크, 보조 채널, 추가 볼륨 등으로 보게 된다.

migration에서 스토리지가 왜 항상 문제의 중심인가

운영 현장에서 migration 실패 원인의 상당수는 네트워크나 CPU보다 storage 가시성 차이에서 나온다.

대표적인 질문은 다음과 같다.

  • target 노드가 같은 PVC를 볼 수 있는가
  • volume mode가 block인가 filesystem인가
  • generated volume은 target에서 다시 만들어질 수 있는가
  • hotplug 디스크가 아직 정리되지 않았는가

KubeVirt가 migration 전에 volume 분류와 target 준비를 세심하게 하는 이유가 바로 여기에 있다.

자주 하는 오해

오해 1: Pod에 마운트되면 guest 디스크도 자동이다

아니다. guest는 libvirt domain을 통해 디스크 장치를 받아야 한다.

오해 2: PVC와 DataVolume은 guest 입장에서 거의 같다

부분적으로는 맞지만, 준비 과정과 상위 orchestration은 다르다. DataVolume은 import와 clone lifecycle이 추가된다.

오해 3: 모든 디스크는 migration 때 똑같이 처리된다

아니다. shared, generated, local-to-migrate 분류가 매우 중요하다.

운영자가 먼저 봐야 할 디버깅 포인트

  • guest 디스크가 안 보이면 Pod mount와 libvirt disk attach를 분리해서 본다.
  • migration 실패면 shared storage 가시성과 local volume 여부를 본다.
  • hotplug 실패면 spec 반영, node mount, libvirt device update 순서로 본다.
  • cloud-init이나 secret 디스크 문제가 있으면 generated volume 준비 경로를 본다.

마무리

KubeVirt의 스토리지는 "Pod에 붙는 볼륨"과 "guest가 보는 디스크" 사이의 변환 문제다. PVC와 DataVolume은 영속 데이터 경로를, container disk와 cloud-init은 부팅 보조 경로를, hotplug는 실행 중 장치 변경 경로를 담당한다. 그리고 migration이 들어오면 각 볼륨은 shared, generated, local-to-migrate 같은 더 구체적인 의미를 갖게 된다.

다음 글부터는 네트워크 레이어로 넘어가서, Pod 네트워크를 VM 네트워크로 바꾸는 기본 원리부터 차근차근 살펴보겠다.

How Disks and Volumes Attach to VMs

Introduction

In container workloads, once a volume is mounted to a Pod, the job is mostly done. But VMs are different. From the guest's perspective, what must be visible is not a simple file mount but a virtual disk device. Therefore KubeVirt's storage layer becomes a translation layer bridging the Pod volume model and the guest disk model.

This article examines the paths through which container disks, PVCs, DataVolumes, hostDisks, generated volumes, and hotplug volumes attach to guests.

The Most Important Fact: Storage Is Interpreted Twice

In KubeVirt, storage goes through at least two stages:

  1. Kubernetes prepares the volume source at the Pod level.
  2. KubeVirt reinterprets it as a guest-visible disk.

In other words, "the PVC is visible to the launcher Pod" and "a disk appears inside the guest" are not the same statement.

What Volume Types Exist

Looking at schema.go, the converter, and storage-related packages, frequently appearing types are:

  • PersistentVolumeClaim
  • DataVolume
  • ContainerDisk
  • HostDisk
  • CloudInitNoCloud
  • CloudInitConfigDrive
  • ConfigMap
  • Secret
  • ServiceAccount
  • Hotplug volume

From the guest's perspective, these are not all the same disk. Some are for persistent data, some for boot metadata, and some are not even copy targets during migration.

Why Container Disk Is Special

Looking at cmd/virt-launcher/virt-launcher.go and pkg/virt-handler/container-disk, container disks are prepared through dedicated local directories and a mounter. This is a KubeVirt-specific pattern for distributing the OS image itself like container image layers.

The advantage is easy distribution. The disadvantage is that the lifecycle differs from normal PVC-based persistent root disks.

Think of container disks as "VM disk images delivered like containers."

How PVC and DataVolume Are Handled

PVC

PVC is the persistent storage model that Kubernetes already knows well. KubeVirt attaches it to the Pod and then connects it as a guest disk.

DataVolume

DataVolume is a higher-level abstraction connected to CDI. It typically imports or clones an image and ultimately provides storage in PVC form.

This is why virt-controller also checks DataVolume readiness state. Guest disk attach is only possible when storage attachable to the Pod is ready.

The Converter Transforms Volume Source to Disk Source

As seen in the previous article, the converter combines volumes and disks. What's important on the storage side is determining the actual source path and mode.

For example, the same PVC can:

  • Be referenced by file path if filesystem-based
  • Need to be treated as a device file if in block mode

This difference also affects guest disk attach methods and migration possibilities.

Why Generated Volumes Are Treated Separately

Looking at classifyVolumesForMigration in live-migration-source.go, there is a classification called generated volume. This includes:

  • Config map
  • Secret
  • Downward API
  • Service account
  • Cloud-init
  • Container disk

These volumes are different from regular shared PVCs -- they are guest boot auxiliary information or generated data. They should not be treated the same way during migration.

KubeVirt classifies disks not simply as "storage or not" but into finer classes like:

  • Shared volume
  • Generated volume
  • Local volume to migrate

Why the Difference Between Local and Shared Disks Matters

From a live migration perspective, this difference is decisive.

Shared Disk

If both nodes can see the same storage, the disk itself doesn't need to be copied. Only memory state and execution state need to be moved.

Local Disk

If data exists only on the source node, disk contents must also be moved during migration. This is where block migration or volume migration problems arise.

live-migration-source.go calculates which disks are actual copy targets based on this volume classification.

Why Hotplug Volume Is More Complex

Regular volumes just need to be prepared before VM start, but hotplug is the problem of inserting a new disk into the guest while it's running.

This requires a chain of steps:

  • VMI spec change detection
  • Launcher Pod or attachment Pod assistance
  • Node-side mount
  • libvirt device addition

pkg/storage/hotplug and pkg/virt-handler/hotplug-disk are the core of this area.

Hotplug is simultaneously a storage problem and a runtime device update problem.

The Storage Reality Shown by virt-launcher Initialization Code

initializeDirs in virt-launcher.go prepares multiple disk directories:

  • cloud-init
  • ignition
  • container disk
  • hotplug disk
  • config map disk
  • secret disk
  • service account disk

Just from this list, you can see that "disk" in KubeVirt has a much broader meaning than simple block storage. The guest sees these as boot disks, metadata disks, auxiliary channels, additional volumes, etc.

Why Storage Is Always at the Center of Migration Problems

In production, a significant portion of migration failure causes come from storage visibility differences rather than network or CPU.

Typical questions include:

  • Can the target node see the same PVC?
  • Is the volume mode block or filesystem?
  • Can generated volumes be recreated on the target?
  • Are hotplug disks still not cleaned up?

This is exactly why KubeVirt carefully performs volume classification and target preparation before migration.

Common Misconceptions

Misconception 1: If Mounted to the Pod, Guest Disk Is Automatic

No. The guest must receive a disk device through the libvirt domain.

Misconception 2: PVC and DataVolume Are Almost the Same from the Guest's Perspective

Partially true, but the preparation process and higher-level orchestration differ. DataVolume has additional import and clone lifecycle.

Misconception 3: All Disks Are Treated the Same During Migration

No. The shared, generated, and local-to-migrate classification is very important.

Debugging Points Operators Should Check First

  • If the guest disk isn't visible, separately check Pod mount and libvirt disk attach.
  • If migration fails, check shared storage visibility and local volume presence.
  • If hotplug fails, check in order: spec reflection, node mount, libvirt device update.
  • If there are cloud-init or secret disk issues, check the generated volume preparation path.

Conclusion

KubeVirt's storage is a translation problem between "volumes attached to Pods" and "disks seen by guests." PVCs and DataVolumes handle persistent data paths, container disks and cloud-init handle boot auxiliary paths, and hotplug handles runtime device change paths. And when migration enters the picture, each volume takes on more specific meanings like shared, generated, and local-to-migrate.

Starting from the next article, we will move to the networking layer and examine the basic principles of converting Pod networks to VM networks step by step.