KubeVirtで色々な方法でVMを作る

# この記事の内容

KubeVirtでVMを作成する方法として、以下があると思います。

- マシンイメージとcloud-initでVM作成
- インストーラISOファイルでVM作成
- 他のKVM環境で作ったVMの仮想ディスクからVM作成

1つ目の方法は、以下の記事の通り確認済みなので、本記事では、2つ目、3つ目の方法を試します。

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


# 環境

#### マシン一覧
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468232/3742299c-8646-4727-a430-aecef268baeb.png)

- 物理PCを2台使用。KVMの仮想化環境を作成。
- KVMで3VM（AlmaLinux 9.5）作り、Masterノードx1、Workerノードx2にしてk8sクラスタを構成。
- KubeVirtで1VM（RockyLinux 9.5）作成。これは、マシンイメージとcloud-initで作成。

#### k8sクラスタ環境（192.168.11.0/24の線の右側）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468232/ba5852f9-0c43-4453-94bb-a3418036da43.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クラスタの操作が可能。

# 1. インストーラISOファイルでVM作成

LinuxをインストーラISOファイルからVM作成するガイドはありません。以下の、Windows11をISOからVM作成するガイドがあるので、これを参考にして、やってみます。

https://kubevirt.io/2022/KubeVirt-installing_Microsoft_Windows_11_from_an_iso.html

### (1) ISOファイルをPVにアップロード

ガイドのコマンドを適当に読み替えて実行しましたが、Waiting forで止まり、5分くらいでtime outを出して終わりました。
```bash
[root@al9host kvm_images]# kubectl virt image-upload pvc rocky-iso-9.5 --size 15Gi --image-path=/var/lib/libvirt/images/Rocky-9.5-x86_64-dvd.iso --insecure
PVC default/rocky-iso-9.5 not found
PersistentVolumeClaim default/rocky-iso-9.5 created
Waiting for PVC rocky-iso-9.5 upload pod to be ready...
timed out waiting for the condition
[root@al9host kvm_images]#
```

PVCは一覧に出ますが、Pendingです。
```bash
[root@master1 kubevirt]# kubectl get pvc,pv
NAME                                       STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
～
persistentvolumeclaim/rocky-iso-9.5        Pending                                                                                       <unset>                 3m49s
～
[root@master1 kubevirt]#
```


describeで詳細を見ると、
```bash
[root@master1 kubevirt]# kubectl describe pvc rocky-iso-9.5
Name:          rocky-iso-9.5
Namespace:     default
StorageClass:
Status:        Pending
Volume:
Labels:        <none>
Annotations:   cdi.kubevirt.io/storage.contentType: kubevirt
               cdi.kubevirt.io/storage.upload.target:
Finalizers:    [kubernetes.io/pvc-protection]
Capacity:
Access Modes:
VolumeMode:    Filesystem
Used By:       <none>
Events:
  Type    Reason         Age                  From                         Message
  ----    ------         ----                 ----                         -------
  Normal  FailedBinding  5s (x24 over 5m47s)  persistentvolume-controller  no persistent volumes available for this claim and no storage class is set
[root@master1 kubevirt]#
```

となっており、StorageClassが指定されていない、と出ています。サンプルコマンドは、Rook/Cephがあることを前提とするためか、そのままやってもエラーになるようです。

本環境はnfs-clientのStorageClassにPVCを作りたいので、それを指定するオプション（--storage-class nfs-client）を指定します。

```bash
[root@al9host kvm_images]# kubectl virt image-upload pvc rocky-iso-9.5 --storage-class nfs-client --size 15Gi --image-path=/var/lib/libvirt/images/Rocky-9.5-x86_64-dvd.iso --insecure
PVC default/rocky-iso-9.5 not found
PersistentVolumeClaim default/rocky-iso-9.5 created
Waiting for PVC rocky-iso-9.5 upload pod to be ready...
Pod now ready
uploadproxy URL not found
[root@al9host kvm_images]#
```

が、これもエラーで終わりました。uploadproxy URLをオプション指定する必要がある、と出ています。以下のcdi-uploadproxyのPodのIPアドレスか、cdi-uploadproxyのServiceのIPアドレスを指定する必要があるようです。

```bash
[root@master1 kubevirt]# kubectl get pod -n cdi -o wide
NAME                               READY   STATUS    RESTARTS   AGE     IP             NODE               NOMINATED NODE   READINESS GATES
cdi-apiserver-cb54d6865-4dvwh      1/1     Running   3          6d22h   10.244.3.105   worker2.internal   <none>           <none>
cdi-deployment-788b9948f8-5b9d8    1/1     Running   5          6d22h   10.244.3.98    worker2.internal   <none>           <none>
cdi-operator-7f6b8ddb4f-mqqkf      1/1     Running   5          6d22h   10.244.3.111   worker2.internal   <none>           <none>
cdi-uploadproxy-6cf85fc475-pbt5k   1/1     Running   3          6d22h   10.244.3.102   worker2.internal   <none>           <none>
[root@master1 kubevirt]#
[root@master1 kubevirt]# kubectl get service -n cdi
NAME                     TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
cdi-api                  ClusterIP   10.110.82.60   <none>        443/TCP    10d
cdi-prometheus-metrics   ClusterIP   10.105.9.213   <none>        8080/TCP   10d
cdi-uploadproxy          ClusterIP   10.104.14.2    <none>        443/TCP    10d
[root@master1 kubevirt]#
```

ServiceのIPアドレスを指定した「--uploadproxy-url=10.104.14.2」を追加したところ、アップロードできました。インストーラISOファイルが10.72GiBなので、収まる適当なサイズ（15GiB）を指定しています。
```bash
[root@master1 kubevirt]# kubectl virt image-upload pvc rocky-iso-9.5 --storage-class nfs-client --size 15Gi --uploadproxy-url=10.104.14.2 --image-path=/tmp/Rocky-9.5-x86_64-dvd.iso --insecure
Using existing PVC default/rocky-iso-9.5
Uploading data to https://10.104.14.2

10.72 GiB / 10.72 GiB [----------------------------] 100.00% 55.48 MiB p/s 3m18s

Uploading data completed successfully, waiting for processing to complete, you can hit ctrl-c without interrupting the progress
Processing completed successfully
Uploading /tmp/Rocky-9.5-x86_64-dvd.iso completed successfully
[root@master1 kubevirt]#
```

こういう状態です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468232/bba950cf-bbc1-473d-8511-4551b4b15d4b.png)

PVは15GiBです。
```bash
[root@master1 kubevirt]# kubectl get pvc,pv | grep -e NAME -e rocky-iso-9.5
NAME                                            STATUS   VOLUME                                     CAPACITY      ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
persistentvolumeclaim/rocky-iso-9.5             Bound    pvc-d02a3efe-c6b7-4ea7-8ee4-0d14268615b0   15Gi          RWO            nfs-client     <unset>                 3h6m
NAME                                                        CAPACITY      ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                             STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
persistentvolume/pvc-d02a3efe-c6b7-4ea7-8ee4-0d14268615b0   15Gi          RWO            Delete           Bound    default/rocky-iso-9.5             nfs-client     <unset>                          3h6m
[root@master1 kubevirt]#
```

インストーラISOファイル（Rocky-9.5-x86_64-dvd.iso）は10.7GiBでしたが、CDIによって14.2GiBのdisk.imgというファイルに変換されて格納されています。
```bash
[root@al9host sc-nfs]# qemu-img info ./default-rocky-iso-9.5-pvc-d02a3efe-c6b7-4ea7-8ee4-0d14268615b0/disk.img
image: ./default-rocky-iso-9.5-pvc-d02a3efe-c6b7-4ea7-8ee4-0d14268615b0/disk.img
file format: raw
virtual size: 14.2 GiB (15220080640 bytes)
disk size: 10.7 GiB
Child node '/file':
    filename: ./default-rocky-iso-9.5-pvc-d02a3efe-c6b7-4ea7-8ee4-0d14268615b0/disk.img
    protocol type: file
    file length: 14.2 GiB (15220080640 bytes)
    disk size: 10.7 GiB
[root@al9host sc-nfs]#
```


### (2) ゲストOSのルートディスクのPV作成

VMは、インストーラISOファイルと、ゲストOSのインストール先にする仮想ディスク（=ルートディスク）を接続して起動します。続いて、インストール先にする仮想ディスクのPVを作ります。

StorageClassから18GiBくらい切り出して、rl95vm-2-rootdiskという名前のPVCリソース（PVあり）にするマニフェストファイルを作成します。
```yaml:rl95vm-2-rootdisk.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: "rl95vm-2-rootdisk"
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 18Gi
  storageClassName: nfs-client
```

適用してPVCを作成します。
```bash
[root@master1 kubevirt]# kubectl apply -f ./rl95vm-2-rootdisk.yaml
persistentvolumeclaim/rl95vm-2-rootdisk created
[root@master1 kubevirt]#
```

作られました。
```bash
[root@master1 kubevirt]# kubectl get pvc,pv | grep -e NAME -e rl95vm-2-rootdisk
NAME                                       STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
persistentvolumeclaim/rl95vm-2-rootdisk    Bound     pvc-e6774427-e7b7-48de-921d-f04604076125   18Gi       RWO            nfs-client     <unset>                 49s
NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                        STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
persistentvolume/pvc-e6774427-e7b7-48de-921d-f04604076125   18Gi       RWO            Delete           Bound    default/rl95vm-2-rootdisk    nfs-client     <unset>                          49s
[root@master1 kubevirt]#
```


### (3) VMの起動

ガイドのサンプルはVmiリソースのマニフェストファイルの例ですが、サンプル目的であって、本来はVmリソースのマニフェストファイルを作るように、とあります。マシンイメージから作ったときの、Vmリソースのマニフェストファイルがありますので、これを複製して、cloud-initのISOファイルの代わりに、OSインストーラISOファイルに変えて、Vmリソースのマニフェストファイルを作ります。

```bash
[root@master1 kubevirt]# cp rl95vm-1.yaml rl95vm-2iso.yaml
[root@master1 kubevirt]# 
[root@master1 kubevirt]# vim rl95vm-2iso.yaml
[root@master1 kubevirt]#
```

これでVMを起動し、VMのVNC画面のプロキシを起動し、VNCビューアで接続してみましたが、以下のように、「No bootable device.」となり、インストーラが起動しません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468232/98d3521d-56c2-4dc0-af82-82a2dff77ada.png)

多分、ISOファイルより先に、空の仮想ディスクからOSを起動しようとしてるのだろう、ということで、yamlファイルのdisk:の順番を逆にしてみましたがダメでした。

Copilotによると、bootOrder:を指定すると良い、ということで、やってみたところ上手くいきました。

ということで、上手くいったVmリソースのマニフェストファイルは、以下でした。
```yaml:rl95vm-2iso.yaml
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  creationTimestamp: 2018-07-04T15:03:08Z
  generation: 1
  labels:
    kubevirt.io/os: linux
  name: rl95vm-2iso
spec:
  runStrategy: Always
  template:
    metadata:
      creationTimestamp: null
      labels:
        kubevirt.io/domain: rl95vm-2iso
    spec:
      domain:
        cpu:
          cores: 4
        devices:
          disks:
          - disk:
              bus: virtio
            name: rootdisk
            bootOrder: 2
          - cdrom:
              bus: sata
              readonly: true
            name: isodisk
            bootOrder: 1
        machine:
          type: q35
        resources:
          requests:
            memory: 4096M
      volumes:
      - name: rootdisk
        persistentVolumeClaim:
          claimName: rl95vm-2-rootdisk
      - name: isodisk
        persistentVolumeClaim:
          claimName: rocky-iso-9.5
```

コピー元のrl95vm-1.yaml（マシンイメージからVM作成したもの）とのdiffは以下です。
```bash
[root@master1 kubevirt]# diff -U1 rl95vm-1.yaml rl95vm-2iso.yaml
--- rl95vm-1.yaml       2025-02-16 17:13:30.193986273 +0900
+++ rl95vm-2iso.yaml    2025-02-22 09:36:44.145428897 +0900
@@ -7,3 +7,3 @@
     kubevirt.io/os: linux
-  name: rl95vm-1
+  name: rl95vm-2iso
 spec:
@@ -14,3 +14,3 @@
       labels:
-        kubevirt.io/domain: rl95vm-1
+        kubevirt.io/domain: rl95vm-2iso
     spec:
@@ -23,3 +23,4 @@
               bus: virtio
-            name: disk0
+            name: rootdisk
+            bootOrder: 2
           - cdrom:
@@ -27,3 +28,4 @@
               readonly: true
-            name: cloudinitdisk
+            name: isodisk
+            bootOrder: 1
         machine:
@@ -34,17 +36,7 @@
       volumes:
-      - name: disk0
+      - name: rootdisk
         persistentVolumeClaim:
-          claimName: rocky-9.5-20241118
-      - cloudInitNoCloud:
-          userData: |
-            #cloud-config
-            hostname: rl95vm-1
-            users:
-              - name: myuser
-            ssh_pwauth: true
-            chpasswd:
-              list: |
-                root:al9host!
-                myuser:al9host!
-              expire: False
-        name: cloudinitdisk
+          claimName: rl95vm-2-rootdisk
+      - name: isodisk
+        persistentVolumeClaim:
+          claimName: rocky-iso-9.5
[root@master1 kubevirt]#
```

これでVmリソースを作成すると、VMが起動します。
```bash
[root@master1 kubevirt]# kubectl apply -f ./rl95vm-2iso.yaml
virtualmachine.kubevirt.io/rl95vm-2iso created
[root@master1 kubevirt]#
```

```bash
[root@master1 kubevirt]# kubectl get vm,vmi
NAME                                     AGE     STATUS    READY
virtualmachine.kubevirt.io/rl95vm-1      5d15h   Running   True
virtualmachine.kubevirt.io/rl95vm-2iso   31s     Running   True

NAME                                             AGE    PHASE     IP             NODENAME           READY
virtualmachineinstance.kubevirt.io/rl95vm-1      146m   Running   10.244.1.79    worker1.internal   True
virtualmachineinstance.kubevirt.io/rl95vm-2iso   30s    Running   10.244.3.116   worker2.internal   True
[root@master1 kubevirt]#
```


### (4) VMのVNC画面の接続（画面表示）

これでVMが、インストーラISOファイルから起動していますので、画面を表示して、画面操作して対話的にインストールを行うことができます。そのために、以下でやったように、al9hostでVNC画面のプロキシを立ち上げ、windows11のVNCビューアから接続して画面を表示します。

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

図にすると、こうやります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468232/f38291f8-e86e-4f0a-a30d-d962a6903074.png)

- kubectl virt vncコマンドを実行し、al9host上に、rl95vm-2isoのVM画面を表示するための、VNCサーバのプロキシを作る。
- 192.168.11.103:5900で待ち受けるよう指定したので、Windows11上で、192.168.11.103:5900を宛先にVNCビューアで接続し、rl95vm-2isoのVMの画面を表示する。

al9hostでVNC画面のプロキシを立ち上げます。VM名として「rl95vm-2iso」を指定しています。
```bash
[root@al9host kvm_images]# kubectl virt vnc --address=192.168.11.103 --port 5900 --proxy-only rl95vm-2iso
{"port":5900}
{"component":"portforward","level":"info","msg":"connection timeout: 1m0s","pos":"vnc.go:159","timestamp":"2025-02-21T23:42:17.733147Z"}
```

windows11のVNCビューアから、プロキシに対して接続します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468232/46ec5c00-72e9-4905-afc0-bb47d492c4a8.png" alt="Description" width="50%">

これで、RockyLinux 9.5のインストーラ画面が表示でき、インストールできるようになりました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468232/8b098719-9c96-415e-9ef8-3278efb68eb9.png" alt="Description" width="70%">


### (5) ゲストOSのインストール

最初のEnterを押した後、VMの画面が一度消えるのか、一回、VNC接続が切れますが、再度開けば、インストールは最後までできました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468232/ae38dd15-52f6-470b-8938-7f6875b89177.png" alt="Description" width="100%">

インストールが一通り行われ、再起動画面となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468232/d5214e0e-fd0d-4582-91a1-1ec1ec5dd350.png)

ここで、「システムの再起動」を押すと、VMが再起動しますが、また、この画面になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468232/37f1b829-8b84-4bbd-9129-8e44f176c86a.png)

bootOrderが、ISOファイルが1、ルートディスクが2のままのためです。そのため、一度、VMを停止して、bootOrderを変えてVMを起動する、ということをします。

まず、VMを停止します。
```bash
[root@master1 kubevirt]# kubectl virt stop rl95vm-2iso
VM rl95vm-2iso was scheduled to stop
[root@master1 kubevirt]#
```

すぐには停止しませんでした。1分くらいで、VNC画面が消え、確認すると、VmリソースがStoppedになり、Vmiリソースが消えていました。
```bash
[root@master1 kubevirt]# kubectl get vm
NAME          AGE     STATUS    READY
rl95vm-1      5d16h   Running   True
rl95vm-2iso   39m     Stopped   False
[root@master1 kubevirt]#
[root@master1 kubevirt]# kubectl get vmi
NAME       AGE     PHASE     IP            NODENAME           READY
rl95vm-1   3h18m   Running   10.244.1.79   worker1.internal   True
[root@master1 kubevirt]#
```

bootOrderを変えました。rootdiskが1、isodiskが2です。（isodiskは消してもいいですが）
```bash
[root@master1 kubevirt]# vim rl95vm-2iso.yaml
[root@master1 kubevirt]#
```

```yaml:rl95vm-2iso.yaml
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  creationTimestamp: 2018-07-04T15:03:08Z
  generation: 1
  labels:
    kubevirt.io/os: linux
  name: rl95vm-2iso
spec:
  runStrategy: Always
  template:
    metadata:
      creationTimestamp: null
      labels:
        kubevirt.io/domain: rl95vm-2iso
    spec:
      domain:
        cpu:
          cores: 4
        devices:
          disks:
          - disk:
              bus: virtio
            name: rootdisk
            bootOrder: 1
          - cdrom:
              bus: sata
              readonly: true
            name: isodisk
            bootOrder: 2
        machine:
          type: q35
        resources:
          requests:
            memory: 4096M
      volumes:
      - name: rootdisk
        persistentVolumeClaim:
          claimName: rl95vm-2-rootdisk
      - name: isodisk
        persistentVolumeClaim:
          claimName: rocky-iso-9.5
```

適用して、VMを起動します。
```bash
[root@master1 kubevirt]# kubectl apply -f ./rl95vm-2iso.yaml
virtualmachine.kubevirt.io/rl95vm-2iso configured
[root@master1 kubevirt]#
```

なお、kubectl virt startをせずとも、applyでVMが起動します。
```bash
[root@master1 kubevirt]# kubectl get vm
NAME          AGE     STATUS    READY
rl95vm-1      5d16h   Running   True
rl95vm-2iso   45m     Running   True
[root@master1 kubevirt]#
[root@master1 kubevirt]# kubectl get vmi
NAME          AGE     PHASE     IP             NODENAME           READY
rl95vm-1      3h24m   Running   10.244.1.79    worker1.internal   True
rl95vm-2iso   40s     Running   10.244.3.121   worker2.internal   True
[root@master1 kubevirt]#
```

これで、VNC画面のプロキシを立ち上げて、
```bash
[root@al9host kvm_images]# kubectl virt vnc --address=192.168.11.103 --port 5900 --proxy-only rl95vm-2iso
{"port":5900}
{"component":"portforward","level":"info","msg":"connection timeout: 1m0s","pos":"vnc.go:159","timestamp":"2025-02-22T00:39:52.882675Z"}
```

VNCビューアで接続すると、ゲストOSが起動した状態となりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468232/f9631869-a6be-4e46-875d-5662efa79247.png)


# 2. 他のKVM環境で作成したVMの仮想ディスクをインポートしてVM作成

そもそも、KubeVirtって、既存システムのアプリケーションをコンテナ化／マイクロサービス化して、k8sの高可用な環境に移行したいけど、いきなりはハードルが高すぎる、というときに、とりあえず既存システムのVMをk8sクラスタ内に持ってきて、アプリをVM稼働からコンテナ稼働に徐々に移していくハードルを下げる、が、想定される利用ケースの1つ、かと思います。

よって、既存のVMをインポートする、という使い方が、KubeVirtでVMを作るときに、最も使われる可能性の高い方法ではないかと思います。

既存のVMをインポートする方法は、以下にガイドがありますので、これを参考にして、やってみます。

https://kubevirt.io/2019/How-To-Import-VM-into-Kubevirt.html

### (1) KVMでのVM作成

インポート確認のために、k8sクラスタとは関係のない、al9host（AlmaLinux9.5）のKVM環境でVMを作ります。Web UI（cockpit）から操作し、「rl95vm-3cockpit」のVM（RockyLinux9.5）を1つ作りました。

「仮想マシンの作成」から、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468232/9f4f9e46-95e0-4f5b-b810-433d1240eb5a.png)

ウイザードが表示されるので、適当に入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468232/bcedefae-3416-40eb-8ea6-b73897ccd34a.png)

これで、VMが作られます。コンソールの欄を見ると、ISOファイルからOSインストーラが起動していることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468232/6c055e57-75ee-40ae-8eee-6d425f6b8f4c.png)

選択肢を適当に選択して、OSのインストールを行いました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468232/e117bf42-3f76-4aa3-9c47-f9783458816d.png)

ログイン画面が表示されましたので、ゲストOSは構築できた、とし、VMをシャットダウンします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468232/f96f1f9b-ee0a-4545-821c-ea2c6cc34b15.png)

作成したVMが、停止したことを確認します。
```bash
[root@al9host kvm_images]# virsh list --all
 Id   名前                                  状態
----------------------------------------------------------
～
-    rl95vm-3cockpit                       シャットオフ

[root@al9host kvm_images]#
```

### (2) 仮想ディスクをインポートしたPV作成

作成したVMの仮想ディスクは、cockpitの画面にも表示されていましたが、/var/lib/libvirt/images/（デフォルトのストレージプール）の、rl95vm-3cockpit.qcow2というファイルです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468232/6f20b410-770a-46aa-b4f5-a76d06cba493.png)

これを、Masterノード（master1）の/tmpにコピーしました。
```bash
[root@master1 tmp]# ls -lh
total 25G
-rw-------. 1 root root 25G Feb 22 10:08 rl95vm-3cockpit.qcow2
～
[root@master1 tmp]#
```

このimgファイルを、CDIを使ってPVにインポートします。コマンドとしては、インストーラISOファイルをPVにアップロードするのに使った、以下のコマンドをベースにします。

```bash
kubectl virt image-upload pvc rocky-iso-9.5 --storage-class nfs-client --size 15Gi --uploadproxy-url=10.104.14.2 --image-path=/tmp/Rocky-9.5-x86_64-dvd.iso --insecure
```

以下のコマンドを実行して、CDIを利用して仮想ディスクをPVにアップロードし、PVCを作成しました。
```bash
[root@master1 kubevirt]# kubectl virt image-upload pvc rl95vm-3cockpit --storage-class nfs-client --size 30Gi --uploadproxy-url=10.111.218.50 --image-path=/tmp/rl95vm-3cockpit.qcow2 --insecure
PVC default/rl95vm-3cockpit not found
PersistentVolumeClaim default/rl95vm-3cockpit created
Waiting for PVC rl95vm-3cockpit upload pod to be ready...
Pod now ready
Uploading data to https://10.111.218.50

24.00 GiB / 24.00 GiB [----------------------------] 100.00% 69.12 MiB p/s 5m56s

Uploading data completed successfully, waiting for processing to complete, you can hit ctrl-c without interrupting the progress
Processing completed successfully
Uploading /tmp/rl95vm-3cockpit.qcow2 completed successfully
[root@master1 kubevirt]#
```

ベースから変えたのは以下です。
- PVC名
- PVのサイズ
- アップロードするファイル
- CDIのIPアドレス

--uploadproxy-url=は、以下のCDIのServiceのIPアドレスを確認して指定しています（Serviceをtype: LoadBalancerに変えられないかなと試して上手くいかなかったので、作り直してIPが変わっています）。

```bash
[root@master1 kubevirt]# kubectl get service cdi-uploadproxy -n cdi
NAME              TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
cdi-uploadproxy   ClusterIP   10.111.218.50   <none>        443/TCP   50s
[root@master1 kubevirt]#
```

ガイドのコマンド例は「virtctl image-upload --pvc-name=cirros-vm-disk --pvc-size=500Mi --image-path=/home/shegde/images/cirros-0.4.0-x86_64-disk.img --uploadproxy-url=\<url to upload proxy service>」ですが、特に、このコマンドから取り込むべきオプションはありません。


### (3) VM作成

Vmリソースのマニフェストファイルも、流用して作ります。

```bash
[root@master1 kubevirt]# cp rl95vm-2iso.yaml rl95vm-3cockpit.yaml
[root@master1 kubevirt]#
```

以下の個所を変更しました。
```bash
[root@master1 kubevirt]# vim rl95vm-3cockpit.yaml
[root@master1 kubevirt]#
[root@master1 kubevirt]# diff -U1 rl95vm-2iso.yaml rl95vm-3cockpit.yaml
--- rl95vm-2iso.yaml    2025-02-22 09:36:44.145428897 +0900
+++ rl95vm-3cockpit.yaml        2025-02-22 19:58:33.304776052 +0900
@@ -7,3 +7,3 @@
     kubevirt.io/os: linux
-  name: rl95vm-2iso
+  name: rl95vm-3cockpit
 spec:
@@ -14,3 +14,3 @@
       labels:
-        kubevirt.io/domain: rl95vm-2iso
+        kubevirt.io/domain: rl95vm-3cockpit
     spec:
@@ -25,7 +25,2 @@
             bootOrder: 1
-          - cdrom:
-              bus: sata
-              readonly: true
-            name: isodisk
-            bootOrder: 2
         machine:
@@ -38,5 +33,2 @@
         persistentVolumeClaim:
-          claimName: rl95vm-2-rootdisk
-      - name: isodisk
-        persistentVolumeClaim:
-          claimName: rocky-iso-9.5
+          claimName: rl95vm-3cockpit
[root@master1 kubevirt]#
```

内容は以下です。
```yaml:rl95vm-3cockpit.yaml
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  creationTimestamp: 2018-07-04T15:03:08Z
  generation: 1
  labels:
    kubevirt.io/os: linux
  name: rl95vm-3cockpit
spec:
  runStrategy: Always
  template:
    metadata:
      creationTimestamp: null
      labels:
        kubevirt.io/domain: rl95vm-3cockpit
    spec:
      domain:
        cpu:
          cores: 4
        devices:
          disks:
          - disk:
              bus: virtio
            name: rootdisk
            bootOrder: 1
        machine:
          type: q35
        resources:
          requests:
            memory: 4096M
      volumes:
      - name: rootdisk
        persistentVolumeClaim:
          claimName: rl95vm-3cockpit
```

VMを起動します。
```bash
[root@master1 kubevirt]# kubectl apply -f ./rl95vm-3cockpit.yaml
virtualmachine.kubevirt.io/rl95vm-3cockpit created
[root@master1 kubevirt]#
[root@master1 kubevirt]# kubectl get vm,vmi
NAME                                         AGE    STATUS    READY
virtualmachine.kubevirt.io/rl95vm-1          6d2h   Running   True
virtualmachine.kubevirt.io/rl95vm-2iso       11h    Running   True
virtualmachine.kubevirt.io/rl95vm-3cockpit   16s    Running   True

NAME                                                 AGE   PHASE     IP             NODENAME           READY
virtualmachineinstance.kubevirt.io/rl95vm-1          13h   Running   10.244.1.79    worker1.internal   True
virtualmachineinstance.kubevirt.io/rl95vm-2iso       10h   Running   10.244.3.121   worker2.internal   True
virtualmachineinstance.kubevirt.io/rl95vm-3cockpit   16s   Running   10.244.1.82    worker1.internal   True
[root@master1 kubevirt]#
```

rl95vm-3cockpitのVMの画面のVNCサーバのプロキシを立ち上げ、
```bash
[root@al9host sc-nfs]# kubectl virt vnc --address=192.168.11.103 --port 5900 --proxy-only rl95vm-3cockpit
{"port":5900}
{"component":"portforward","level":"info","msg":"connection timeout: 1m0s","pos":"vnc.go:159","timestamp":"2025-02-22T10:59:52.576159Z"}
```

VNCビューアで接続すると、VMの画面が表示されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468232/8415160d-e582-43c2-8a12-a85a2b8a7812.png)


# まとめ

KubeVirtの環境で、ISOファイルからOSインストーラを起動してVMを作成する方法と、KVM環境で作成したVMのimgファイルをインポートしてVMを作成する方法を試しました。以前のマシンイメージから作成したVM含め、以下の3つのVMができました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468232/0cabeca1-a4d7-49dd-9633-c92fdd7bef4e.png)