跳转至

1 热插拔卷

热插拔卷

KubeVirt 支持热插拔卷到正在运行的虚拟机实例(VMI)中。卷必须是块存储卷(block volume)或包含磁盘映像(虚拟机镜像或虚拟机磁盘)的卷。 当热插拔卷的虚拟机被重新启动时,热插拔的卷将被挂载到重新启动的虚拟机上。如果卷被持久化,它们将成为VM规范的一部分,而不会被视为热插拔。 如果它们没有被持久保存,卷将作为热插拔卷重新连接。

热插拔卷使用场景:将故障的虚拟机系统卷热插拔到正常运行的虚拟机中进行修复。

使用热插拔卷的前置条件是先在kubevirt中启用HotplugVolumes特性

# more kubevirt-cr.yaml 
---
apiVersion: kubevirt.io/v1
kind: KubeVirt
metadata:
  name: kubevirt
  namespace: kubevirt
spec:
  certificateRotateStrategy: {}
  configuration:
    developerConfiguration:
      featureGates:
        - HotplugVolumes
...

为虚拟机添加热插拔卷步骤

  1. 要使用热插拔卷,需要先准备一个能被VM使用的卷,可以是DV(DataVolume),此处创建了一个空的DV

    apiVersion: cdi.kubevirt.io/v1beta1
    kind: DataVolume
    metadata:
      name: hotplug-vol01
    spec:
      source:
        blank: {}
      pvc:
        storageClassName: "ceph-hdd-block"
        accessModes:
          - ReadWriteOnce
        resources:
          requests:
            storage: 5Gi
    

    上述yaml示例使用的accessMode模式是ReadWriteOnce,volumeMode是Filesystem,可通过pvc信息进行查看。 如果存储支持,卷热插拔支持块存储卷模式为ReadWriteMany/ReadWriteOnce/ReadOnlyMany的所有组合。

  2. 使用virtctl命令为VM添加热插拔卷,并可以使用--persist来持久化卷

    virtctl addvolume vm-ubuntu01 --volume-name=hotplug-vol01 --persist
    
    注意 这条命令会将卷热插拔到正在运行的vm-ubuntu01中,并将磁盘的序列号设置为卷名称,也就是hotplug-vol01——persist表示永久添加该卷,这意味着该卷已经定义在VM中,即使重新启动VM,卷仍然存在。 即例使用virtctl removevolume 移除热插拔卷,也会在虚拟机下次重启时又插回到虚拟机中,这是因为--persist参数已经将该卷的定义添到了VM中,所以删除时也要加上virtctl removevolume xx --persist同时删除定义。
        spec:
          architecture: amd64
          domain:
            clock:
              timezone: Asia/Shanghai
            cpu:
              cores: 1
            devices:
              ...
              - disk:
                  bus: scsi
                name: hotplug-vol01
                serial: hotplug-vol01
              interfaces:
              - masquerade: {}
                name: default
              rng: {}
              ...
          volumes:
            ...
          - dataVolume:
              hotpluggable: true
              name: hotplug-vol01
            name: hotplug-vol01
    

  3. 进入到虚拟机,查看到多了一块sda的磁盘

    # lsblk
    NAME    MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
    loop0     7:0    0  63.9M  1 loop /snap/core20/2105
    loop1     7:1    0 114.4M  1 loop /snap/lxd/26741
    loop2     7:2    0  40.4M  1 loop /snap/snapd/20671
    sda       8:0    0   4.7G  0 disk 
    vda     252:0    0    10G  0 disk 
    ├─vda1  252:1    0   9.9G  0 part /
    ├─vda14 252:14   0     4M  0 part 
    └─vda15 252:15   0   106M  0 part /boot/efi
    vdb     252:16   0     1M  0 disk 
    
    # ls -l /dev/disk/by-id/
    scsi-0QEMU_QEMU_HARDDISK_hotplug-vol01
    scsi-SQEMU_QEMU_HARDDISK_hotplug-vol01
    

    新增了一个热插拔卷的pod,这个pod的名字可以在相应VMI的status.volumeStatus中查看到

    # kubectl get pods
    NAME                              READY   STATUS    RESTARTS   AGE
    hp-volume-2jbmz                   1/1     Running   0          23m
    virt-launcher-vm-ubuntu01-tmck4   2/2     Running   0          35m
    
    为什么磁盘是sda而不是vdc(这里的vdb是cloudinit挂载的卷)? 因为热插拔卷使用的是virtio-scsi。总线类型是scsi磁盘,而非常规的virtio磁盘。原因在于virtio磁盘存在一个限制,即每个磁盘在虚拟机中都会占用一个PCIe插槽,而PCIe插槽数量最多为32个。 这就意味着可以热插拔磁盘的数量上限较低,特别是考虑到其他硬件设备也需要占用PCIe插槽的情况下。另一个问题是这些插槽需要预先预留。因此,如果无法提前知道热插拔磁盘的确切数量,就无法正确预留所需的插槽数目。

为了解决这个问题,每个虚拟机都配置了一个virtio-scsi控制器,该控制器允许使用scsi总线来挂载热插拔磁盘。 通过这种方式,virtio-scsi控制器能够支持超过400万块磁盘的热插拔操作。而且,根据相关性能测试显示,virtio-scsi与virtio在性能上非常接近,具体可参考github

  1. 可以指定热插拔卷的序列号

    在添加热插拔卷时,是可以加上--serial参数,来指定热插拔卷的序列号

    ## 先移除,再重新添加
    # virtctl removevolume vm-ubuntu01 --volume-name=hotplug-vol01
    Successfully submitted remove volume request to VM vm-ubuntu01 for volume hotplug-vol01
    
    ## 添加热插拔卷,并指定序列号
    # virtctl addvolume vm-ubuntu01 --volume-name=hotplug-vol01 --serial=012345678910
    
    ## 查看
    # ls -l /dev/disk/by-id/
    total 0
    lrwxrwxrwx 1 root root 9 Feb 20 06:04 scsi-0QEMU_QEMU_HARDDISK_012345678910 -> ../../sda
    lrwxrwxrwx 1 root root 9 Feb 20 06:04 scsi-SQEMU_QEMU_HARDDISK_012345678910 -> ../../sda
    

查看热插拔卷状态信息

当执行了添加卷的热插拔操作后(例如,在addvolume示例中),VMI对象的status部分将会包含关于新热插拔卷的详细状态信息。 这意味着通过查看VMI的status.VolumeStatus字段,我们可以清晰地了解到所有磁盘的当前状态,这对于监控、管理和排查虚拟机实例的存储问题非常有用。

# kubectl get vmi vm-ubuntu01 -o yaml
...
status:
  ...
  volumeStatus:
  - name: cloudinitdisk
    size: 1048576
    target: vdb
  - hotplugVolume:
      attachPodName: hp-volume-2jbmz
      attachPodUID: 5f608032-a09e-4f61-b88a-d154eb0d3088
    message: Successfully attach hotplugged volume hotplug-vol01 to VM
    name: hotplug-vol01
    persistentVolumeClaimInfo:
      accessModes:
      - ReadWriteOnce
      capacity:
        storage: 5Gi
      filesystemOverhead: "0.055"
      requests:
        storage: 5Gi
      volumeMode: Filesystem
    phase: Ready
    reason: VolumeReady
    target: sda
  - name: root-disk
    persistentVolumeClaimInfo:
      accessModes:
      - ReadWriteMany
      capacity:
        storage: 10Gi
      filesystemOverhead: "0"
      requests:
        storage: 10Gi
      volumeMode: Block
    target: vda
- vda通常代表包含操作系统(vm-ubuntu01)的磁盘; - vdb则是cloudinit磁盘。 - 每个卷都有一个target,这个target是指向QEMU虚拟机监控程序的唯一标识符,在将磁盘分配给虚拟机时使用,target的值对于每个VM来说都是唯一的。 - attachPodName记录了用于将该卷挂载到运行VMI节点上的Pod名称。如果这个Pod被删除,那么VMI也将停止运行,因为无法确保卷会继续保留在节点上。 - 当卷的phase为ready时,就表示可以被虚拟机使用了。

删除热插拔卷

# virtctl removevolume vm-ubuntu01 --volume-name=hotplug-vol01
Successfully submitted remove volume request to VM vm-ubuntu01 for volume hotplug-vol01

## 永久删除,包括删除了VM中热插拔卷的定义
# virtctl removevolume vm-ubuntu01 --volume-name=hotplug-vol01 --persist

有热插拔卷的VM也支持实时迁移

目前,允许任何带有热插拔卷的VMI进行实时迁移。但是,有一个已知问题,就是目标节点使用了CPU管理器,并且其策略设置为静态(static policy),同时使用的runc版本早于v1.0.0, 那么对于带有热插拔块存储卷(block volumes)的VMI,在迁移过程中可能会失败。