仮想化通信

日本仮想化技術株式会社の公式エンジニアブログ

KubeVirtのボリューム割り当てについて試す

これまで、KubernetesにKuberVirtを導入し、仮想マシンを利用できるようにしました。

tech.virtualtech.jp

前回はKubeVirt VMにKubernetesのサービスを適用しました。

tech.virtualtech.jp

今回はKubeVirtのボリューム割り当てについて試しました。 いろいろな方法でボリュームのアタッチが可能ですが、今回はよく使うemptyDiskとPVCを使う方法を試してみます。

参考にした情報はKubeVirt User-Guide - Disks and Volumesです。

KubeVirt VMにemptyDiskを追加する

KubeVirtのemptyDiskは、KubernetesのemptyDirと同様に機能し、追加のqcow2ディスクが割り当てられてVMと同様に存続します。 ゲストVMの再起動時もボリュームは存続しますが、VMの再作成時は削除されます。

前回KubeVirtの動作確認に使ったYAMLファイルをベースに書いてみます。

# wget https://raw.githubusercontent.com/kubevirt/kubevirt.github.io/master/labs/manifests/vm.yaml

diffで差分を取ってみました。 meta data nameとkubevirt.io/domainの差分はVMにつけられる名前なので置いておいて、 domain deviceのemptydiskという名前のdiskを列挙し、volumesに2GBのemptyDiskを列挙する形で記述します。

$ diff -u vm.yaml vm1.yaml 
--- vm.yaml 2021-04-15 06:53:46.986242330 +0000
+++ vm1.yaml    2021-04-15 06:13:33.122816673 +0000
@@ -1,14 +1,14 @@
 apiVersion: kubevirt.io/v1alpha3
 kind: VirtualMachine
 metadata:
-  name: testvm
+  name: vm1
 spec:
   running: false
   template:
     metadata:
       labels:
         kubevirt.io/size: small
-        kubevirt.io/domain: testvm
+        kubevirt.io/domain: vm1
     spec:
       domain:
         devices:
@@ -19,6 +19,9 @@
             - name: cloudinitdisk
               disk:
                 bus: virtio
+            - name: emptydisk
+              disk:
+                bus: virtio
           interfaces:
           - name: default
             bridge: {}
@@ -35,3 +38,6 @@
         - name: cloudinitdisk
           cloudInitNoCloud:
             userDataBase64: SGkuXG4=
+        - name: emptydisk
+          emptyDisk:
+            capacity: 2Gi

全体は次のようになります。

$ cat vm1.yaml 
apiVersion: kubevirt.io/v1alpha3
kind: VirtualMachine
metadata:
  name: vm1
spec:
  running: false
  template:
    metadata:
      labels:
        kubevirt.io/size: small
        kubevirt.io/domain: vm1
    spec:
      domain:
        devices:
          disks:
            - name: containerdisk
              disk:
                bus: virtio
            - name: cloudinitdisk
              disk:
                bus: virtio
            - name: emptydisk
              disk:
                bus: virtio
          interfaces:
          - name: default
            bridge: {}
        resources:
          requests:
            memory: 64M
      networks:
      - name: default
        pod: {}
      volumes:
        - name: containerdisk
          containerDisk:
            image: quay.io/kubevirt/cirros-container-disk-demo
        - name: cloudinitdisk
          cloudInitNoCloud:
            userDataBase64: SGkuXG4=
        - name: emptydisk
          emptyDisk:
            capacity: 2Gi

それではこのYAMLを使ってVMを作成してみます。

$ kubectl create -f vm1.yaml 
virtualmachine.kubevirt.io/vm1 created
$ virtctl start vm1
VM vm1 was scheduled to start
$ kubectl get vmi
NAME   AGE   PHASE        IP    NODENAME
vm1    10s   Scheduling         
$ kubectl get vmi
NAME   AGE   PHASE     IP               NODENAME
vm1    15s   Running   10.244.224.117   ml110gen9.maas

ログインしてデバイスが割り当てられた確認してみます。 Disk /dev/vdcが追加したデバイスです。

$ virtctl console vm1
Successfully connected to vm1 console. The escape sequence is ^]

login as 'cirros' user. default password: 'gocubsgo'. use 'sudo' for root.
vm1 login: cirros
Password: gocubsgo
$ sudo fdisk -l
...
Disk /dev/vda: 44 MiB, 46137344 bytes, 90112 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 127BB530-4FDD-4855-B653-77C39F7AE9C4

Device     Start   End Sectors Size Type
/dev/vda1  18432 90078   71647  35M Linux filesystem
/dev/vda15  2048 18431   16384   8M EFI System

Partition table entries are not in disk order.

Disk /dev/vdb: 366 KiB, 374784 bytes, 732 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes

Disk /dev/vdc: 2 GiB, 2147483648 bytes, 4194304 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes

あとはこのデバイスをLinuxにおけるストレージの追加の方法でVMにマウントすればストレージ領域として使えます。

KubeVirt VMにPersistent Volume Claim(PVC)を追加する

次にPVCを使う方法です。VMの終了後にVirtualMachineInstanceのディスクを永続化する必要がある場合に使える方法です。 ただ、実際にデータが永続化されるかは、この永続ボリュームを提供しているストレージのポリシー次第になります。

StorageClass の ReclaimPolicyではPVC が削除された時にPVやPVCによって作成された物理的なストレージを保持する(Retain)か削除する(Delete)か選択できます。 次の例はDeleteが設定されているため、PVCを消すと物理的なデータも削除されます。

$ kubectl get sc
NAME         PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
local-path   rancher.io/local-path   Delete          WaitForFirstConsumer   false                  25h

早速、PVCボリュームをVMに割り当てる前に、まずはPVCを作ってみます。 PVCは次のように、KubernetesでPodに対して永続ボリュームを割り当てる際に使うものと同じ書き方でいけるようです。

$ cat testpvc1.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: testpvc1
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: local-path
  resources:
    requests:
      storage: 2Gi

あとは次の差分にあるように作成したPVCのmetadata nameをclaimNameに記述して、persistentVolumeClaimとして定義し、 domain deviceにdiskを追加するだけです。VMの名前は識別できるように一意の名前を定義します。

$ diff -u vm.yaml vm2.yaml 
--- vm.yaml 2021-04-15 06:53:46.986242330 +0000
+++ vm2.yaml    2021-04-15 06:06:16.711290998 +0000
@@ -1,14 +1,14 @@
 apiVersion: kubevirt.io/v1alpha3
 kind: VirtualMachine
 metadata:
-  name: testvm
+  name: vm2
 spec:
   running: false
   template:
     metadata:
       labels:
         kubevirt.io/size: small
-        kubevirt.io/domain: testvm
+        kubevirt.io/domain: vm2
     spec:
       domain:
         devices:
@@ -19,6 +19,9 @@
             - name: cloudinitdisk
               disk:
                 bus: virtio
+            - name: testpvcdisk
+              disk:
+                bus: virtio
           interfaces:
           - name: default
             bridge: {}
@@ -35,3 +38,6 @@
         - name: cloudinitdisk
           cloudInitNoCloud:
             userDataBase64: SGkuXG4=
+        - name: testpvcdisk
+          persistentVolumeClaim:
+            claimName: testpvc1

前のemptyDiskの例と同様、ログインしてデバイスが割り当てられたか確認すると同様にVMにデバイスが追加されているはずです。

$ kubectl create -f vm2.yaml 
virtualmachine.kubevirt.io/vm2 created
$ virtctl start vm2
$ kubectl get vmi -w
NAME   AGE   PHASE     IP               NODENAME
vm2    9s    Scheduling
vm2    14s   Scheduled                  ml110gen9.maas
vm2    18s   Running   10.244.224.118   ml110gen9.maas

$ virtctl console vm2
Successfully connected to vm2 console. The escape sequence is ^]
...
$ sudo fdisk -l
...
Disk /dev/vdc: 2 GiB, 2147483648 bytes, 4194304 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes

同様に、このデバイスをLinuxにおけるストレージの追加の方法でVMにマウントすればストレージ領域として使えます。

KubeVirt VMに追加したボリュームを利用してみる

KubeVirt VMに追加したボリュームにデータを書き込んで、データが永続的に使えることを確認してみましょう。

接続したデバイスを確認します。VMなのでvdをキーにgrepします。

$ fdisk -l |grep vd

パーティションを作成します。

$ sudo fdisk /dev/vdc
Command (m for help): n

パーティションの作成方法についての詳細は省略します。以下を参考にパーティションを作成します。

www.express.nec.co.jp

パーティションとして/dev/vdc1ができたことを確認します。

Command (m for help): p
Disk /dev/vdc: 2 GiB, 2147483648 bytes, 4194304 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x0b9e402c

Device     Boot Start     End Sectors Size Id Type
/dev/vdc1        2048 4194303 4192256   2G 83 Linux

作成したパーティションにmke2fsやmkfsなどを使って、EXT4でボリュームをフォーマットします(フォーマットに使うツールはOSによって異なります)。

$ sudo mkfs.ext4 /dev/vdc1

マウントポイントを作成します。

$ mkdir ~/myvolume

ボリュームをシステムにマウントシアmす。

$ sudo mount /dev/vdc1 ~/myvolume 

root権限でボリュームがマウントされるので、権限を修正します(ユーザー、グループはidコマンドなどで確認してから)。

$ sudo chown cirros.cirros ~/myvolume 

マウントしたらデータの読み書きができるようになります。

$ touch ~/myvolume/hoge
$ echo "hogehuga" >  ~/myvolume/hoge
$ cat ~/myvolume/hoge
hogehuga

ボリュームの再利用を試す

ボリュームのマウントとデータの読み書きが可能であることを確認したら、次にこのボリュームの再利用を試してみます。 一度マウントを解除してみます。

$ cd
$ sudo umount ~/myvolume

一度vm2を削除してVMを再作成してみます。

$ virtctl stop vm2
VM vm2 was scheduled to stop
$ kubectl delete -f vm2.yaml --wait
virtualmachine.kubevirt.io "vm2" deleted

$ kubectl create -f vm2.yaml 
virtualmachine.kubevirt.io/vm2 created
$ virtctl start vm2
VM vm2 was scheduled to start

ログインしてfdiskコマンドを実行すると、ファイルシステムが残っていることが確認できます。

$ virtctl console vm2
...
$ sudo fdisk -l
...
Disk /dev/vdc: 2 GiB, 2147483648 bytes, 4194304 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x0b9e402c

Device     Boot Start     End Sectors Size Id Type
/dev/vdc1        2048 4194303 4192256   2G 83 Linux

マウントポイントを作成してボリュームをマウントしてみましょう。

$ mkdir ~/myvolume
$ sudo mount /dev/vdc1 ~/myvolume
$ sudo chown cirros.cirros ~/myvolume 
$ ls ~/myvolume
hoge
$ cat hoge 
hogehuga

別のVMでボリュームをマウントしても引き続きデータは利用できることが確認できました。