(k8s-king-king)(kubevirt运维案例)容器云原生虚拟化
1.KubeVirt介绍
(1)背景介绍
随着这些年容器技术和云原生技术的发展,Kubernetes在2017年容器编排大战中击败Docker Swarm和Mesos之后,进一步发展壮大。到现在为止,基本上所有公有云的容器服务(xKS服务)和私有云的容器云PaaS平台都是用的Kubernetes,Kubernetes已成为事实上的容器编排标准。从这个意义上讲,可以称Kubernetes为云原生计算的操作系统。
值得注意的是,在企业的数据中心或云平台上,大部分应用都还没有进行容器化,仍旧以传统二进制代码的方式运行在虚拟机上面。对于某些客户来讲,不希望在运营一个以管理传统虚拟机为主的IaaS平台或虚拟化平台(比如OpenStack或者VMWare)之外,同时运营另外一个基于Kubernetes的容器平台。因此,一个自然而然的想法就形成了。既然Kubernetes在容器编排领域如此成功,能不能使用Kubernetes来管一切虚拟化运行时,包含裸金属、VM、kata、容器等,实现一套调度、多种运行时,用户按需选择。
基于以上想法,业界在从OpenStack向Kubernetes转型的过程中涌现了一部分比较好的项目,例如KubeVirt、Virtlet、Rancher、VM等,但是社区活跃度最高、公认设计最好的还是KubeVirt。
KubeVirt总体架构图如图1所示:
、
图1
(2)容器里运行虚拟机
容器里面运行的应用程序本质上是一个进程。容器技术通过采用Linux的命名空间(namespace)和控制组(cgroup)等内核技术实现进程隔离,并且可以对隔离的进程进行资源分配控制。既然容器里面真正运行的是进程,那么,如何能让在容器里面跑虚拟机呢?
在采用KVM做Hypervisor的Linux机器上,从Hypervisor的角度来看,虚拟机就是一个KVM进程。
本质上来讲,KubeVirt的虚拟化功能,除了没有直接使用virsh创建虚拟机,本质上也是采用libvirt、QEMU和KVM等同样的虚拟化核心技术来实现的,如图2所示:
图2
(3)KubeVirt的实现方式
KubeVirt充分采用了Kubernetes方式扩展了Kubernetes,主要在以下3个方面进行了扩展:
- VM相关的自定义资源CRD被增加到Kubernetes API中间。新增的CRD包括VirtualMachine、VirtualMachineInstance、VirtualMachineInstanceMigration、DataVolume等。
- 新建的虚拟机控制器,用于实现上述相关CRD在增、删、改时应该执行的相关操作。
- 每个节点上面的守护进程virt-handler,可以认为是KubeVirt的Kubelet。Virt-handler和Kubelet一起,用于创建虚拟机实例(VMI),以达到CRD中期望的状态。
KubeVirt的架构图如图3所示:
图3
Kubevirt 主要实现了下面几种资源,以实现对虚拟机的管理:
- VirtualMachineInstance(VMI):类似于Kubernetes Pod,是管理虚拟机的最小资源。一个VMI对象即表示一台正在运行的虚拟机实例,包含一个虚拟机所需要的各种配置。
- VirtualMachine(VM):为群集内的VMI提供管理功能,例如开机、关机、重启虚拟机,确保虚拟机实例的启动状态,与虚拟机实例是1:1的关系,类似与spec.replica为1的StatefulSet。
- VirtualMachineInstanceReplicaSet(VMIRS):类似于ReplicaSet,可以启动指定数量的VMI,并且保证指定数量的VMI运行,可以配置HPA。
2. 部署KubeVirt环境
检查CPU是否支持虚拟化:
[root@master ~]# egrep -c 'vmx|svm' /proc/cpuinfo
8
只要输出结果不为0则表示支持虚拟化。VMX和SVM都是虚拟化技术,Intel平台称为VMX–virtual machine extension;AMD平台称为SVM–Secure Virtual Machine extension。
下载软件包并导入镜像:
[root@master ~]# curl -O http://mirrors.douxuedu.com/competition/KubeVirt-v1.0.tar.gz
[root@master ~]# tar -xf KubeVirt-v1.0.tar.gz
[root@master ~]# docker load -i KubeVirt/images/images.tar
安装KubeVirt环境:
[root@master ~]# kubectl apply -f KubeVirt/manifests/kubevirt-operator.yaml
[root@master ~]# kubectl apply -f KubeVirt/manifests/kubevirt-cr.yaml
查看KubeVirt Pod:
[root@master ~]# kubectl -n kubevirt get pods
NAME READY STATUS RESTARTS AGE
virt-api-5b5479dbdc-n6rx2 1/1 Running 0 47s
virt-controller-66b5c9fbfc-4nj4q 1/1 Running 0 22s
virt-controller-66b5c9fbfc-n7jp5 1/1 Running 0 22s
virt-handler-9rf87 1/1 Running 0 22s
virt-operator-dd7ffb6fd-5prh9 1/1 Running 0 86s
virt-operator-dd7ffb6fd-xsjzg 1/1 Running 0 86s
安装KubeVirt命令行工具:
[root@master ~]# cp KubeVirt/tools/virtctl-v0.56.0-linux-amd64 /usr/bin/virtctl
[root@master ~]# virtctl version
Client Version: version.Info{GitVersion:"v0.56.0", GitCommit:"b1dbd1bccc882282690331ca84e97ddf83555611", GitTreeState:"clean", BuildDate:"2022-08-18T20:19:27Z", GoVersion:"go1.17.8", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{GitVersion:"v0.56.0", GitCommit:"b1dbd1bccc882282690331ca84e97ddf83555611", GitTreeState:"clean", BuildDate:"2022-08-18T20:19:27Z", GoVersion:"go1.17.8", Compiler:"gc", Platform:"linux/amd64"}
3. 虚拟机生命周期
KubeVirt虚拟机生命周期管理主要分为以下几种状态:
- 创建:创建VM对象,并同步创建DataVolume/PVC,通过调度、IP分配后生成VMI以及管理VM的Launcher Pod。
- 运行:运行状态下的VM可以进行控制台管理、快照备份/恢复、热迁移、磁盘热挂载/热删除等操作,此外还可以进行重启、下电操作,提高VM安全的同时解决业务存储空间需求和主机异常Hung等问题。
- 关机:关机状态下的VM可以进行快照备份/恢复、冷迁移、CPU/MEM规格变更、重命名以及磁盘挂载等操作,同时可通过重新启动进入运行状态,也可删除进行资源回收。
- 删除:对VM资源进行回收,但VM所属的磁盘数据仍将保留、具备恢复条件。
KubeVirt生命周期管理如图4所示:
图4
(1)创建
VM资源清单文件模板如下:
apiVersion: kubevirt.io/v1 # API版本号
kind: VirtualMachine # 对象类型,VM
metadata: # 元数据
creationTimestamp: null
labels: # 自定义标签的名称和值
kubevirt-vm: vm-${NAME}
kubevirt.io/os: fedora27
name: ${NAME} # VM名称
spec:
running: false # 决定是否启动VMI
template:
metadata:
creationTimestamp: null
labels:
kubevirt-vm: vm-${NAME}
kubevirt.io/os: fedora27
spec:
domain:
cpu:
cores: ${{CPU_CORES}} # vCPUS数量
devices:
disks:
- disk: # 提供用户数据user-data和元数据meta-data
bus: virtio
name: cloudinitdisk
- disk: # 系统盘(必选)
bus: virtio
name: containerdisk
interfaces: # 网络接口
- masquerade: {}
model: virtio
name: default
networkInterfaceMultiqueue: true
rng: {}
resources: # 资源请求
requests:
memory: ${MEMORY}
networks:
- name: default
pod: {} # 使用Kubernetes默认Pod网络
terminationGracePeriodSeconds: 0
volumes:
- cloudInitNoCloud: # 初始化操作
userData: |-
#cloud-config
password: fedora
chpasswd: { expire: False }
name: cloudinitdisk
- containerDisk:
image: ${IMAGE} # 系统镜像
name: containerdisk
编写VM资源清单文件:
[root@master ~]# vi vm.yaml
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
labels:
kubevirt.io/vm: vm-fedora
name: vm-fedora
spec:
running: false
template:
metadata:
labels:
kubevirt.io/vm: vm-fedora
spec:
domain:
resources:
requests:
memory: 1Gi
devices:
disks:
- name: containerdisk
disk:
bus: virtio
volumes:
- name: containerdisk
containerDisk:
image: kubevirt/fedora-cloud:v1.0
imagePullPolicy: IfNotPresent
创建VM:
[root@master ~]# kubectl apply -f vm.yaml
查看VM:
[root@master ~]# kubectl get vm
NAME AGE STATUS READY
vm-fedora 20s Stopped False
因为.spec.running字段的值设置的false,所有虚拟机的状态是Stopped,由于VM还没启动,所以目前还没有VMI资源,只有VM资源。
(2)启动
启动VM:
[root@master ~]# virtctl start vm-fedora
VM vm-fedora was scheduled to start
查看VM:
[root@master ~]# kubectl get vm
NAME AGE STATUS READY
vm-fedora 118s Running True
可以看到,VM的状态已经变为Running了。
查看对应的VMI:
[root@master ~]# kubectl get vmi
NAME AGE PHASE IP NODENAME READY
vm-fedora 52s Running 192.244.0.13 master True
(3)暂停和取消暂停
暂停VM:
[root@master ~]# virtctl pause vm vm-fedora
VMI vm-fedora was scheduled to pause
[root@master ~]# kubectl get vm
NAME AGE STATUS READY
vm-fedora 7m10s Paused False
查看暂停后的VMI状态:
[root@master ~]# kubectl get vm vm-fedora -o=jsonpath='{.status.conditions[?(@.type=="Paused")].message}'
VMI was paused by user
取消暂停VM:
[root@master ~]# virtctl unpause vm vm-fedora
VMI vm-fedora was scheduled to unpause
(4)重启VM
[root@master ~]# virtctl restart vm-fedora
VM vm-fedora was scheduled to restart
(5)删除VM
[root@master ~]# kubectl delete vm vm-fedora
4. 虚拟机运行策略
VM配置文件中的Running字段用来确定是否运行VMI。Running是一个布尔值,只能为真或假,并不总是满足用户的需求。例如,在某些情况下,用户希望能够从VM内部关闭VMI,但是使用“spec.running: true”,KubeVirt将立即重新启动VMI。
RunStrategy会根据一系列条件决定VMI的行为,作为Running的替代方案,RunStrategy为创建和管理VMI提供了更大的灵活性。Running和RunStrategy是相互排斥的,只能同时使用spec.running或spec.runStrategy之一,如果两者都存在,则会出现错误。
RunStrategy目前支持四种策略:
- Always:在创建VM时,始终会存在VMI。如果因为任何原因造成原始的VMI停止运行,则会创建一个新的VMI,这与spec.running: true的行为相同。
- RerunOnFailure:如果上一个VMI因为错误而失败,则会重新创建一个VMI。如果VM成功停止(例如VM正常关机),则不会重新创建VMI。
- Manual:KubeVirt不会尝试启动或停止VM。为了改变状态,用户必须从API调用start、stop和restart,virtctl客户端命令可以用来控制VMI的状态。
- Halted:创建VM时没有VMI,这与spec.running: false的行为相同。
Always运行策略的示例用法如下:
[root@master ~]# vi vm-runstrategy.yaml
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
labels:
kubevirt.io/vm: vm-fedora
name: vm-fedora
spec:
runStrategy: Always
template:
metadata:
labels:
kubevirt.io/vm: vm-fedora
spec:
domain:
resources:
requests:
memory: 1Gi
devices:
disks:
- name: containerdisk
disk:
bus: virtio
volumes:
- name: containerdisk
containerDisk:
image: kubevirt/fedora-cloud:v1.0
imagePullPolicy: IfNotPresent
创建VM:
[root@master ~]# kubectl apply -f vm-runstrategy.yaml
virtualmachine.kubevirt.io/vm-fedora created
查看VM和VMI:
[root@master ~]# kubectl get vm
NAME AGE STATUS READY
vm-fedora 11s Running True
[root@master ~]# kubectl get vmi
NAME AGE PHASE IP NODENAME READY
vm-fedora 14s Running 192.244.0.15 master True
可以看到,VM创建后的状态为Running,对应的VMI也已运行。使用virtctl的start、stop和restart命令可以影响VM的运行策略。
表1-2显示了VM在运行virtctl命令后运行策略的变化。第一列显示了VM原始的运行策略,其它列显示运行的virtctl命令以及在运行该命令后的新的运行策略。
表1-2 VM在运行virtctl命令后运行策略的变化
RunStrategy | start | stop | restart |
---|---|---|---|
Always | - | Halted | Always |
RerunOnFailure | - | Halted | RerunOnFailure |
Manual | Manual | Manual | Manual |
Halted | Always | - | - |
使用virtctl工具对该VM执行stop操作:
[root@master ~]# virtctl stop vm-fedora
VM vm-fedora was scheduled to stop
查看VM和VMI:
[root@master ~]# kubectl get vm
NAME AGE STATUS READY
vm-fedora 6m35s Stopped False
[root@master ~]# kubectl get vmi
No resources found in default namespace.
此时VMI已经消失。查看VM的RunStrategy:
[root@master ~]# kubectl get vm vm-fedora -o jsonpath={.spec.runStrategy}
Halted
可以看到,在执行“virtctl stop”命令后,VM的RunStrategy由Always变成了Halted。
删除VM:
[root@master ~]# kubectl delete vm vm-fedora
5. 虚拟机存储卷
存储卷是启动虚拟机必不可少的部分,KubeVirt 中提供多种方式的存储卷,存储卷的使用方式非常灵活。
KubeVirt支持在spec.volumes下指定多种类型的卷:
- cloudInitConfigDrive:通过给VM挂载一个文件系统,给cloud-init提供meta-data和user-data。
- cloudInitNoCloud:通过给VM挂载一个文件系统,给cloud-init提供meta-data和user-data,生成的文件格式与ConfigDrive不同。
- containerDisk:指定一个包含QCOW2或RAW格式的Docker镜像,重启VM数据会丢失。
- dataVolume:动态创建一个PVC,并用指定的磁盘映像填充该PVC,重启VM数据不会丢失。
- emptyDisk:从宿主机上分配固定容量的空间,映射到VM中的一块磁盘,与emptyDir一样,emptyDisk的生命周期与VM等同,重启VM数据会丢失。
- ephemeral:在VM启动时创建一个临时卷,VM关闭后自动销毁,临时卷在不需要磁盘持久性的任何情况下都很有用。
- hostDisk:在宿主机上创建一个IMG镜像文件给VM使用。重启VM数据不会丢失。
- persistentVolumeClaim:指定一个PVC创建一个块设备。重启VM数据不会丢失。
- secret:使用Kubernetes的secret来存储和管理一些敏感数据,比如密码、Token、密钥等敏感信息,并把这些信息注入给VM,可以动态更新到Pod,但是不能修改Pod中生成的ISO文件,更不能更新到VM。要想更新到VM,需重启VM。
- configMap:功能类似于secret,把configMap里的信息写入到ISO磁盘中,挂给VM。
- serviceAccount:功能类似为secret,把serviceAccount里的信息写入到ISO磁盘中,挂给VM。
- sysprep:以secret或configMap的形式,往VM写入sysprep。
(1)containerDisk
KubeVirt 可以使用 ContainerDisk 类型的存储卷,ContainerDisk 提供了一种以 registry 存储和分发虚拟机镜像的方案,可以使用这种方式制作上传镜像。
虚拟机镜像制作流程如图5所示:
图5
虚拟机镜像采用容器镜像形式存放在镜像仓库中。将Linux发行版本的镜像文件存放到基础镜像的/disk目录内,镜像格式支持QCOW2、RAW和IMG。通过Dockerfile文件将虚拟机镜像制作成容器镜像,然后分别推送到不同的registry镜像仓库中。客户在创建虚拟机时,根据配置的优先级策略拉取registry中的虚拟机容器镜像。
编写Dockerfile:
[root@master ~]# vi Dockerfile
FROM scratch
ADD KubeVirt/images/cirros-0.5.2-x86_64-disk.img /disk/
构建镜像:
[root@master ~]# docker build -t cirros:v1.0 .
Sending build context to Docker daemon 80.6MB
Step 1/2 : FROM scratch
--->
Step 2/2 : ADD KubeVirt/images/cirros-0.5.2-x86_64-disk.img /disk/
---> bef33c2671f3
Successfully built bef33c2671f3
Successfully tagged cirros:v1.0
使用新构建的镜像,并将ContainerDisk作为临时磁盘附加到VM:
[root@master ~]# vi vmi-containerdisk.yaml
apiVersion: kubevirt.io/v1
kind: VirtualMachineInstance
metadata:
labels:
special: vmi-cirros
name: vmi-cirros
spec:
domain:
devices:
disks:
- disk:
bus: virtio
name: containerdisk
resources:
requests:
memory: 1024M
terminationGracePeriodSeconds: 0
volumes:
- containerDisk:
image: cirros:v1.0
imagePullPolicy: IfNotPresent
name: containerdisk
创建VMI:
[root@master ~]# kubectl apply -f vmi-containerdisk.yaml
virtualmachineinstance.kubevirt.io/vmi-cirros created
查看VMI:
[root@master ~]# kubectl get vmi
NAME AGE PHASE IP NODENAME READY
vmi-cirros 26s Running 192.244.0.16 master True
删除VMI:
[root@master ~]# kubectl delete vmi vmi-cirros
(2)cloudInitNoCloud
cloudInitNoCloud利用cloud-init对虚拟机做初始化,类似于nova中的configdrive,包含元数据meta-data和用户数据user-data。meta-data能实现一些固定功能设置,如主机名称,user-data则可以实现更多灵活的功能,如生成文件、执行脚本等。
如基于cloudInitNoCloud设置VMI密码:
[root@master ~]# vi vmi-cloudinit.yaml
apiVersion: kubevirt.io/v1
kind: VirtualMachineInstance
metadata:
labels:
special: vmi-fedora
name: vmi-fedora
spec:
domain:
devices:
disks:
- disk:
bus: virtio
name: containerdisk
- disk:
bus: virtio
name: cloudinitdisk
rng: {}
resources:
requests:
memory: 1024M
terminationGracePeriodSeconds: 0
volumes:
- containerDisk:
image: kubevirt/fedora-cloud:v1.0
imagePullPolicy: IfNotPresent
name: containerdisk
- cloudInitNoCloud:
userData: |-
#cloud-config
password: fedora
chpasswd: { expire: False }
name: cloudinitdisk
创建VMI:
[root@master ~]# kubectl apply -f vmi-cloudinit.yaml
查看VMI:
[root@master ~]# kubectl get vmi
NAME AGE PHASE IP NODENAME READY
vmi-fedora 23s Running 192.244.0.17 master True
创建VMI的时候通过cloudInitNoCloud设置系统密码为fedora,使用该密码连接VMI:
[root@master ~]# virtctl console vmi-fedora
Successfully connected to vmi-fedora console. The escape sequence is ^]
vmi-fedora login: fedora
Password:
[fedora@vmi-fedora ~]$ vi /etc/redhat-release
Fedora release 32 (Thirty Two)
使用“Ctrl + ]”组合即可退出console控制台界面。
删除VMI:
[root@master ~]# kubectl delete vmi vmi-fedora
(3)emptyDisk
emptyDisk的工作原理类似于Kubernetes中的emptyDir,将创建额外的稀疏QCOW2磁盘,emptyDisk的生命周期与VMI等同。当VMI初始化重启后,数据保留下来,但当VMI重启时,数据将被丢弃。创建emptyDisk时必须提供磁盘容量大小。
例如为VMI额外创建一块2 GB大小的磁盘:
[root@k8s-master-node1 KubeVirt]# vi vmi-emptydisk.yaml
apiVersion: kubevirt.io/v1
kind: VirtualMachineInstance
metadata:
labels:
special: vmi-fedora
name: vmi-fedora
spec:
domain:
devices:
disks:
- disk:
bus: virtio
name: containerdisk
- name: emptydisk
disk:
bus: virtio
- disk:
bus: virtio
name: cloudinitdisk
resources:
requests:
memory: 1024M
terminationGracePeriodSeconds: 0
volumes:
- containerDisk:
image: kubevirt/fedora-cloud:v1.0
name: containerdisk
- name: emptydisk
emptyDisk:
capacity: 2Gi
- cloudInitNoCloud:
userData: |-
#cloud-config
password: fedora
chpasswd: { expire: False }
name: cloudinitdisk
创建VMI:
[root@master ~]# kubectl apply -f vmi-emptydisk.yaml
查看VMI磁盘信息:
[root@master ~]# virtctl console vmi-fedora
Successfully connected to vmi-fedora console. The escape sequence is ^]
vmi-fedora login: fedora
Password:
[fedora@vmi-fedora ~]$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
vda 252:0 0 4G 0 disk
└─vda1 252:1 0 4G 0 part /
vdb 252:16 0 2G 0 disk
vdc 252:32 0 1M 0 disk
可以看到VMI中挂载了一块磁盘vdb,大小为2 GB,说明emptyDisk创建成功。
使用“Ctrl + ]”组合键即可退出console控制台界面。
删除VMI:
[root@master ~]# kubectl delete vmi vmi-fedora
- 点赞
- 收藏
- 关注作者
评论(0)