KubeVirtのVMの仮想ディスクの作り方パターン

# この記事の内容
KubeVirtでVMを作るときの流れは、ざっくり、

- 仮想ディスクを作る
- VMを作る

です。この仮想ディスクの作り方について、バリエーションが多いため整理し、役に立つと思われるパターンについて、実施例を示してみます。

# 環境

#### マシン一覧
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468232/f77c6489-d51d-45f6-ae73-932db0febd0b.png)

- 物理PCを2台使用。KVMの仮想化環境を作成。
- KVMで3VM（AlmaLinux 9.5）作り、Masterノードx1、Workerノードx2にしてk8sクラスタを構成。

#### k8sクラスタ環境
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468232/23f47916-5134-4259-8498-ca4c8c8b5d5d.png)

- k8sクラスタに対し、以下をインストール済み。
-- MetalLB（ロードバランサ用）
-- kubernetes-dashboard（k8sクラスタの各リソース表示確認など）
-- NFS Subdir External Provisioner（NFSのStorageClass用。名前はnfs-client）
-- KubeVirt（VM作成用）

- また、k8sクラスタ内のMasterノード、k8sクラスタ外のwindows11とAlmaLinux9.5(al9host)には、kubectlコマンドとkubectl virtコマンドをインストール済みであり、k8sクラスタの操作が可能。

- KubeVirtで3VM（RockyLinux 9.5）作成済み。


# 1. 試すパターン

仮想ディスクの作り方として、（あまり意味のない方法を含めて）パターン的に、このような方法が挙げられます（他にもあるかもですが、思いつくところで）。

- VMから見た仮想ディスク
-- PVCを使う
-- DataVolumeを使う（実体はPVC）

- PVの作り方
-- StorageClassから切り出す
-- PVのyamlから作る

- disk.imgの作り方
-- WebのファイルURLを指定
-- ローカルファイルを指定

これらの方法は、

(1) PVCのyamlを作成。PVはStorageClassから切り出す。disk.imgはWebURL指定。
(2) (1)の内、PVはyamlから作る。
(3) PVCをコマンドで作成。PVはStorageClassから切り出す。disk.imgはローカルファイル指定。
(4) DataVolumeのyamlを作成。基本的に(1)と同じ。

のやり方が分かれば、一通り網羅的に、仮想ディスクの作り方を把握できるのではないかと思います。

以降、この(1)～(4)の方法で、仮想ディスクを作り、VMを作る方法を、それぞれ、示してみます。いずれも、RockyLinux9.5のマシンイメージから、VMを作ります。


# 2. (1)の方法（PVCのyamlを作成／PVはStorageClassから切り出す／disk.imgはWebURL指定）

この(1)の方法は、以下で示した方法そのものです（名前などは違いますがやり方は同じ）。

https://qiita.com/nonbiri-yama/items/bc29a6ba181a2ac9b326

以下、要点だけ示します。


### (1) 実施前のPVC/PV確認

PVCリソースはありません。
```bash
[root@master1 kubevirt-test]# kubectl get pvc
No resources found in kubevirt-test namespace.
[root@master1 kubevirt-test]#
```

PVリソースは、これまでに作った3VMの4つのPVが表示されています（ルートディスク3つとISOディスク1つ）。
```
[root@master1 kubevirt-test]# kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                        STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pvc-074aba38-5b71-4b55-9d79-8910430cf271   30Gi       RWO            Delete           Bound    default/rl95vm-3cockpit      nfs-client     <unset>                          25h
pvc-d02a3efe-c6b7-4ea7-8ee4-0d14268615b0   15Gi       RWO            Delete           Bound    default/rocky-iso-9.5        nfs-client     <unset>                          28h
pvc-e6774427-e7b7-48de-921d-f04604076125   18Gi       RWO            Delete           Bound    default/rl95vm-2-rootdisk    nfs-client     <unset>                          28h
pvc-f5fcfd71-0604-4476-aebe-8f93f007b1b3   16Gi       RWO            Delete           Bound    default/rocky-9.5-20241118   nfs-client     <unset>                          7d4h
[root@master1 kubevirt-test]#
```

なお、kubevirt-testのnamespaceを作りセットしています。以下のように、namespaceのyamlファイルを作って適用し、
```
[root@master1 kubevirt-test]# vim kubevirt-test-namespace.yaml
[root@master1 kubevirt-test]#
[root@master1 kubevirt-test]# cat kubevirt-test-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: kubevirt-test
[root@master1 kubevirt-test]#
[root@master1 kubevirt-test]# kubectl apply -f ./kubevirt-test-namespace.yaml
namespace/kubevirt-test created
[root@master1 kubevirt-test]#
```

これで、作成したnamespaceに切り替わりました。
```bash
[root@master1 kubevirt]# kubectl config set-context --current --namespace=kubevirt-test
Context "kubernetes-admin@kubernetes" modified.
[root@master1 kubevirt]#
[root@master1 kubevirt-test]# kubectl config get-contexts
CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
*         kubernetes-admin@kubernetes   kubernetes   kubernetes-admin   kubevirt-test
[root@master1 kubevirt-test]#
```

### (2) PVCをyamlから作成（StorageClass、URL）

PVCリソースのyamlを作り、適用します。
```bash
[root@master1 kubevirt-test]# vim test1-1-yaml-sc-url-pvc.yaml
[root@master1 kubevirt-test]#
[root@master1 kubevirt-test]# cat test1-1-yaml-sc-url-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test1-1-yaml-pv-url-pvc
  labels:
    app: containerized-data-importer
  annotations:
    cdi.kubevirt.io/storage.import.endpoint: "https://dl.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud-Base-9.5-20241118.0.x86_64.qcow2"
spec:
  storageClassName: nfs-client
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 11Gi
[root@master1 kubevirt-test]#
[root@master1 kubevirt-test]# kubectl apply -f ./test1-1-yaml-sc-url-pvc.yaml
persistentvolumeclaim/test1-2-yaml-pv-url-pvc created
[root@master1 kubevirt-test]#
```


### (3) 実施後のPVC/PV確認

PVCリソースが作られました。
```bash
[root@master1 kubevirt-test]# kubectl get pvc
NAME                      STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
test1-1-yaml-pv-url-pvc   Bound    pvc-d9ea4023-50f8-4ae0-9029-a9edfcc38d5f   11Gi       RWO            nfs-client     <unset>                 4m55s
[root@master1 kubevirt-test]#
```

PVリソースも、StorageClassから切り出されて作られています。
```bash
[root@master1 kubevirt-test]# kubectl get pv | grep -e NAME -e kubevirt-test
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                                   STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pvc-d9ea4023-50f8-4ae0-9029-a9edfcc38d5f   11Gi       RWO            Delete           Bound    kubevirt-test/test1-1-yaml-pv-url-pvc   nfs-client     <unset>                          4m53s
[root@master1 kubevirt-test]#
```

PV（実体はNFSサーバのディレクトリ）には、disk.imgが作られています。
```bash
[root@al9host sc-nfs]# qemu-img info kubevirt-test-test1-1-yaml-pv-url-pvc-pvc-d9ea4023-50f8-4ae0-9029-a9edfcc38d5f/disk.img
image: kubevirt-test-test1-1-yaml-pv-url-pvc-pvc-d9ea4023-50f8-4ae0-9029-a9edfcc38d5f/disk.img
file format: raw
virtual size: 10.4 GiB (11161042944 bytes)
disk size: 1.27 GiB
Child node '/file':
    filename: kubevirt-test-test1-1-yaml-pv-url-pvc-pvc-d9ea4023-50f8-4ae0-9029-a9edfcc38d5f/disk.img
    protocol type: file
    file length: 10.4 GiB (11161042944 bytes)
    disk size: 1.27 GiB
[root@al9host sc-nfs]#
```


### (4) VM起動

Vmリソースのyamlを作り、適用して、VMを起動します。
```bash
[root@master1 kubevirt-test]# vim test1-1-vm.yaml
[root@master1 kubevirt-test]#
[root@master1 kubevirt-test]# cat test1-1-vm.yaml
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  labels:
    kubevirt.io/os: linux
  name: test1-1-vm
spec:
  runStrategy: Always
  template:
    metadata:
      creationTimestamp: null
      labels:
        kubevirt.io/domain: test1-1-vm
    spec:
      domain:
        cpu:
          cores: 1
        devices:
          disks:
          - disk:
              bus: virtio
            name: rootdisk
          - cdrom:
              bus: sata
              readonly: true
            name: cloudinitdisk
        machine:
          type: q35
        resources:
          requests:
            memory: 1024M
      volumes:
      - name: rootdisk
        persistentVolumeClaim:
          claimName: test1-1-yaml-pv-url-pvc
      - cloudInitNoCloud:
          userData: |
            #cloud-config
            hostname: test1-1guest
            users:
              - name: myuser
            ssh_pwauth: true
            chpasswd:
              list: |
                root:initpasswd
                myuser:initpasswd
              expire: False
        name: cloudinitdisk
[root@master1 kubevirt-test]#
[root@master1 kubevirt-test]# kubectl create -f ./test1-1-vm.yaml
virtualmachine.kubevirt.io/test1-1-vm created
[root@master1 kubevirt-test]#
```

### (5) VMへのsshログイン

Vmiリソースの情報を表示してIPアドレスを確認します。
```bash
[root@master1 kubevirt-test]# kubectl get vmi
NAME         AGE   PHASE     IP            NODENAME           READY
test1-1-vm   23s   Running   10.244.1.95   worker1.internal   True
[root@master1 kubevirt-test]#
```

VMのIPアドレスを指定して、sshでログインできました。
```bash
[root@master1 kubevirt-test]# ssh myuser@10.244.1.95
The authenticity of host '10.244.1.95 (10.244.1.95)' can't be established.
ED25519 key fingerprint is SHA256:NvEdt7uQJglFs70a5iptHoaZ86nmYfoXVP6UuTw3GNE.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.244.1.95' (ED25519) to the list of known hosts.
myuser@10.244.1.95's password:
[myuser@test1-1-vm ~]$
```


# 3. (2)の方法（PVCのyamlを作成／PVはyamlから作る／disk.imgはWebURL指定）

正直、StorageClassからPVを切り出す方が便利だし、特にStorageClassを使うことにデメリットがあるわけでもないため、こういうやり方も一応ありますよ、程度で。


### (1) PVをyamlから作成（StorageClass）

PVリソースのyamlを作り、適用します。
```bash
[root@master1 kubevirt-test]# vim test1-2-yaml-pv-url-pv.yaml
[root@master1 kubevirt-test]#
[root@master1 kubevirt-test]# cat test1-2-yaml-pv-url-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: test1-2-yaml-pv-url-pv
spec:
  storageClassName: nfs-client
  capacity:
    storage: 12Gi
  accessModes:
  - ReadWriteOnce
  nfs:
    path: /root/sc-nfs/test1-2-yaml-pv-url-pv
    server: 192.168.11.103
[root@master1 kubevirt-test]#
[root@master1 kubevirt-test]# kubectl apply -f ./test1-2-yaml-pv-url-pv.yaml
persistentvolume/test1-2-yaml-pv-url-pv created
[root@master1 kubevirt-test]#
```

この場合、StorageClassのNFSサーバのディレクトリには、「path: /root/sc-nfs/test1-2-yaml-pv-url-pv」で指定したディレクトリが自動的に作られないため、手動で作る必要があります。

ここだけ、NFSサーバのal9hostでやります。
```bash
[root@al9host sc-nfs]# mkdir test1-2-yaml-pv-url-pv; chmod 777 test1-2-yaml-pv-url-pv
[root@al9host sc-nfs]#
```


### (2) 実施後のPV確認

PVリソースが作られました。PVCにバインドされていないため、STATUSがAvailableです。あと、上のyamlの場合、RECLAIM POLICYがRetainになっています（バインドしたPVCを消しても、PVのSTATUSがReleasedになり残る）
```bash
[root@master1 kubevirt-test]# kubectl get pv | grep -e NAME -e test
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                                   STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pvc-d9ea4023-50f8-4ae0-9029-a9edfcc38d5f   11Gi       RWO            Delete           Bound       kubevirt-test/test1-1-yaml-pv-url-pvc   nfs-client     <unset>                          143m
test1-2-yaml-pv-url-pv                     12Gi       RWO            Retain           Available                                           nfs-client     <unset>                          58s
[root@master1 kubevirt-test]#
```


### (3) PVCをyamlから作成（StorageClass、URL）

PVCリソースのyamlを作り、適用します。
```bash
[root@master1 kubevirt-test]# vim ./test1-2-yaml-pv-url-pvc.yaml
[root@master1 kubevirt-test]#
[root@master1 kubevirt-test]# cat ./test1-2-yaml-pv-url-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test1-2-yaml-pv-url-pvc
  labels:
    app: containerized-data-importer
  annotations:
    cdi.kubevirt.io/storage.import.endpoint: "https://dl.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud-Base-9.5-20241118.0.x86_64.qcow2"
spec:
  storageClassName: nfs-client
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 12Gi
[root@master1 kubevirt-test]#
[root@master1 kubevirt-test]# kubectl apply -f ./test1-2-yaml-pv-url-pvc.yaml
persistentvolumeclaim/test1-2-yaml-pv-url-pvc created
[root@master1 kubevirt-test]#
```


### (4) 実施後のPVC/PV確認

PVCリソースが作られました。先に作成しておいたPVがバインドされています。
```bash
[root@master1 kubevirt-test]# kubectl get pvc
NAME                      STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
test1-1-yaml-pv-url-pvc   Bound    pvc-d9ea4023-50f8-4ae0-9029-a9edfcc38d5f   11Gi       RWO            nfs-client     <unset>                 152m
test1-2-yaml-pv-url-pvc   Bound    test1-2-yaml-pv-url-pv                     12Gi       RWO            nfs-client     <unset>                 33s
[root@master1 kubevirt-test]#
[root@master1 kubevirt-test]# kubectl get pv | grep -e NAME -e test
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                                   STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pvc-d9ea4023-50f8-4ae0-9029-a9edfcc38d5f   11Gi       RWO            Delete           Bound    kubevirt-test/test1-1-yaml-pv-url-pvc   nfs-client     <unset>                          151m
test1-2-yaml-pv-url-pv                     12Gi       RWO            Retain           Bound    kubevirt-test/test1-2-yaml-pv-url-pvc   nfs-client     <unset>                          9m8s
[root@master1 kubevirt-test]#
```

PV（実体はNFSサーバのディレクトリ）には、disk.imgが作られています。
```bash
[root@al9host sc-nfs]# qemu-img info test1-2-yaml-pv-url-pv/disk.img
image: test1-2-yaml-pv-url-pv/disk.img
file format: raw
virtual size: 11.3 GiB (12176064512 bytes)
disk size: 1.26 GiB
Child node '/file':
    filename: test1-2-yaml-pv-url-pv/disk.img
    protocol type: file
    file length: 11.3 GiB (12176064512 bytes)
    disk size: 1.26 GiB
[root@al9host sc-nfs]#
```


### (5) VM起動

Vmリソースのyamlを作り、適用して、VMを起動します。
```bash
[root@master1 kubevirt-test]# vim test1-2-vm.yaml
[root@master1 kubevirt-test]#
[root@master1 kubevirt-test]# cat test1-2-vm.yaml
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  labels:
    kubevirt.io/os: linux
  name: test1-2-vm
spec:
  runStrategy: Always
  template:
    metadata:
      creationTimestamp: null
      labels:
        kubevirt.io/domain: test1-2-vm
    spec:
      domain:
        cpu:
          cores: 1
        devices:
          disks:
          - disk:
              bus: virtio
            name: rootdisk
          - cdrom:
              bus: sata
              readonly: true
            name: cloudinitdisk
        machine:
          type: q35
        resources:
          requests:
            memory: 1024M
      volumes:
      - name: rootdisk
        persistentVolumeClaim:
          claimName: test1-2-yaml-pv-url-pvc
      - cloudInitNoCloud:
          userData: |
            #cloud-config
            hostname: test1-2guest
            users:
              - name: myuser
            ssh_pwauth: true
            chpasswd:
              list: |
                root:initpasswd
                myuser:initpasswd
              expire: False
        name: cloudinitdisk
[root@master1 kubevirt-test]#
[root@master1 kubevirt-test]# kubectl apply -f ./test1-2-vm.yaml
virtualmachine.kubevirt.io/test1-2-vm created
[root@master1 kubevirt-test]#
```


### (6) VMへのsshログイン

Vmiリソースの情報を表示してIPアドレスを確認します。
```bash
[root@master1 kubevirt-test]# kubectl get vmi
NAME         AGE    PHASE     IP            NODENAME           READY
test1-1-vm   159m   Running   10.244.1.95   worker1.internal   True
test1-2-vm   11s    Running   10.244.1.98   worker1.internal   True
[root@master1 kubevirt-test]#
```

VMのIPアドレスを指定して、sshでログインできました。
```bash
[root@master1 kubevirt-test]# ssh myuser@10.244.1.98
The authenticity of host '10.244.1.98 (10.244.1.98)' can't be established.
ED25519 key fingerprint is SHA256:jmq1aRkz8nthQSd1LoSOlCW5OovbQ/74j5dxJtqkeiI.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.244.1.98' (ED25519) to the list of known hosts.
myuser@10.244.1.98's password:
[myuser@test1-2-vm ~]$
```


# 4. (3)の方法（PVCはコマンドで作成／PVはStorageClassから切り出す／disk.imgはローカルファイルを指定）

この(3)の方法は、以下で示した方法です（ISOファイル、KVMで作ったimgファイル、でやっています）。

https://qiita.com/nonbiri-yama/items/977806dcd9bb031689e8

kubectl virt image-uploadコマンドを使います。コマンドを使ってリソースを操作するのは、k8sで重要な宣言的設定を使う方針に反するので、あまり気が進みません。

しかし、そもそも、yamlファイルに記述して、CDIでローカルファイルをアップロードする方法は、見つけられませんでした（無いと書いてる情報は見つけられていませんが、できるという情報が見つけられない）。
また、ISOファイルは特に、認証なしに取得できるURLを示せるとは限りませんし、同じ581MiBのマシンイメージファイルをアップロードするにしても、Webから落とさせるより、ローカルファイルをアップロードする方が、圧倒的に早いです。

以上から、恐らく、(1)よりも使いやすい方法ではないかと思います。


以下、要点だけ示します。

### (1) cdi-uploadproxyのIPアドレス確認

アップロード先として指定する必要があるので、IPアドレスを確認します。以下の場合、「10.111.218.50」です。
```bash
[root@master1 kubevirt-test]# kubectl get service -n cdi
NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
cdi-api                  ClusterIP   10.110.82.60    <none>        443/TCP    12d
cdi-prometheus-metrics   ClusterIP   10.105.9.213    <none>        8080/TCP   12d
cdi-uploadproxy          ClusterIP   10.111.218.50   <none>        443/TCP    37h
[root@master1 kubevirt-test]#
```


### (2) ローカルファイルのPVへのアップロードとPVC作成

このコマンドで、
- PVC作成
- PV作成
- disk.img作成

が、まとめて行われます。
```bash
[root@master1 kubevirt-test]# kubectl virt image-upload pvc test1-3-cmd-pv-file-pvc --storage-class nfs-client --size 13Gi --uploadproxy-url=10.111.218.50 --image-path=/root/kubevirt/Rocky-9-GenericCloud-Base-9.5-20241118.0.x86_64.qcow2 --insecure
PVC kubevirt-test/test1-3-cmd-pv-file-pvc not found
PersistentVolumeClaim kubevirt-test/test1-3-cmd-pv-file-pvc created
Waiting for PVC test1-3-cmd-pv-file-pvc upload pod to be ready...
Pod now ready
Uploading data to https://10.111.218.50

581.56 MiB / 581.56 MiB [---------------------------------------------------------------] 100.00% 52.53 MiB p/s 11s

Uploading data completed successfully, waiting for processing to complete, you can hit ctrl-c without interrupting the progress
Processing completed successfully
Uploading /root/kubevirt/Rocky-9-GenericCloud-Base-9.5-20241118.0.x86_64.qcow2 completed successfully
[root@master1 kubevirt-test]#
```

### (3) 実施後のPVC/PV確認

作られています。
```bash
[root@master1 kubevirt-test]# kubectl get pv | grep -e NAME -e test
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                                   STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pvc-c2b70d42-2cc6-4e91-bd64-e1ab59caec47   13Gi       RWO            Delete           Bound    kubevirt-test/test1-3-cmd-pv-file-pvc   nfs-client     <unset>                          4m16s
pvc-d9ea4023-50f8-4ae0-9029-a9edfcc38d5f   11Gi       RWO            Delete           Bound    kubevirt-test/test1-1-yaml-pv-url-pvc   nfs-client     <unset>                          10h
test1-2-yaml-pv-url-pv                     12Gi       RWO            Retain           Bound    kubevirt-test/test1-2-yaml-pv-url-pvc   nfs-client     <unset>                          8h
[root@master1 kubevirt-test]#
[root@master1 kubevirt-test]# kubectl get pvc
NAME                      STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
test1-1-yaml-pv-url-pvc   Bound    pvc-d9ea4023-50f8-4ae0-9029-a9edfcc38d5f   11Gi       RWO            nfs-client     <unset>                 10h
test1-2-yaml-pv-url-pvc   Bound    test1-2-yaml-pv-url-pv                     12Gi       RWO            nfs-client     <unset>                 8h
test1-3-cmd-pv-file-pvc   Bound    pvc-c2b70d42-2cc6-4e91-bd64-e1ab59caec47   13Gi       RWO            nfs-client     <unset>                 4m20s
[root@master1 kubevirt-test]#
```

PV（実体はNFSサーバのディレクトリ）には、disk.imgが作られています。
```bash
[root@al9host sc-nfs]# qemu-img info kubevirt-test-test1-3-cmd-pv-file-pvc-pvc-c2b70d42-2cc6-4e91-bd64-e1ab59caec47/disk.img
image: kubevirt-test-test1-3-cmd-pv-file-pvc-pvc-c2b70d42-2cc6-4e91-bd64-e1ab59caec47/disk.img
file format: raw
virtual size: 12.3 GiB (13190037504 bytes)
disk size: 1.13 GiB
Child node '/file':
    filename: kubevirt-test-test1-3-cmd-pv-file-pvc-pvc-c2b70d42-2cc6-4e91-bd64-e1ab59caec47/disk.img
    protocol type: file
    file length: 12.3 GiB (13190037504 bytes)
    disk size: 1.13 GiB
[root@al9host sc-nfs]#
```

### (4) VM起動
Vmリソースのyamlを作り、適用して、VMを起動します。
```bash
[root@master1 kubevirt-test]# vim test1-3-vm.yaml
[root@master1 kubevirt-test]#
[root@master1 kubevirt-test]# cat test1-3-vm.yaml
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  labels:
    kubevirt.io/os: linux
  name: test1-3-vm
spec:
  runStrategy: Always
  template:
    metadata:
      creationTimestamp: null
      labels:
        kubevirt.io/domain: test1-3-vm
    spec:
      domain:
        cpu:
          cores: 1
        devices:
          disks:
          - disk:
              bus: virtio
            name: rootdisk
          - cdrom:
              bus: sata
              readonly: true
            name: cloudinitdisk
        machine:
          type: q35
        resources:
          requests:
            memory: 1024M
      volumes:
      - name: rootdisk
        persistentVolumeClaim:
          claimName: test1-3-cmd-pv-file-pvc
      - cloudInitNoCloud:
          userData: |
            #cloud-config
            hostname: test1-3guest
            users:
              - name: myuser
            ssh_pwauth: true
            chpasswd:
              list: |
                root:initpasswd
                myuser:initpasswd
              expire: False
        name: cloudinitdisk
[root@master1 kubevirt-test]#
[root@master1 kubevirt-test]# kubectl apply -f ./test1-3-vm.yaml
virtualmachine.kubevirt.io/test1-3-vm created
[root@master1 kubevirt-test]#
```


### (5) VMへのsshログイン
Vmiリソースの情報を表示してIPアドレスを確認します。

```bash
[root@master1 kubevirt-test]# kubectl get vmi
NAME         AGE     PHASE     IP             NODENAME           READY
test1-1-vm   10h     Running   10.244.1.95    worker1.internal   True
test1-2-vm   7h50m   Running   10.244.1.98    worker1.internal   True
test1-3-vm   47s     Running   10.244.1.100   worker1.internal   True
[root@master1 kubevirt-test]#
```

VMのIPアドレスを指定して、sshでログインできました。
```bash
[root@master1 kubevirt-test]# ssh myuser@10.244.1.100
The authenticity of host '10.244.1.100 (10.244.1.100)' can't be established.
ED25519 key fingerprint is SHA256:iXd23rRWVJ6Ann/kxgc2x92e/OHc/rOLLUUvdB52cUc.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.244.1.100' (ED25519) to the list of known hosts.
myuser@10.244.1.100's password:
[myuser@test1-3-vm ~]$
```


# 5. (4)の方法（DataVolumeのyamlを作成／PVはStorageClassから切り出す／disk.imgはWebURL指定）

正直、(1)と(3)の方法で、事足りていると思いますが、KubeVirtのマニフェストファイルの例を探すと、結構、「kind: DataVolume」が出てくるので、どういうものか把握しておくことは必要です。

DataVolumeとはなにかは、以下に説明があります。

https://kubevirt.io/user-guide/storage/disks_and_volumes/


>dataVolume
DataVolumes are a way to automate importing virtual machine disks onto PVCs during the virtual machine's launch flow. Without using a DataVolume, users have to prepare a PVC with a disk image before assigning it to a VM or VMI manifest. With a DataVolume, both the PVC creation and import is automated on behalf of the user.

つまり、DataVolumeリソースは、VMを作成するときに、仮想ディスクをPVCにインポートする、ということをしてくれるリソースです。これによって、VM作成前にPVCを作っておく手間を省けます、とのこと。

ということで、これを使ってやってみます。

### (1) DataVolumeをyamlから作成（StorageClass、URL）

DataVolumeリソースのyamlを作り、適用します。

```bash
[root@master1 kubevirt-test]# vim test1-4-yaml-dv.yaml
[root@master1 kubevirt-test]#
[root@master1 kubevirt-test]# cat test1-4-yaml-dv.yaml
apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
  name: test1-4-datavolume
  namespace: kubevirt-test
spec:
  source:
    http:
      url: "https://dl.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud-Base-9.5-20241118.0.x86_64.qcow2"
  pvc:
    accessModes:
    - ReadWriteOnce
    resources:
      requests:
        storage: 14Gi
    storageClassName: nfs-client
[root@master1 kubevirt-test]#
[root@master1 kubevirt-test]# kubectl apply -f ./test1-4-yaml-dv.yaml
datavolume.cdi.kubevirt.io/test1-4-datavolume created
[root@master1 kubevirt-test]#
```

### (2) 実施後のPVC/PV確認

PVCリソースが作られました。先に作成しておいたPVがバインドされています。

```bash
[root@master1 kubevirt-test]# kubectl get pv | grep -e NAME -e test
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                                   STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pvc-193f1361-921c-48bf-9944-2b8fe85fefe3   14Gi       RWO            Delete           Bound    kubevirt-test/test1-4-datavolume        nfs-client     <unset>                          4m51s
pvc-c2b70d42-2cc6-4e91-bd64-e1ab59caec47   13Gi       RWO            Delete           Bound    kubevirt-test/test1-3-cmd-pv-file-pvc   nfs-client     <unset>                          36m
pvc-d9ea4023-50f8-4ae0-9029-a9edfcc38d5f   11Gi       RWO            Delete           Bound    kubevirt-test/test1-1-yaml-pv-url-pvc   nfs-client     <unset>                          11h
test1-2-yaml-pv-url-pv                     12Gi       RWO            Retain           Bound    kubevirt-test/test1-2-yaml-pv-url-pvc   nfs-client     <unset>                          8h
[root@master1 kubevirt-test]#
[root@master1 kubevirt-test]# kubectl get pvc
NAME                      STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
test1-1-yaml-pv-url-pvc   Bound    pvc-d9ea4023-50f8-4ae0-9029-a9edfcc38d5f   11Gi       RWO            nfs-client     <unset>                 11h
test1-2-yaml-pv-url-pvc   Bound    test1-2-yaml-pv-url-pv                     12Gi       RWO            nfs-client     <unset>                 8h
test1-3-cmd-pv-file-pvc   Bound    pvc-c2b70d42-2cc6-4e91-bd64-e1ab59caec47   13Gi       RWO            nfs-client     <unset>                 36m
test1-4-datavolume        Bound    pvc-193f1361-921c-48bf-9944-2b8fe85fefe3   14Gi       RWO            nfs-client     <unset>                 4m54s
[root@master1 kubevirt-test]#
```

PV（実体はNFSサーバのディレクトリ）には、disk.imgが作られています。
```bash
[root@al9host sc-nfs]# qemu-img info kubevirt-test-test1-4-datavolume-pvc-193f1361-921c-48bf-9944-2b8fe85fefe3/disk.img
image: kubevirt-test-test1-4-datavolume-pvc-193f1361-921c-48bf-9944-2b8fe85fefe3/disk.img
file format: raw
virtual size: 13.2 GiB (14205059072 bytes)
disk size: 1.13 GiB
Child node '/file':
    filename: kubevirt-test-test1-4-datavolume-pvc-193f1361-921c-48bf-9944-2b8fe85fefe3/disk.img
    protocol type: file
    file length: 13.2 GiB (14205059072 bytes)
    disk size: 1.13 GiB
[root@al9host sc-nfs]#
```

### (3) 実施後のDataVolume確認

datavolumeリソースも作られています。
```bash
[root@master1 kubevirt-test]# kubectl get datavolume
NAME                 PHASE       PROGRESS   RESTARTS   AGE
test1-4-datavolume   Succeeded   100.0%                6m2s
[root@master1 kubevirt-test]#
```

describeは以下です。
```bash
[root@master1 kubevirt-test]# kubectl describe datavolume test1-4-datavolume
Name:         test1-4-datavolume
Namespace:    kubevirt-test
Labels:       <none>
Annotations:  cdi.kubevirt.io/storage.usePopulator: false
API Version:  cdi.kubevirt.io/v1beta1
Kind:         DataVolume
Metadata:
  Creation Timestamp:  2025-02-23T14:32:24Z
  Generation:          1
  Resource Version:    1342794
  UID:                 f9518349-f314-4f5c-b328-2238fc7dce43
Spec:
  Pvc:
    Access Modes:
      ReadWriteOnce
    Resources:
      Requests:
        Storage:         14Gi
    Storage Class Name:  nfs-client
  Source:
    Http:
      URL:  https://dl.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud-Base-9.5-20241118.0.x86_64.qcow2
Status:
  Claim Name:  test1-4-datavolume
  Conditions:
    Last Heartbeat Time:   2025-02-23T14:32:24Z
    Last Transition Time:  2025-02-23T14:32:24Z
    Message:               PVC test1-4-datavolume Bound
    Reason:                Bound
    Status:                True
    Type:                  Bound
    Last Heartbeat Time:   2025-02-23T14:36:55Z
    Last Transition Time:  2025-02-23T14:36:55Z
    Status:                True
    Type:                  Ready
    Last Heartbeat Time:   2025-02-23T14:36:54Z
    Last Transition Time:  2025-02-23T14:36:54Z
    Message:               Import Complete
    Reason:                Completed
    Status:                False
    Type:                  Running
  Phase:                   Succeeded
  Progress:                100.0%
Events:
  Type     Reason            Age    From                          Message
  ----     ------            ----   ----                          -------
  Normal   Pending           6m32s  datavolume-import-controller  PVC test1-4-datavolume Pending
  Normal   Bound             6m32s  datavolume-import-controller  PVC test1-4-datavolume Bound
  Normal   ImportInProgress  6m30s  datavolume-import-controller  Import into test1-4-datavolume in progress
  Warning  Completed         2m2s   datavolume-import-controller  Import Complete
  Normal   ImportSucceeded   2m1s   datavolume-import-controller  Successfully imported into PVC test1-4-datavolume
[root@master1 kubevirt-test]#
```

### (5) VM起動

Vmリソースのyamlを作り、適用して、VMを起動します。
```bash
[root@master1 kubevirt-test]# cat test1-4-vm.yaml
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: test1-4-vm
  namespace: kubevirt-test
  labels:
    kubevirt.io/os: linux
spec:
  runStrategy: Always
  template:
    metadata:
      labels:
        kubevirt.io/domain: test1-4-vm
    spec:
      domain:
        cpu:
          cores: 1
        devices:
          disks:
          - disk:
              bus: virtio
            name: rootdisk
          - cdrom:
              bus: sata
              readonly: true
            name: cloudinitdisk
        machine:
          type: q35
        resources:
          requests:
            memory: 1024M
      volumes:
      - name: rootdisk
        dataVolume:
          name: test1-4-datavolume
      - cloudInitNoCloud:
          userData: |
            #cloud-config
            hostname: test1-4guest
            users:
              - name: myuser
            ssh_pwauth: true
            chpasswd:
              list: |
                root:initpasswd
                myuser:initpasswd
              expire: False
        name: cloudinitdisk
[root@master1 kubevirt-test]#
[root@master1 kubevirt-test]# kubectl apply -f ./test1-4-vm.yaml
virtualmachine.kubevirt.io/test1-4-vm created
[root@master1 kubevirt-test]#
```

### (6) VMへのsshログイン
Vmiリソースの情報を表示してIPアドレスを確認します。

```bash
[root@master1 kubevirt-test]# kubectl get vmi
NAME         AGE   PHASE     IP             NODENAME           READY
test1-1-vm   11h   Running   10.244.1.95    worker1.internal   True
test1-2-vm   8h    Running   10.244.1.98    worker1.internal   True
test1-3-vm   34m   Running   10.244.1.100   worker1.internal   True
test1-4-vm   37s   Running   10.244.3.141   worker2.internal   True
[root@master1 kubevirt-test]#
```

VMのIPアドレスを指定して、sshでログインできました。
```bash
[root@master1 kubevirt-test]# ssh myuser@10.244.3.141
The authenticity of host '10.244.3.141 (10.244.3.141)' can't be established.
ED25519 key fingerprint is SHA256:tb1S999xrHjGrtM2o5AiqXFEcMHqBqX9cohbB48E5LM.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.244.3.141' (ED25519) to the list of known hosts.
myuser@10.244.3.141's password:
[myuser@test1-4-vm ~]$
```

ということで、DataVolumeを使ってみましたが、(1)のPVCとの違いは、特に無いように思います。CDIのアップロードの進捗を、kubectl get datavolumeで確認できること、くらいでしょうか（別にそれだって、kubectl logs -fで確認できますが）。


# まとめ
KubeVirtでVMを作るときにバリエーションの多い、仮想ディスクの作り方について、4つのパターンについて比較し、それぞれ、試しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468232/e0f7f94f-22e9-4e1d-aeec-2fccb56e390f.png)

このような4VMを作りました。