Kubernetes Tools/Kubevirt

[KubeVirt Ep.5] 🚀 VM 이미지 다루기 | ContainerDisk와 PVC 이해 및 활용

ygtoken 2025. 3. 21. 13:48
728x90

이 글에서는 KubeVirt에서 VM 이미지를 다루는 다양한 방법을 알아보겠습니다. ContainerDisk의 개념과 활용법, Docker를 사용하여 qcow2 이미지를 ContainerDisk로 변환하는 방법, 그리고 PVC 기반 스토리지 및 DataVolume을 활용하는 방법을 실습 중심으로 살펴보겠습니다.


📌 KubeVirt의 VM 이미지 개요

KubeVirt에서 VM을 실행하려면 운영체제가 설치된 디스크 이미지가 필요합니다. 여러 방식으로 VM 이미지를 제공할 수 있으며, 각 방식에는 장단점이 있습니다.

 

KubeVirt VM 이미지 제공 방식 비교

 

 

VM 이미지 제공 방식

KubeVirt에서 VM 이미지를 제공하는 주요 방식은 다음과 같습니다:

  1. ContainerDisk: 디스크 이미지를 컨테이너 이미지로 패키징
    • 장점: 컨테이너 레지스트리를 통한 배포, 불변성, 재사용성
    • 단점: 상태 유지 불가, 대용량 이미지 관리 어려움
  2. PVC (PersistentVolumeClaim): 쿠버네티스 영구 볼륨에 디스크 이미지 저장
    • 장점: 상태 유지, 쿠버네티스 스토리지 통합
    • 단점: 이미지 관리 복잡성, 초기 설정 필요
  3. DataVolume: CDI(Containerized Data Importer)를 통한 이미지 가져오기 및 관리
    • 장점: HTTP 소스에서 직접 가져오기, VM 생성 과정 자동화
    • 단점: 추가 구성요소(CDI) 필요
  4. ephemeral 스토리지: 임시 디스크 기반 VM 실행
    • 장점: 빠른 프로비저닝, 테스트 용도로 적합
    • 단점: VM 재시작 시 모든 데이터 손실

디스크 이미지 형식

KubeVirt는 다양한 디스크 이미지 형식을 지원합니다:

  1. QCOW2 (QEMU Copy-On-Write v2):
    • 가장 널리 사용되는 형식
    • 공간 효율적, 스냅샷 지원
    • 예: ubuntu-20.04.qcow2
  2. RAW:
    • 압축되지 않은 원시 디스크 이미지
    • 최고 성능, 단순함
    • 공간 효율성 낮음
  3. ISO:
    • 설치 미디어 용도
    • 읽기 전용
    • VM 설치 과정에 주로 사용

▶️ 이미지 선택 팁: "프로덕션 환경에서는 QCOW2 형식이 공간 효율성과 스냅샷 기능을 제공하기 때문에 권장됩니다. 개발 및 테스트 환경에서는 ContainerDisk를 사용하면 빠르고 간편하게 VM을 배포할 수 있습니다."


📌 ContainerDisk 개념 이해하기

ContainerDisk는 KubeVirt의 혁신적인 기능 중 하나로, VM 디스크 이미지를 컨테이너 이미지로 패키징하여 쿠버네티스의 컨테이너 인프라를 활용하는 방식입니다.

 

ContainerDisk의 작동 원리

ContainerDisk는 다음과 같은 원리로 작동합니다:

  1. 디스크 이미지(qcow2, raw 등)를 컨테이너 이미지로 패키징
  2. 컨테이너 레지스트리에 이미지 저장 및 배포
  3. VM 생성 시 컨테이너에서 디스크 이미지를 추출하여 VM에 마운트
  4. VM Pod의 초기화 컨테이너를 통해 디스크 이미지 제공
# ContainerDisk를 사용한 VM 예시
apiVersion: kubevirt.io/v1           # KubeVirt API 버전
kind: VirtualMachine                 # 리소스 종류: 가상머신 정의
metadata:
  name: containerdisk-vm             # VM 이름
spec:
  running: true                      # VM 생성 후 바로 실행 여부
  template:
    spec:
      domain:                        # VM 하드웨어 정의 시작
        devices:
          disks:                     # 디스크 장치 목록
          - name: containerdisk      # 디스크 이름 (volumes와 연결됨)
            disk:
              bus: virtio            # 디스크 버스 유형 (virtio: 성능 최적화)
      volumes:                       # 볼륨 정의 시작
      - name: containerdisk          # 디스크와 동일한 이름 (연결 필요)
        containerDisk:               # ContainerDisk 볼륨 유형 지정
          image: quay.io/kubevirt/fedora-container-disk-demo:latest  # 컨테이너 이미지 위치
          path: /disk/fedora.qcow2   # 컨테이너 내 디스크 이미지 경로 (선택적)
          imagePullPolicy: IfNotPresent  # 이미지 풀 정책 (기존 이미지 재사용)

 

ContainerDisk의 장점

ContainerDisk는 다음과 같은 장점을 제공합니다:

  1. 불변성(Immutability): 이미지가 변경되지 않으므로 일관된 환경 보장
  2. 재현성(Reproducibility): 동일한 이미지를 여러 VM에서 재사용 가능
  3. 배포 간소화: 컨테이너 레지스트리를 통한 간편한 배포 및 버전 관리
  4. 쿠버네티스 통합: 기존 컨테이너 인프라와 워크플로우 활용

ContainerDisk의 단점 및 제한사항

ContainerDisk에는 다음과 같은 제한사항도 있습니다:

  1. 상태 유지 불가: 변경사항이 유지되지 않음 (읽기 전용 특성)
  2. 디스크 이미지 크기: 대용량 이미지의 경우 컨테이너 이미지 크기 증가
  3. 이미지 레이어 제한: 컨테이너 이미지 계층 구조로 인한 제약

▶️ 사용 사례 가이드: "ContainerDisk는 OS 이미지나 불변 애플리케이션 이미지에 적합합니다. 사용자 데이터나 동적으로 변경되는 데이터는 별도의 PVC를 추가하여 관리해야 합니다."

 

 

ContainerDisk 구조 및 작동 방식

 


📌 Docker로 qcow2 이미지를 ContainerDisk로 만들기

이제 직접 qcow2 이미지를 ContainerDisk로 변환하는 과정을 실습해 보겠습니다.

필요한 도구 및 사전 준비

ContainerDisk를 만들기 위해 다음 도구가 필요합니다:

  • Docker 또는 Podman (컨테이너 이미지 빌드용)
  • qcow2 또는 raw 형식의 VM 이미지
  • 컨테이너 레지스트리 계정 (Docker Hub, Quay.io 등)

사전에 VM 이미지를 준비하거나 다운로드해야 합니다. 예를 들어, Ubuntu 클라우드 이미지:

# Ubuntu 클라우드 이미지 다운로드
$ wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img
# Ubuntu 20.04 LTS (Focal) 클라우드 이미지를 다운로드합니다
# 클라우드 이미지는 cloud-init으로 초기화되도록 미리 구성되어 있습니다

 

Dockerfile 작성

ContainerDisk 이미지를 만들기 위한 간단한 Dockerfile을 작성합니다:

# Dockerfile
FROM scratch  # 빈 베이스 이미지 사용 (최소 크기로 컨테이너 생성)
ADD focal-server-cloudimg-amd64.img /disk/ubuntu.qcow2  # 로컬 디스크 이미지를 /disk 경로에 추가
# 참고: scratch 이미지를 사용해 최소한의 오버헤드만 갖게 됨
# /disk 경로는 KubeVirt가 기본적으로 디스크 이미지를 찾는 위치입니다

이 Dockerfile은 매우 단순합니다:

  • FROM scratch: 빈 베이스 이미지 사용 (추가 OS 레이어 없음)
  • ADD: 로컬 디스크 이미지를 컨테이너 이미지에 추가

이미지 빌드 및 푸시

Dockerfile을 사용하여 컨테이너 이미지를 빌드하고 레지스트리에 푸시합니다:

# 이미지 빌드
$ docker build -t yourusername/ubuntu-container-disk:20.04 .
# Dockerfile을 사용해 ContainerDisk 이미지를 빌드합니다
# -t: 이미지 태그 지정 (registry/name:tag 형식)
# . : 현재 디렉토리의 Dockerfile 사용

# 이미지 푸시
$ docker push yourusername/ubuntu-container-disk:20.04
# 빌드한 이미지를 컨테이너 레지스트리에 업로드합니다
# 이렇게 하면 KubeVirt가 이미지를 가져와 VM 디스크로 사용할 수 있습니다

 

여러 디스크 이미지를 포함하는 ContainerDisk

여러 디스크 이미지를 하나의 ContainerDisk에 포함시킬 수도 있습니다:

# 여러 디스크가 포함된 Dockerfile
FROM scratch  # 빈 베이스 이미지
ADD ubuntu-20.04.qcow2 /disk/ubuntu.qcow2  # 시스템 디스크 이미지
ADD data-disk.qcow2 /disk/data.qcow2       # 데이터 디스크 이미지
ADD windows-2019.qcow2 /disk/windows.qcow2 # Windows 이미지
# 여러 디스크 이미지를 하나의 컨테이너에 패키징합니다
# 각 이미지는 다른 경로에 저장됩니다

 

이 경우 VM 정의에서 path 속성을 사용하여 특정 디스크를 지정합니다:

volumes:
- name: rootdisk
  containerDisk:
    image: yourusername/multi-disk-container:latest  # 여러 디스크가 들어있는 이미지
    path: /disk/ubuntu.qcow2  # 특정 디스크 경로 지정
    # path를 사용하면 하나의 컨테이너에서 특정 디스크만 선택해 사용할 수 있습니다

 

빈 ContainerDisk 생성

새로운 빈 디스크를 ContainerDisk로 만들어야 할 경우:

# 빈 디스크 이미지 생성
$ qemu-img create -f qcow2 empty-disk.qcow2 10G
# qemu-img 도구로 10GB 크기의 빈 qcow2 이미지 생성
# -f qcow2: qcow2 형식 지정
# 10G: 디스크 크기 (10 기가바이트)

# Dockerfile 작성
$ echo 'FROM scratch
ADD empty-disk.qcow2 /disk/empty.qcow2' > Dockerfile.empty
# 빈 디스크를 포함하는 간단한 Dockerfile 생성

# 이미지 빌드
$ docker build -f Dockerfile.empty -t yourusername/empty-disk:10g .
# 특정 Dockerfile을 지정하여 빌드 (-f 옵션 사용)

# 이미지 푸시
$ docker push yourusername/empty-disk:10g
# 빌드한 이미지를 레지스트리에 업로드

▶️ 최적화 팁: "ContainerDisk 이미지 크기를 줄이려면 디스크 이미지를 압축하고 불필요한 데이터를 제거하세요. 예를 들어 qemu-img convert -O qcow2 -c source.qcow2 compressed.qcow2 명령으로 압축된 qcow2 이미지를 만들 수 있습니다."


📌 ContainerDisk로 VM 생성하기

이제 만든 ContainerDisk를 사용하여 VM을 생성해 보겠습니다.

 

기본 ContainerDisk VM 매니페스트

다음은 방금 만든 Ubuntu ContainerDisk를 사용하는 VM 매니페스트입니다:

apiVersion: kubevirt.io/v1       # KubeVirt API 버전
kind: VirtualMachine             # 리소스 종류
metadata:
  name: ubuntu-vm                # VM 이름
spec:
  running: true                  # 생성 즉시 VM 실행
  template:
    metadata:
      labels:
        kubevirt.io/vm: ubuntu-vm  # VM 식별 레이블
    spec:
      domain:                    # VM 하드웨어 정의 시작
        cpu:
          cores: 2               # 2개 CPU 코어 할당
        devices:
          disks:                 # 디스크 장치 목록
          - name: rootdisk       # 루트 디스크 (OS 이미지)
            disk:
              bus: virtio        # virtio 버스 사용 (성능 최적화)
          - name: cloudinitdisk  # cloud-init 설정 디스크
            disk:
              bus: virtio
          interfaces:            # 네트워크 인터페이스
          - name: default
            masquerade: {}       # NAT 모드 네트워킹 (외부 통신 가능)
        resources:
          requests:
            memory: 2Gi          # 2GB 메모리 할당
      networks:                  # 네트워크 정의
      - name: default
        pod: {}                  # 기본 Pod 네트워크 사용
      volumes:                   # 볼륨 정의
      - name: rootdisk           # 루트 디스크 볼륨
        containerDisk:
          image: yourusername/ubuntu-container-disk:20.04  # 방금 만든 이미지
      - name: cloudinitdisk      # cloud-init 볼륨
        cloudInitNoCloud:        # cloud-init 구성 (NoCloud 방식)
          userData: |            # VM 초기 설정 데이터
            #cloud-config
            hostname: ubuntu-vm  # 호스트명 설정
            user: ubuntu         # 사용자 생성
            password: ubuntu     # 비밀번호 설정
            chpasswd: { expire: False }  # 비밀번호 만료 비활성화
            ssh_pwauth: True     # SSH 비밀번호 인증 허용

 

읽기 전용 ContainerDisk와 쓰기 가능 PVC 조합

운영체제는 ContainerDisk로, 데이터는 PVC로 구성하는 일반적인 패턴입니다:

apiVersion: kubevirt.io/v1         # KubeVirt API 버전
kind: VirtualMachine               # 리소스 종류
metadata:
  name: ubuntu-with-data           # VM 이름
spec:
  running: true                    # 생성 즉시 VM 실행
  template:
    spec:
      domain:
        devices:
          disks:
          - name: rootdisk         # 루트 디스크 (OS)
            disk:
              bus: virtio          # virtio 버스 사용
          - name: datadisk         # 데이터 디스크 (영구 저장소)
            disk:
              bus: virtio
      volumes:
      - name: rootdisk
        containerDisk:
          image: yourusername/ubuntu-container-disk:20.04  # 읽기 전용 OS 이미지
          # ContainerDisk는 불변이므로 OS 이미지에 적합
      - name: datadisk
        persistentVolumeClaim:
          claimName: ubuntu-data-pvc  # 쓰기 가능한 PVC 사용
          # PVC는 상태를 유지하므로 데이터 저장에 적합

이 패턴에서:

  • rootdisk: 읽기 전용 OS 이미지 (ContainerDisk)
  • datadisk: 쓰기 가능한 데이터 스토리지 (PVC)

부팅 가능한 CD-ROM 이미지 사용

ISO 이미지를 사용하여 설치 미디어를 제공하는 방법:

apiVersion: kubevirt.io/v1          # KubeVirt API 버전
kind: VirtualMachine                # 리소스 종류
metadata:
  name: installer-vm                # VM 이름
spec:
  running: true                     # 생성 즉시 VM 실행
  template:
    spec:
      domain:
        devices:
          disks:
          - name: installer          # 설치 미디어 디스크
            cdrom:                   # CD-ROM으로 마운트 (부팅 가능)
              bus: sata              # SATA 버스 사용 (CD-ROM에 적합)
          - name: harddrive          # 설치 대상 하드 디스크
            disk:
              bus: virtio            # virtio 버스 사용
      volumes:
      - name: installer
        containerDisk:
          image: quay.io/kubevirt/iso-installer:latest  # ISO 이미지 컨테이너
          # ISO 이미지가 CD-ROM으로 마운트됨
      - name: harddrive
        persistentVolumeClaim:
          claimName: installation-target-pvc  # 설치 대상 PVC
          # OS가 설치될 영구 볼륨

이 예제에서는:

  • ISO 이미지가 CD-ROM으로 마운트됨 (cdrom 설정)
  • 설치 대상은 영구 볼륨 (harddrive)

▶️ VM 초기화 팁: "ContainerDisk와 cloud-init을 함께 사용하면 VM을 빠르게 초기화하고 사용자 지정할 수 있습니다. cloud-init으로 SSH 키, 네트워크 설정, 사용자 등을 구성하세요."


📌 PVC 기반 VM 루트 디스크 구성

지속적인 상태를 유지해야 하는 VM의 경우, 영구 볼륨 클레임(PVC)을 루트 디스크로 사용할 수 있습니다.

 

VM용 PVC 생성

VM용 PVC를 직접 생성하는 방법:

# vm-rootdisk-pvc.yaml
apiVersion: v1                     # 쿠버네티스 코어 API 버전
kind: PersistentVolumeClaim        # PVC 리소스 정의
metadata:
  name: vm-rootdisk                # PVC 이름
spec:
  accessModes:
    - ReadWriteOnce                # 접근 모드: 단일 노드에서 읽기/쓰기
    # RWO: 하나의 노드만 읽기/쓰기 가능
    # 대부분의 VM 디스크에 적합
  resources:
    requests:
      storage: 10Gi                # 요청 스토리지 용량: 10GB
  storageClassName: standard       # 스토리지 클래스 (클러스터에 맞게 조정)
  # 클러스터 설정에 따라 다른 스토리지 클래스 사용 가능
  # 예: aws-ebs, azurefile, local-path 등
# PVC 생성
$ kubectl apply -f vm-rootdisk-pvc.yaml
# PVC 매니페스트 적용

# PVC 상태 확인
$ kubectl get pvc vm-rootdisk
NAME          STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
vm-rootdisk   Bound    pvc-a9d75bd5-2c0b-4b66-9f3b-4a4f4e79699b   10Gi       RWO            standard       5s
# STATUS가 Bound인지 확인
# Bound 상태는 PVC가 PV(PersistentVolume)에 연결되었음을 의미

 

PVC를 사용하는 VM 생성

이제 생성한 PVC를 VM의 루트 디스크로 사용합니다:

# pvc-vm.yaml
apiVersion: kubevirt.io/v1            # KubeVirt API 버전
kind: VirtualMachine                  # 리소스 종류
metadata:
  name: pvc-vm                        # VM 이름
spec:
  running: true                       # 생성 즉시 VM 실행
  template:
    metadata:
      labels:
        kubevirt.io/vm: pvc-vm        # VM 식별 레이블
    spec:
      domain:
        devices:
          disks:
          - name: rootdisk            # 루트 디스크
            disk:
              bus: virtio             # virtio 버스 사용
          - name: cloudinitdisk       # cloud-init 디스크
            disk:
              bus: virtio
        resources:
          requests:
            memory: 1Gi               # 1GB 메모리 할당
      volumes:
      - name: rootdisk
        persistentVolumeClaim:
          claimName: vm-rootdisk      # 앞서 생성한 PVC 사용
          # PVC를 VM의 루트 디스크로 사용
      - name: cloudinitdisk
        cloudInitNoCloud:
          userData: |                 # cloud-init 설정
            #cloud-config
            password: ubuntu          # 사용자 비밀번호
            chpasswd: { expire: False }  # 비밀번호 만료 비활성화

하지만 이 VM은 아직 부팅할 수 없습니다. PVC에 부팅 가능한 OS가 설치되어 있지 않기 때문입니다.

 

설치 미디어로 OS 설치하기

PVC에 OS를 설치하기 위해 부팅 디스크와 설치 미디어를 함께 구성합니다:

# os-installer-vm.yaml
apiVersion: kubevirt.io/v1               # KubeVirt API 버전
kind: VirtualMachine                     # 리소스 종류
metadata:
  name: os-installer                     # VM 이름
spec:
  running: true                          # 생성 즉시 VM 실행
  template:
    spec:
      domain:
        devices:
          disks:
          - name: rootdisk               # 대상 디스크 (OS 설치 대상)
            disk:
              bus: virtio                # virtio 버스 사용
          - name: installer              # 설치 미디어 디스크
            cdrom:                       # CD-ROM으로 마운트
              bus: sata                  # SATA 버스 사용 (CD-ROM용)
        resources:
          requests:
            memory: 2Gi                  # 2GB 메모리 할당 (설치에 충분한 메모리)
      volumes:
      - name: rootdisk
        persistentVolumeClaim:
          claimName: vm-rootdisk         # 대상 PVC (여기에 OS 설치)
      - name: installer
        containerDisk:
          image: quay.io/kubevirt/ubuntu-installer:20.04  # 설치 ISO 이미지
          # ContainerDisk로 패키징된 Ubuntu 설치 ISO

 

이 방식은 수동 설치 과정이 필요합니다:

# VM 생성
$ kubectl apply -f os-installer-vm.yaml
# 설치용 VM 생성

# 콘솔에 접속하여 설치 진행
$ virtctl console os-installer
# 직렬 콘솔에 접속하여 텍스트 모드 설치 진행

# 또는 VNC로 접속 (그래픽 설치)
$ virtctl vnc os-installer
# 그래픽 설치 환경에 VNC로 접속
# 설치 마법사를 따라 OS를 PVC에 설치

▶️ PVC 활용 팁: "프로덕션 환경에서는 골든 이미지를 미리 만들어 놓고, 이를 복제하여 새 VM의 PVC를 초기화하는 것이 효율적입니다. 이를 위해 DataVolume과 KubeVirt CDI를 활용할 수 있습니다."


📌 DataVolume과 CDI 활용하기

DataVolume과 CDI(Containerized Data Importer)를 사용하면 VM 이미지 관리와 PVC 초기화 과정을 자동화할 수 있습니다.

 

 

DataVolume 및 CDI 워크플로우

 

CDI 설치

먼저 CDI 컴포넌트를 클러스터에 설치합니다:

# 최신 CDI 버전 확인
$ CDI_VERSION=$(curl -s https://github.com/kubevirt/containerized-data-importer/releases/latest | grep -o "v[0-9]\.[0-9]*\.[0-9]*")
# GitHub API를 통해 최신 CDI 버전 확인

# CDI 설치
$ kubectl create -f https://github.com/kubevirt/containerized-data-importer/releases/download/$CDI_VERSION/cdi-operator.yaml
# CDI Operator 설치 (CRD 및 컨트롤러 배포)

$ kubectl create -f https://github.com/kubevirt/containerized-data-importer/releases/download/$CDI_VERSION/cdi-cr.yaml
# CDI 커스텀 리소스 생성 (CDI 인스턴스 배포)

# 설치 확인
$ kubectl get pods -n cdi
NAME                              READY   STATUS    RESTARTS   AGE
cdi-apiserver-7f58b68b95-xl9bn    1/1     Running   0          2m
cdi-deployment-5d8f84756f-l6s7v   1/1     Running   0          2m
cdi-operator-7565c7f5d4-xz6zn     1/1     Running   0          3m
cdi-uploadproxy-6dd497b5b-fh2v8   1/1     Running   0          2m
# CDI 관련 모든 Pod가 Running 상태인지 확인
# 4개의 주요 컴포넌트: apiserver, deployment, operator, uploadproxy

 

 

DataVolume 직접 생성

HTTP URL에서 이미지를 가져와 DataVolume을 생성하는 예:

# ubuntu-dv.yaml
apiVersion: cdi.kubevirt.io/v1beta1     # CDI API 버전
kind: DataVolume                         # DataVolume 리소스 정의
metadata:
  name: ubuntu-dv                        # DataVolume 이름
spec:
  source:                                # 소스 정의 (데이터 가져올 곳)
    http:                                # HTTP 소스 지정
      url: "https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img"
      # Ubuntu 20.04 클라우드 이미지 URL
      # CDI는 이 URL에서 이미지를 다운로드하여 PVC에 저장
  pvc:                                   # 생성할 PVC 명세
    accessModes:
      - ReadWriteOnce                    # 단일 노드 읽기/쓰기 접근
    resources:
      requests:
        storage: 10Gi                    # 10GB 스토리지 요청
    storageClassName: standard           # 스토리지 클래스 지정
# DataVolume 생성
$ kubectl apply -f ubuntu-dv.yaml
# DataVolume 리소스 생성
# CDI 컨트롤러가 자동으로 이미지 다운로드 시작

# 진행 상황 모니터링
$ kubectl get datavolume ubuntu-dv
NAME        PHASE       PROGRESS   RESTARTS   AGE
ubuntu-dv   ImportInProgress   20%        0          45s
# PHASE: 현재 단계 표시
# PROGRESS: 가져오기 진행률
# ImportInProgress → Succeeded로 변경되면 완료

CDI 컨트롤러는 자동으로:

  1. 지정된 URL에서 이미지를 다운로드
  2. 이미지를 PVC에 기록
  3. VM에서 사용할 수 있도록 준비

DataVolume을 사용하는 VM 생성

DataVolume을 VM의 볼륨으로 직접 지정할 수 있습니다:

# datavolume-vm.yaml
apiVersion: kubevirt.io/v1              # KubeVirt API 버전
kind: VirtualMachine                    # 리소스 종류
metadata:
  name: datavolume-vm                   # VM 이름
spec:
  running: true                         # 생성 즉시 시작
  template:
    metadata:
      labels:
        kubevirt.io/vm: datavolume-vm   # VM 식별 레이블
    spec:
      domain:
        devices:
          disks:
          - name: rootdisk              # 루트 디스크
            disk:
              bus: virtio               # virtio 버스 사용
          - name: cloudinitdisk         # cloud-init 디스크
            disk:
              bus: virtio
        resources:
          requests:
            memory: 2Gi                 # 2GB 메모리 할당
      volumes:
      - name: rootdisk
        dataVolume:
          name: ubuntu-dv               # 기존 DataVolume 참조
          # 이미 생성된 DataVolume을 VM의 디스크로 사용
      - name: cloudinitdisk
        cloudInitNoCloud:               # cloud-init 설정
          userData: |
            #cloud-config
            user: ubuntu                # 사용자 이름
            password: ubuntu            # 비밀번호
            chpasswd: { expire: False } # 비밀번호 만료 비활성화

 

VM 정의에서 DataVolume 인라인 생성

VM 정의 내에서 DataVolume을 인라인으로 정의할 수도 있습니다:

# inline-datavolume-vm.yaml
apiVersion: kubevirt.io/v1              # KubeVirt API 버전
kind: VirtualMachine                    # 리소스 종류
metadata:
  name: inline-datavolume-vm            # VM 이름
spec:
  running: true                         # 생성 즉시 시작
  dataVolumeTemplates:                  # 인라인 DataVolume 템플릿 정의
  - metadata:
      name: inline-dv                   # 생성될 DataVolume 이름
    spec:
      source:                           # 소스 정의
        http:
          url: "https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img"
          # Ubuntu 클라우드 이미지 URL
      pvc:                              # PVC 스펙
        accessModes:
          - ReadWriteOnce
        resources:
          requests:
            storage: 10Gi               # 10GB 스토리지
  template:
    spec:
      domain:
        devices:
          disks:
          - name: rootdisk
            disk:
              bus: virtio
        resources:
          requests:
            memory: 2Gi
      volumes:
      - name: rootdisk
        dataVolume:
          name: inline-dv               # 인라인 템플릿 참조
          # dataVolumeTemplates에서 정의한 DataVolume 참조

이 방식은 VM 생성 과정을 자동화하여 한 단계로 처리합니다:

  1. 사용자가 VM을 생성
  2. DataVolume이 자동으로 생성되고 이미지 임포트
  3. 임포트가 완료되면 VM이 자동으로 시작

▶️ CDI 활용 사례: "CDI는 ISO 이미지, 클라우드 이미지, 레지스트리 이미지 등 다양한 소스에서 VM 이미지를 가져올 수 있습니다. 또한 이미지 클론, VM 스냅샷, PVC 복제 등 고급 데이터 관리 기능도 제공합니다."


📌 고급 이미지 관리 기법

마지막으로, 고급 이미지 관리 기법과 유용한 팁들을 알아보겠습니다.

 

VM 이미지 변환 및 최적화

VM 이미지 형식을 변환하거나 최적화하는 방법:

# raw에서 qcow2로 변환
$ qemu-img convert -f raw -O qcow2 disk.raw disk.qcow2
# -f raw: 소스 이미지 형식 지정
# -O qcow2: 출력 이미지 형식 지정
# 원시 이미지를 공간 효율적인 qcow2로 변환

# 압축된 qcow2 이미지 생성
$ qemu-img convert -O qcow2 -c source.qcow2 compressed.qcow2
# -c: 압축 사용 (공간 절약)
# 기존 qcow2 이미지를 압축하여 크기 감소

# 이미지 크기 확인
$ qemu-img info disk.qcow2
# 이미지 정보 표시: 크기, 형식, 가상 크기, 실제 크기 등

# 이미지 크기 조정
$ qemu-img resize disk.qcow2 +10G
# 기존 디스크 이미지 크기를 10GB 증가
# 참고: 파일 시스템은 VM 내부에서 별도로 확장해야 함

 

기존 VM에서 이미지 만들기

기존 VM을 골든 이미지로 만드는 과정:

  1. VM 종료:
$ virtctl stop my-vm
# 이미지 생성을 위해 VM 중지 (데이터 일관성 보장)
  1. PVC 스냅샷 생성:
# vm-snapshot.yaml
apiVersion: snapshot.storage.k8s.io/v1  # 스냅샷 API 버전
kind: VolumeSnapshot                    # 볼륨 스냅샷 리소스
metadata:
  name: my-vm-rootdisk-snapshot         # 스냅샷 이름
spec:
  volumeSnapshotClassName: csi-hostpath-snapclass  # 스냅샷 클래스
  # 사용 가능한 스냅샷 클래스는 클러스터 설정에 따라 다름
  source:
    persistentVolumeClaimName: my-vm-rootdisk  # 스냅샷 대상 PVC
    # 스냅샷을 생성할 VM 디스크 PVC
  1. 스냅샷에서 새 PVC 생성:
# golden-image-pvc.yaml
apiVersion: v1                          # 쿠버네티스 API 버전
kind: PersistentVolumeClaim             # PVC 리소스
metadata:
  name: golden-image                    # 골든 이미지 PVC 이름
spec:
  dataSource:                           # 데이터 소스 정의
    name: my-vm-rootdisk-snapshot       # 소스 스냅샷 이름
    kind: VolumeSnapshot                # 소스 종류: 볼륨 스냅샷
    apiGroup: snapshot.storage.k8s.io   # 스냅샷 API 그룹
  accessModes:
    - ReadWriteOnce                     # 접근 모드
  resources:
    requests:
      storage: 10Gi                     # 스토리지 크기
  # 스냅샷을 기반으로 새 PVC 생성 (빠른 복제)

 

DataVolume 복제 및 클론

DataVolume을 사용하여 기존 PVC를 복제하는 방법:

# clone-datavolume.yaml
apiVersion: cdi.kubevirt.io/v1beta1     # CDI API 버전
kind: DataVolume                        # DataVolume 리소스
metadata:
  name: cloned-dv                       # 복제본 이름
spec:
  source:
    pvc:                                # PVC 소스 지정
      namespace: default                # 소스 PVC 네임스페이스
      name: golden-image                # 소스 PVC 이름 (골든 이미지)
  pvc:
    accessModes:
      - ReadWriteOnce                   # 접근 모드
    resources:
      requests:
        storage: 10Gi                   # 스토리지 크기
  # 기존 PVC를 복제하여 새 DataVolume 생성
  # CDI가 효율적인 복제 수행 (가능한 경우 스냅샷 활용)

 

이미지 업로드 기능 활용

로컬 이미지를 직접 클러스터에 업로드할 수 있는 방법:

# 업로드 프록시 포트포워딩
$ kubectl port-forward -n cdi service/cdi-uploadproxy 8443:443
# CDI 업로드 프록시 서비스에 로컬 포트 연결
# 이렇게 하면 로컬 시스템에서 8443 포트로 업로드 가능

# 이미지 업로드
$ virtctl image-upload dv new-vm-disk \
  --size=10Gi \
  --image-path=/path/to/local/disk.qcow2 \
  --insecure
# virtctl 도구를 사용하여 로컬 이미지 업로드
# --size: 생성할 DataVolume 크기
# --image-path: 로컬 디스크 이미지 경로
# --insecure: 인증서 검증 무시 (테스트 환경용)

▶️ : "프로덕션 환경에서는 골든 이미지 접근 방식을 사용하세요. 미리 설정된 OS, 보안 패치, 기본 소프트웨어가 설치된 이미지를 준비하고, DataVolume 클론 기능으로 새 VM을 빠르게 프로비저닝할 수 있습니다."


📌 Summary

이 글에서는 KubeVirt에서 VM 이미지를 다루는 다양한 방법을 알아보았습니다:

  • ContainerDisk: VM 디스크 이미지를 컨테이너로 패키징하여 불변 OS 이미지 제공
  • Docker로 ContainerDisk 생성: qcow2 이미지를 컨테이너 이미지로 변환하는 방법
  • PVC 기반 VM 디스크: 상태를 유지해야 하는 VM을 위한 영구 스토리지 구성
  • DataVolume과 CDI: URL, 레지스트리, 기존 PVC 등에서 VM 이미지를 자동으로 가져오기
  • 고급 이미지 관리: 이미지 변환, 골든 이미지 생성, 복제, 업로드 등의 기법

이러한 방법을 조합하여 효율적인 VM 이미지 관리 전략을 구축할 수 있습니다. 불변 OS 이미지는 ContainerDisk로, 데이터는 PVC로, 이미지 관리 자동화는 CDI로 처리하는 것이 일반적인 패턴입니다.

728x90