虚拟化简介

在云计算发展中,有两类虚拟化平台:

  • openstack(iaas):关注于资源的利用,虚拟机的计算,网络和存储
  • Kubernetes(pass):关注容器的编排调度,自动化部署,发布管理

Hypervisor(VMM)虚拟机监视器的分类

1、 Type-1,native or bare-metal hypervisors :硬件虚拟化

这些Hypervisor是直接安装并运行在宿主机上的硬件之上的,Hypervisor运行在硬件之上来控制和管理硬件资源。

比如:

  • Microsoft Hyper-V
  • VMware ESXI
  • KVM

2、 Typer-2 or hosted hypervisors :

这些Hypervisor直接作为一种计算机程序运行在宿主机上的操作系统之上的。

  • QEMU
  • VirtualBox
  • VMware Player
  • VMware WorkStation

3、虚拟化主要就是虚拟CPU,MEM(内存),I/Odevices

其中Intel VT-x/AMD-X实现的是COU虚拟化

Intel EPT/AMD-NPT实现MEM的虚拟化

4、Qemu-Kvm的结合:

KVM只能进行CPU,MEM,的虚拟化,QEMU能进行硬件,比如:声卡,USE接口,…的虚拟化,因此通常将QEMU,KVM结合共同虚拟:QEMU-KVM。

Libvirt

是一个虚拟化管理平台的软件集合。它提供统一的API,守护进程libvirtd和一个默认命令行管理工具:virsh。

其实我们也可以使用kvm-qemu命令行的管理工具,但是其参数过多,不便使用。

所以我们通常使用libvirt的解决方案,来对虚拟换进行管理。

libvirt是Hypertvisor的管理方案,就是管理Hypervisor的。

我们通过libvirt命令行工具,来调动Hypervisor,从而使Hypervisor管理虚拟机。

KubeVirt介绍

参考文档:https://github.com/kubevirt/kubevirt

官方文档:https://kubernetes.io/blog/2018/05/22/getting-to-know-kubevirt/

有关卷和磁盘的介绍:http://kubevirt.io/user-guide/virtual_machines/disks_and_volumes/

KubeVirt是Red-Hat开源的,以容器方式运行的虚拟机项目。是基于Kubernetes运行的,具体的来说是基于Kubernetes的CRD(自定义资源)增加虚拟机的运行和管理相关的资源。特别是VM,VMI资源类型。也是说我们通过CRD进行增加关于虚拟机的资源类型,然后通过写YAML的形式来创建虚拟机等一系列的操作。

主要有两种资源类型:VM,VMI

  • VM资源: 为群集内的 VirtualMachineInstance 提供管理功能,例如开机/关机/重启虚拟机,确保虚拟机实例的启动状态,与虚拟机实例是 1:1 的关系,类似与 spec.replica 为 1 的 StatefulSet。
  • VMI( VirtualMachineInstance )资源: 类似于 kubernetes Pod,是管理虚拟机的最小资源。一个 VirtualMachineInstance 对象即表示一台正在运行的虚拟机实例,包含一个虚拟机所需要的各种配置。

通过以上资源,可以在Kubernetes上管理虚拟机。

Kubevirt的架构

先看架构图:

kubesphere gpu虚拟化 kubevirt 性能_kubesphere gpu虚拟化

KubeVirt以CRD的形式将VM管理接口接入到Kubernetes中,通过一个Pod去使用libvirt管理VM一样,实现Pod于VM的一一对应,就是说一个Pod中可以即可以运行VM同时也可以运行容器。做到如同容器般去管理虚拟机,并且做到与容器一样的资源管理,调度规划。

不同的是,普通Pod就叫做Pod,而包含VM的Pod就做virt-launcher Pod。

下面来介绍Master节点的组件:

  • virt-api:KubeVirt是以CRD形式去管理virt-launcher Pod。virt-api就是所有管理虚拟机操作的入口,它只接收指令,比如:CRD更新,删除,增加,以及对虚拟机的start,stop,delete,console等等
  • virt-controller: 管理和监控 VMI 对象及其关联的 Pod,对其状态进行更新。 virt-controller会根据你编写的VM资源清单 ,创建对应的VMI,然后在创建对应的virt-launcher Pod。并且和kuberneters的api-server通信,来监控和维护VMI资源的创建删除等。

下面来介绍node节点的组件:

  • virt-handler:这个组件是以Pod的方式启动的,并且注意它是个DaemonSet的Pod,也就是守护进程是的Pod,那这就意味着,他需要守护进程的方式部署在每一个Node上,负责监控和操作节点上每个虚拟机实例。一旦检测到状态虚拟机实例变化,会进行响应并且确保响应的操作能够达到VMI CRD中你期望的状态。
  • virt-launcher:每一个virt-launcher Pod对应这一个VMI。Kubernetes只负责virt-launcher Pod的运行状态,不会关心VMI创建的情况,所以virt-handler会根据创建资源清单的参数配置,去通知virt-launcher去使用本地的libvirtd来管理虚拟机的生命周期。 随着Pod的生命周期结束,virt-lanuncher也会去通知VMI去执行终止操作。
  • virtctl:virtctl是kubevirt自带的命令行工具,和kubectl的性质一样,但不同于kubectl的是,virtctl和virt-api进行交互,从而进行虚拟机的删除,创建,更新等操作。

VM(虚拟机)的启动流程

参考文档:https://github.com/kubevirt/kubevirt

kubesphere gpu虚拟化 kubevirt 性能_kubernetes_02

虚拟机相关资源简介

  • virtualmachines(VM):为群集内的VirtualMachineInstance提供管理功能,例如开机/关机/重启虚拟机,确保虚拟机实例的启动状态。
  • virtualmachineinstances (VMI) :类似于Kubernetes Pod,是管理虚拟机的最小资源。一个VirtualMachineInstance对象即表示台正在运行的虚拟机实例, 包含一个虚拟机所需要的各种配置。
  • VirtualMachineInstanceReplicaSet:类似Kubernetes的ReplicaSet, 可以启动指定数量的VirtualMachineInstance,并且保证指定数量的VirtualMachineInstance运行,可以配置HPA。
  • VirtualMachineInstanceMigrations:提供虚拟机迁移的能力。

虚拟机镜像,磁盘,卷

有关卷和磁盘的介绍:http://kubevirt.io/user-guide/virtual_machines/disks_and_volumes/

创建虚拟机镜像肯定是必须的,那既然需要镜像,就需要由存储来存放镜像。

在KubeVirt中有个子项目:CDI。

CDI是Kubernetes持久化存储管理的插件,CDI项目提供了用于使PVC作为KubeVirt VM磁盘的功能。

在spec.volumes下可以指定多种类型的卷:

  • cloudInitNoCloud: Cloud-init相关的配置, 用于修改或者初始化虚拟机中的配置信息
  • containerDisk:指定一个包含 qcow2或raw格式的docker镜像,重启vm数据会丢失
  • dataVolume:动态创建一个PVC,并用指定的磁盘映像填充该PVC,重启vm数据不会丢失
  • emptyDisk:从宿主机上分配固定容量的空间,映射到vm中的一块磁盘,emptyDisk 的生命周期与vm等同,重启mv数据会丢失
  • ephemeral:在虚机启动时创建一一个临时卷,虚机关闭后自动销毁,临时卷在不需要磁盘持久性的任何情况下都很有用。
  • hostDisk:在宿主机上创建一一个img镜像文件,挂给虚拟机使用。重启vm数据不会丢失。
  • persistentVolumeClaim:指定一个PVC创建一个块设备。 重启vm数据不会丢失。

KubeVirt网络

前置环境

需要Kubernetes平台

可采用KubeKey部署

安装(v0.48.1)

官网地址:https://github.com/kubevirt/kubevirt

准备工作

1、先安装libvirt和qemu软件包

[root@master ~]# yum install -y qemu-kvm libvirt virt-install bridge-utils

2、查看节点是否支持kvm硬件虚拟化

[root@master ~]# virt-host-validate qemu
#以下就是虚拟化失败的情况
QEMU: Checking for hardware virtualization                                 : FAIL (Only emulated CPUs are available, performance will be significantly limited)
  QEMU: Checking if device /dev/vhost-net exists                             : PASS
  QEMU: Checking if device /dev/net/tun exists                               : PASS
  QEMU: Checking for cgroup 'memory' controller support                      : PASS
  QEMU: Checking for cgroup 'memory' controller mount-point                  : PASS
  QEMU: Checking for cgroup 'cpu' controller support                         : PASS
  QEMU: Checking for cgroup 'cpu' controller mount-point                     : PASS
  QEMU: Checking for cgroup 'cpuacct' controller support                     : PASS
  QEMU: Checking for cgroup 'cpuacct' controller mount-point                 : PASS
  QEMU: Checking for cgroup 'cpuset' controller support                      : PASS
  QEMU: Checking for cgroup 'cpuset' controller mount-point                  : PASS
  QEMU: Checking for cgroup 'devices' controller support                     : PASS
  QEMU: Checking for cgroup 'devices' controller mount-point                 : PASS
  QEMU: Checking for cgroup 'blkio' controller support                       : PASS
  QEMU: Checking for cgroup 'blkio' controller mount-point                   : PASS
WARN (Unknown if this platform has IOMMU support)

3、如果不支持,则需要让kubevirt使用软件模拟虚拟化的配置:

kubectl create namespace kubevirt
kubectl create configmap -n kubevirt kubevirt-config \
 --from-literal debug.useEmulation=true

安装KubeVirt

部署0.48.1版本

export VERSION=v0.48.1
kubectl apply -f https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/kubevirt-operator.yaml
kubectl apply -f https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/kubevirt-cr.yaml

检测结果:

[root@master ~]# kubectl get pods -n kubevirt
NAME                               READY   STATUS    RESTARTS   AGE
virt-api-67699974c9-46h4p          1/1     Running   0          11m
virt-api-67699974c9-rxvzn          1/1     Running   0          11m
virt-controller-575dbb5b66-q2kps   1/1     Running   0          9m24s
virt-controller-575dbb5b66-xhv89   1/1     Running   0          9m24s
virt-handler-f9jlk                 1/1     Running   0          9m24s
virt-handler-gtstv                 1/1     Running   0          9m24s
virt-operator-574d595ffb-tlbcs     1/1     Running   0          12m
virt-operator-574d595ffb-w9s88     1/1     Running   0          12m

部署CDI(v1.47.1)

Containerized Data Importer(CDI)项目提供了用于使 PVC 作为 KubeVirt VM 磁盘的功能。建议同时部署 CDI:

[root@master ~]# export VERSION=$(curl -s https://github.com/kubevirt/containerized-data-importer/releases/latest | grep -o "v[0-9]\.[0-9]*\.[0-9]*")
[root@controller ~]# kubectl create -f https://github.com/kubevirt/containerized-data-importer/releases/download/$VERSION/cdi-operator.yaml
[root@controller ~]# kubectl create -f https://github.com/kubevirt/containerized-data-importer/releases/download/$VERSION/cdi-cr.yaml

检测结果:

[root@master ~]# kubectl get pods -n cdi
NAME                               READY   STATUS    RESTARTS   AGE
cdi-apiserver-67944db5c9-6bmpz     1/1     Running   0          2m53s
cdi-deployment-6fcc76f596-pfjqq    1/1     Running   0          2m45s
cdi-operator-5f57676b77-vq6rj      1/1     Running   0          5m39s
cdi-uploadproxy-66bd867c6f-5fl2r   1/1     Running   0          2m41s

安装virtctl客户端工具

KubeVirt提供了一个命令行工具:virtctl,我们直接下载使用。

[root@master ~]# wget https://github.com/kubevirt/kubevirt/releases/download/v0.48.1/virtctl-v0.48.1-linux-amd64
[root@master ~]# mv virtctl-v0.48.1-linux-amd64 /usr/local/bin/virtctl
[root@master ~]# chmod +x /usr/local/bin/virtctl 
[root@master ~]# virtctl -h     #help帮助命令

下载官方的vm.yaml文件(来生成官方的虚拟机)

1、下载官方VM.yaml文件。vm.yaml文件声明了,一个虚拟机所需要的所有配置,比如:网络,磁盘,镜像,…

[root@master ~]# wget https://kubevirt.io/labs/manifests/vm.yaml --no-check-certificate
#文件内容如下:
apiVersion: kubevirt.io/v1
kind: VirtualMachine           #vm资源
metadata:
  name: testvm
spec:
  running: false            #当此字段为"Running",开始创建vmi资源
  template:
    metadata:
      labels:
        kubevirt.io/size: small
        kubevirt.io/domain: testvm
    spec:
      domain:
        devices:            #代表可以添加设备,比如:磁盘,网络...
          disks:            #硬盘设置。表示创建那种硬盘,这里表示有两块硬盘
            - name: containerdisk
              disk:              #将卷作为磁盘连接到vmi(虚拟机实例)
                bus: virtio      #表示要模拟的磁盘设备的类型,比如有:sata,scsi,virtio
            - name: cloudinitdisk
              disk:
                bus: virtio
          interfaces:            #选择定义的网络,下面的networks字段,就定义了一个"default"网络,这里就表示选择那个"default"网络
          - name: default
            masquerade: {}       #开启masquerade,这个表示使用网络地址转换(NAT)来通过Linux网桥将虚拟机连接至Pod网络后端。
        resources:
          requests:
            memory: 64M
      networks:          #网络的配置
      - name: default              #定义一个网络叫做"default",这里表示使用Kubernetes默认的CNI,也就是使用默认的网络
        pod: {}
      volumes:
        - name: containerdisk
          containerDisk:
            image: quay.io/kubevirt/cirros-container-disk-demo      #使用此镜像创建个虚拟机。
        - name: cloudinitdisk
          cloudInitNoCloud:
            userDataBase64: SGkuXG4=

2、使用此模板文件创建虚拟机:

[root@master ~]# kubectl apply -f vm.yaml 
virtualmachine.kubevirt.io/testvm created
#查看vm的状态,在上面的概念中也将到了,vm中的"running"字段默认是"false"的,我们需要用virtctl命令行去启动此vm,然后virt-controller就会把vm中的"running"字段由"false"改为"true",之后在创建vmi资源,创建虚拟机等操作。
[root@master ~]# kubectl get vm
NAME     AGE   STATUS    READY
testvm   5s    Stopped   False

3、启动虚拟机,尽量开启虚拟化

#启动testvm这个虚拟机
[root@master ~]# virtctl start testvm
VM testvm was scheduled to start
#查看Pod,这个Pod里面就存放一个虚拟机
[root@master ~]# kubectl get pods
virt-launcher-testvm-c5gfc   2/2     Running   0          25s
#在查看vmi资源
[root@master ~]# kubectl get vmi
NAME     AGE   PHASE     IP            NODENAME   READY
testvm   59s   Running   10.244.1.26   node1      True

4、进入虚拟机控制台

virtctl console testvm
#Ctrl+]退出此虚拟机
Successfully connected to testvm console. The escape sequence is ^]

OK
GROWROOT: NOCHANGE: partition 1 is size 71647. it cannot be grown
/dev/root resized successfully [took 0.17s]
/run/cirros/datasource/data/user-data was not '#!' or executable
=== system information ===
Platform: KubeVirt None/RHEL-AV
Container: none
Arch: x86_64
CPU(s): 1 @ 2199.541 MHz
Cores/Sockets/Threads: 1/1/1
Virt-type: AMD-V
RAM Size: 43MB
Disks:
NAME  MAJ:MIN     SIZE LABEL         MOUNTPOINT
vda   253:0   46137344               
vda1  253:1   36683264 cirros-rootfs /
vda15 253:15   8388608               
vdb   253:16   1048576 cidata        
=== sshd host keys ===
-----BEGIN SSH HOST KEY KEYS-----
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCh4nXQS4nzbGRBMHw92aSBrSG1OPxbfp99vC2NHrYLtA6rMbi8sZ7H7Ys7A4RVC0vH1dcbVN/NFXRBfANXcD0rmr17HHX6nhXvFzWGBEEZEY2OYWErjxGAtAI/m+6OwOoYwYkHVIZTyAMejcN/JgW+yYqPAc8Md7zAfZ5c9xTqVnRASFxTpWwxGaf5p1pWq1RH2QHzKvEcbSqt0OIRyneqo25xn7we3rh2KcjCj16f4E0iL7qkum/ftv6bzgZ9mPKgRb2ja6W1LEek1GlHIwmvUuflL8Y6a4sk0RFTvyEUnNq8SdNBTqTUGZ9O8SSQx1bj733vr2WGLljDZkFB6Ver root@testvm
ssh-dss AAAAB3NzaC1kc3MAAACBAIlxV2kDXdGe3qapWXZ2qKoI3KCK9c6w80zSgfr0loLFwUaCWZax6NedlJDIXzoigjcgT0YWQT40aLxUrYQXlBUISnz8CkfKjfByzQK1WMP4OpZ0xjCWuuOdp0kqtGr76J8teq14RTRHdApUey0JHQCEkEU05AUqj3V3nmY8HcoRAAAAFQCmziUZA8vzBKHzc19KOpxnCsndUwAAAIBCPympZPf8EuY7miagP+vt6qFSW2Yv1X/xP0vTqd89BYCYmgoGHYKlU3B7gCq7EEF5kphzZ0CagjAPiHt50X3aL9vviqM9gJx721Dz+y5xvnicRs0OKfYMSDo7gg5bcsKM/BtKTR80gRq51IBWm+kO5NcIcCK75HIQX5cu5UK2DwAAAIBZPygbYSM7fetwf0qEvXInhbsvDtjFGXsHAh2M3n6DkbmDgTjwcnDBb2WPzkMzmnGz/mCsClMR/mZRjViZ7A5i3OKk2tpqBQbfP0drKPg4WaMuvtpkZ5drr8y6PHWlweekBmcuiK0mHlgRFCl0aoJ0KWXU0AH3llDxdZlVwl1U1Q== root@testvm
-----END SSH HOST KEY KEYS-----
=== network info ===
if-info: lo,up,127.0.0.1,8,,
if-info: eth0,up,10.0.2.2,24,fe80::5054:ff:feae:bce3/64,
ip-route:default via 10.0.2.1 dev eth0 
ip-route:10.0.2.0/24 dev eth0  src 10.0.2.2 
ip-route6:fe80::/64 dev eth0  metric 256 
ip-route6:unreachable default dev lo  metric -1  error -101
ip-route6:ff00::/8 dev eth0  metric 256 
ip-route6:unreachable default dev lo  metric -1  error -101
=== datasource: nocloud local ===
instance-id: testvm.default
name: N/A
availability-zone: N/A
local-hostname: testvm
launch-index: N/A
=== cirros: current=0.4.0 uptime=18.75 ===
  ____               ____  ____
 / __/ __ ____ ____ / __ \/ __/
/ /__ / // __// __// /_/ /\ \ 
\___//_//_/  /_/   \____/___/ 
   http://cirros-cloud.net


login as 'cirros' user. default password: 'gocubsgo'. use 'sudo' for root.
#根据上面提供的用户/密码进行登录
testvm login:

Ctrl+]退出此虚拟机

5、相关命令

virtctl stop vm
virtctl start vm
virtctl restart vm
virtctl console vm

创建Win10操作系统的虚拟机

1、下载Win10镜像

下载地址:https://tb.rg-adguard.net/public.php

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D2Vd7Buo-1685428751730)(C:\Users\郑波\AppData\Roaming\Typora\typora-user-images\1650169936524.png)]

下载到Win在传至Linux,或者直接在Linux中:

wget https://tb.rg-adguard.net/dl.php?go=165b1d29

创建默认存储(StorageClass)

说明:由于等会我们需要上传镜像,需要使用PV,PVC,PVC它会给我们自动创建,但是PV,需要我们自己创建。

我们知道创建PV,PVC有两种方法,一个是静态,一个是动态。

静态就是:手动编写PV,PVC资源清单,然后在将他们进行绑定。

动态就是:我们创建一个存储类:StorageClass,然后我们只需要编写PVC的资源清单即可,它会给我们自动创建PV,然后和PVC进行绑定。

我们这里采用动态的方式:

1、部署NFS服务

# 在每个机器。
yum install -y nfs-utils


# 在master 执行以下命令 
echo "/nfs/data/ *(insecure,rw,sync,no_root_squash)" > /etc/exports


# 执行以下命令,启动 nfs 服务;创建共享目录
mkdir -p /nfs/data


# 在master执行
systemctl enable rpcbind
systemctl enable nfs-server
systemctl start rpcbind
systemctl start nfs-server

# 使配置生效
exportfs -r


#检查配置是否生效
exportfs

2、配置存储类

文件如下:

只需要修改两部分:就是把NFS服务端的IP修改为自己的即可。

## 创建了一个存储类
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-storage
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:
  archiveOnDelete: "true"  ## 删除pv的时候,pv的内容是否要备份

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/nfs-subdir-external-provisioner:v4.0.2
          # resources:
          #    limits:
          #      cpu: 10m
          #    requests:
          #      cpu: 10m
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: k8s-sigs.io/nfs-subdir-external-provisioner
            - name: NFS_SERVER
              value: 172.31.0.4 ## 指定自己nfs服务器地址
            - name: NFS_PATH  
              value: /nfs/data  ## nfs服务器共享的目录
      volumes:
        - name: nfs-client-root
          nfs:
            server: 172.31.0.4
            path: /nfs/data
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
rules:
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: default
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: default
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io

3、应用,并查看StorageClass(sc)

kubectl apply -f sc.yaml 
[root@master ~]# kubectl get sc
NAME                    PROVISIONER                                   RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
nfs-storage (default)   k8s-sigs.io/nfs-subdir-external-provisioner   Delete          Immediate           false                  11m

上传镜像

KubeVirt 可以使用 PVC 作为后端磁盘,使用 filesystem 类型的 PVC 时,默认使用的时 /disk.img 这个镜像,用户可以将镜像上传到 PVC,在创建 VMI 时使用此 PVC。使用这种方式需要注意下面几点:

一个 PVC 只允许存在一个镜像,只允许一个 VMI 使用,要创建多个 VMI,需要上传多次

/disk.img 的格式必须是 RAW 格式

CDI 提供了使用使用 PVC 作为虚拟机磁盘的方案,在虚拟机启动前通过下面方式填充 PVC:

通过 URL 导入虚拟机镜像到 PVC,URL 可以是 http 链接,s3 链接

Clone 一个已经存在的 PVC

通过 container registry 导入虚拟机磁盘到 PVC,需要结合 ContainerDisk 使用

通过客户端上传本地镜像到 PVC

通过命令行 virtctl,结合 CDI 项目,可以上传本地镜像到 PVC 上,支持的镜像格式有:

.img

.qcow2

.iso

压缩为 .tar,.gz,.xz 格式的上述镜像

我们的目标是安装 Windows 10 虚拟机,所以需要将上面下载好的 Windows 镜像上传到 PVC:

如下操作:

virtctl image-upload  \
 --image-path='Win10_20H2_Chinese(Simplified)_x64.iso' \
 --pvc-name=iso-win10 \
 --pvc-size=7G \
 --uploadproxy-url=https://10.96.237.3 \
 --insecure --wait-secs=240


#参数讲解:
--image-path='Win10_20H2_Chinese(Simplified)_x64.iso'    #指定Win镜像的路径,我们是在/root目录下,因此就这个路径即可。
--pvc-name=iso-win10         #指定PVC的名字
--pvc-size=7G                #指定PVC的大小,根据操作系统镜像大小来设定,一般略大一个G就行。
--uploadproxy-url=https://10.96.237.3         #cdi-uploadproxy 的 Service IP,可以通过命令 kubectl -n cdi get svc -l cdi.kubevirt.io=cdi-uploadproxy 来查看。

增加 hostDisk 支持

Kubevirt 默认没有开启对 hostDisk 的支持,需要手动开启,这里我们直接editKubeVirt1的ConfigMap

[root@master ~]# kubectl get cm -n kubevirt
NAME                              DATA   AGE
kube-root-ca.crt                  1      3h47m
kubevirt-ca                       1      3h40m
kubevirt-config                   2      3h47m          #edit此ConfigMap
kubevirt-install-strategy-r6gd8   1      3h40m

[root@master ~]# kubectl edit cm kubevirt-config -n kubevirt
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
  debug.useEmulation: "true"
  feature-gates: HostDisk              #添加这一行即可
kind: ConfigMap
metadata:
  creationTimestamp: "2022-04-17T01:19:05Z"
  name: kubevirt-config
  namespace: kubevirt
  resourceVersion: "46074"
  uid: 56ff5d51-1ce5-4c0e-bef2-7c2d24525306

创建虚拟机

1、同样我们需要自己写个vm.yaml文件

apiVersion: kubevirt.io/v1alpha3
kind: VirtualMachine
metadata:
  name: win10
spec:
  running: false
  template:
    metadata:
      labels:
        kubevirt.io/domain: win10
    spec:
      domain:
        cpu:
          cores: 4
        devices:
          disks:
          - bootOrder: 1
            cdrom:
              bus: sata
            name: cdromiso
          - disk:
              bus: virtio
            name: harddrive
          - cdrom:
              bus: sata
            name: virtiocontainerdisk
          interfaces:
          - masquerade: {}
            model: e1000
            name: default
        machine:
          type: q35
        resources:
          requests:
            memory: 16G
      networks:
      - name: default
        pod: {}
      volumes:
      - name: cdromiso
        persistentVolumeClaim:
          claimName: iso-win10
      - name: harddrive
        hostDisk:
          capacity: 50Gi
          path: /data/disk.img
          type: DiskOrCreate
      - containerDisk:
          image: kubevirt/virtio-container-disk
        name: virtiocontainerdisk

这里用到了 3 个 Volume:

cdromiso : 提供操作系统安装镜像,即上文上传镜像后生成的 PVC iso-win10。

harddrive : 虚拟机使用的磁盘,即操作系统就会安装在该磁盘上。这里选择 hostDisk 直接挂载到宿主机以提升性能,如果使用分布式存储则体验非常不好。

containerDisk : 由于 Windows 默认无法识别 raw 格式的磁盘,所以需要安装 virtio 驱动。containerDisk 可以将打包好 virtio 驱动的容器镜像挂载到虚拟机中。

关于网络部分,spec.template.spec.networks 定义了一个网络叫 default,这里表示使用 Kubernetes 默认的 CNI。spec.template.spec.domain.devices.interfaces 选择定义的网络 default,并开启 masquerade,以使用网络地址转换 (NAT) 来通过 Linux 网桥将虚拟机连接至 Pod 网络后端。

2、 使用模板文件创建虚拟机:

kubectl apply -f win10.yaml 
virtctl start win10
#查看VM,VMI,Pod的状态
[root@master ~]# kubectl get vm
NAME     AGE     STATUS    READY
testvm   3h30m   Stopped   False
win10    4m7s    Running   True

[root@master ~]# kubectl get vmi
NAME    AGE    PHASE     IP            NODENAME   READY
win10   4m7s   Running   10.244.2.12   node1      True

[root@master ~]# kubectl get pods
virt-launcher-win10-hwhcw                 2/2     Running   0          4m16s