Skip to content
Published on

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

Authors

들어가며

컨테이너 워크로드에서는 볼륨이 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 네트워크로 바꾸는 기본 원리부터 차근차근 살펴보겠다.