随着Docker
和Kubernetes
生态圈的发展,云计算领域对容器的兴趣达到了狂热的程度。 容器技术为应用程序提供了隔离的运行空间,每个容器内都包含一个独享的完整用户环境空间, 容器内的变动不会影响其他容器的运行环境。因为容器之间共享同一个系统内核,当同一个库被多个容器使用时, 内存的使用效率会得到提升。基于物理主机操作系统内核的,那就意味着对于不同内核或者操作系统需求的应用是不可能部署在一起的。
虚拟化技术则是提供了一个完整的虚拟机,为用户提供了不依赖于宿主机内核的运行环境。 对于从物理服务器过渡到虚拟服务器是一个很自然的过程,从用户使用上并没有什么区别。 容器与虚拟机当前看来并不是一个非此即彼的关系,至于采用那种方式去运行应用需要根据具体需求去决定。 在这里笔者并不讨论这个问题,且笔者仅是容器服务的入门玩家,内容若有不准确之处还望斧正。
kubernetes
提供了较灵活的容器调度和管理能力,那么虚拟机能否像容器一样被k8s
管理调度, 充分利用k8s
的故障发现,滚动升级等管理机制呢。 在Linux操作系统中虚拟机本质上就是一个操作系统进程应该是可以运行在容器内部的。
目前Redhat开源的kubevirt
和Mirantis开源的virtlet
都提供了以容器方式运行虚拟机的方案, 至于两者之间的区别,可以看下这篇Mirantis的 blog(https://www.mirantis.com/blog/kubevirt-vs-virtlet-comparison-better/)。
本文将详细介绍kubevirt
项目如何实现和运行容器化的虚拟机。
kubevirt 是 Redhat 开源的以容器方式运行虚拟机的项目,以 k8s add-on方式,利用 k8s CRD 为增加资源类型VirtualMachineInstance(VMI)
, 使用容器的image registry去创建虚拟机并提供VM生命周期管理。 CRD的方式是的kubevirt对虚拟机的管理不用局限于pod管理接口,但是也无法使用pod的RS
DS
Deployment
等管理能力,也意味着 kubevirt
如果想要利用pod管理能力,要自主去实现,目前kubevirt实现了类似RS
的功能。 kubevirt目前支持的runtime是docker和runv,本文中实践使用的是docker。
从kubevirt架构看如何创建虚拟机,Kubevirt架构如图所示,由4部分组件组成。从架构图看出kubevirt创建虚拟机的核心就是创建了一个特殊的pod virt-launcher
,其中的子进程包括libvirt
和qemu
。
做过openstack nova 项目的朋友应该比较习惯于一台宿主机中运行一个libvirtd
后台进程,kubevirt
中采用每个pod中一个libvirt
进程是去中心化的模式,来避免因为 libvirtd
服务异常导致所有的虚拟机无法管理。
vnc
console
start vm
stop vm
等。VMI
资源创建删除等状态VMI
定义创建virt-launcher
pod,该pod中将会运行虚拟机VMI
状态VMI
被标记得nodeName与自身node匹配时,负责虚拟机的生命周期管理VMI
定义生成虚拟机模板,通过libvirt API创建虚拟机Client K8s API VMI CRD Virt Controller VMI Handler
-------------------------- ----------- ------- ----------------------- ---------- listen <----------- WATCH /virtualmachines
listen <----------------------------------- WATCH /virtualmachines
| |
POST /virtualmachines ---> validate | |
create ---> VMI ---> observe --------------> observe
| | v v
validate <--------- POST /pods defineVMI
create | | |
| | | |
schedPod ---------> observe |
| | v |
validate <--------- PUT /virtualmachines |
update ---> VMI ---------------------------> observe
| | | launchVMI
| | | |
: : : :
| | | |
DELETE /virtualmachines -> validate | | |
delete ----> * ---------------------------> observe
| | shutdownVMI
| | |
: : :
kubevirt目前提供了多种方式的虚拟机的磁盘:
spec.volumes.registryDisk.image
转化为qcow2格式,路径为pod根目录spec.volumes.cloudInitNoCloud
创建包含iso文件,包含 meta-data 和 user-data。kubevirt
利用pvc挂载方式都是文件系统模式挂载, PVC首先被挂载在virt-laucher
pod中, 且需要存在名称为/disk/*.img
的文件,才挂载给虚拟机。 file模式虚拟化方式对虚拟机磁盘存储性能有很大的影响。
熟悉openstack的朋友应该也了解nova-compute中如何使用ceph rbd image的,实质上是libvirt使用librbd以network
方式 将rbd image远程改在给虚拟机。而kubevirt中将POD ip移交给了虚拟机,那将意味着pod内的libvirt服务其实是无法直接使用network
disk的。 要么增加网络代理转发即通过host来与网络设备通讯,要么就是采用k8s volumeMount:block feature来实现。
kubevirt社区有PR已经实现了以Block的方式去使用是rbd image, 笔者手动merge并测试通过。 实质是使用了kernel rbd.ko,首先将rbd image map到host,block的mount方式将不再以文件系统方式去挂载/dev/rbdx,而是为作为原始设备给pod,而pod内的libvirt就可以block
方式将rbd image作为 磁盘挂载给虚拟机。
相较于PVC先格式化为文件系统并必须创建disk.img文件的使用方式,显然rbd image 以block device直接作为块设备给虚拟机少了本地文件系统层 单从存储效率讲都能提高不少。至于librbd
和rbd.ko
的性能本文没有对比测试,有时间再补充。
k8s PVC
后续版本应该也可以提供block mode方式的mount。DataVolume
resource。 可以看成是从PVC和registryDisk衍生出来的,上面提过PVC使用是比较麻烦的,不仅需要PVC还需要创建disk.img, dataVolume其实将这个过程简化了,自动化的将disk.img创建在PVC中。 创建DataVolume是可以定义source
即image/data来源可以是http
或者s3
的URL,CDI controller会将 自动将image转化并拷贝到PVC文件系统/disk/
kubevirt虚拟机网络使用的是pod网络也就是说,虚拟网络原生与pod之间是打通的。虚拟机具体的网络如图所示, virt-launcher pod网络的网卡不再挂有pod ip,而是作为虚拟机的虚拟网卡的与外部网络通信的交接物理网卡。 那么虚拟机是如何拿到pod的ip的呢,virt-launcher
实现了简单的单ip dhcp server,就是需要虚拟机中启动dhclient,virt-launcher 服务会分配给虚拟机。
使用命令kubectl exec $virt-launch-pod -c compute -- brctl show
可以看到bridge信息。 其中eth0就是pod与host网络通讯的veth peer网卡。也可以通过virsh dumpxml
命令查看虚拟机的xml定义文件。
首先需要k8s环境,本文中使用的是v1.10.5
版本,kubevirt选择v0.8.0
,调用如下命令部署kubevirt:
$ export VERSION=v0.8.0
$ kubectl create \
-f https://github.com/kubevirt/kubevirt/releases/download/$VERSION/kubevirt.yaml
kubevirt.yaml 中定义了 RBAC 相关认证,默认管理服务都创建再 kube-system
namespace中,可以通过以下命令查看资源,以及服务部署状态。当看到pods 全部创建成功后,通过kubectl get vmis
来检测服务是否可用。
kubectl get all -n kube-system -l kubevirt.io
NAME READY STATUS RESTARTS AGE
pod/virt-api-54cc86ff87-9xt8s 1/1 Running 0 14d
pod/virt-api-54cc86ff87-xvjg4 1/1 Running 0 14d
pod/virt-controller-769db5f6bf-2wgr4 1/1 Running 0 13d
pod/virt-controller-769db5f6bf-xwgks 1/1 Running 0 13d
pod/virt-handler-gpn6b 1/1 Running 0 2hNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/virt-api ClusterIP 172.30.7.81 <none> 443/TCP 16dNAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
daemonset.apps/virt-handler 1 1 1 1 1 <none> 16dNAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deployment.apps/virt-api 2 2 2 2 16d
deployment.apps/virt-controller 2 2 2 2 16dNAME DESIRED CURRENT READY AGE
replicaset.apps/virt-api-54cc86ff87 2 2 2 14d
replicaset.apps/virt-api-645f74c7fc 0 0 0 16d
replicaset.apps/virt-controller-658bf69f57 0 0 0 16d
replicaset.apps/virt-controller-769db5f6bf 2 2 2 14d
Kubevirt 在 openshift 的部署是类似的,唯一不同的是需要为 kubevirt service account 增加 openshift 权限。在需要使用 block volumemount 时,openshift需要修改 origin-node 的配置文件增加 feature-gates “BlockVolume=true”
oc adm policy add-scc-to-user privileged system:serviceaccount:kube-system:kubevirt-privilegedoc adm policy add-scc-to-user privileged system:serviceaccount:kube-system:kubevirt-controlleroc adm policy add-scc-to-user privileged system:serviceaccount:kube-system:kubevirt-infraoc adm policy add-scc-to-user privileged system:serviceaccount:kube-system:kubevirt-apiserver
在kubevirt存储一节中介绍了kubevirt支持的存储类型,其中registryDisk和PVC方式可以为作为预装操作系统的虚拟机root disk。
kubevirt提供了registryDisk的base docker image registry-disk-v1alpha
1 . 准备raw或者qcow2格式的虚拟机镜像,例如Windows---server-2012-datacenter-64bit-cn-syspreped---2018-01-15.qcow2
2 . 创建Dockerfile
FROM kubevirt/registry-disk-v1alphaMAINTAINER "MinMin" <rmm0811@gmail.com># Add alpine image
COPY Windows---server-2012-datacenter-64bit-cn-syspreped---2018-01-15.qcow2 /disk/windows2012dc.img
3 . 创建image
docker build -t windows2012dc:latest ./
docker push windows2012dc:latest
4 . 更新vmi yaml文件中image
将vmi文件中的image更新为新创建的image
kind: VirtualMachineInstance
...
spec:
domain:
devices:
disks:
- disk:
bus: virtio
name: registrydisk
volumeName: registryvolume
... - name: registryvolume
registryDisk:
image: windows2012dc:latest
PVC是k8s提供的持久化存储方式,当需要对虚拟机变更持久化存储时必须要采用这种方式。笔者在写本文时,kubevirt还未支持blockmode PVC,此章节 仅介绍file方式的。kubevirt中创建虚拟机是以pod空间中的/disk/
目录下,那么意味着需要将PVC实现进行文件系统格式化,并创建disk/目录将 虚拟机root disk image拷贝至disk目录中。 这个过程可以手动完成比较繁杂,kubevirt提供了新的项目kubevirt/containerized-data-importer自动化这个过程,可参考示例 vm-alpine-datavolume.yaml)通过DataVolume.spec.source定义虚拟操作系统的image路径。
自己创建vmi的yaml文件,或者从github.com/kubevirt/kubevirt 项目中的cluster/examples 下的 vmi-flavor-small.yaml 文件去创建虚拟机,创建完成后可以 使用ssh登陆查看虚拟机或者使用virtctl console
和 virtctl vnc
来登陆虚拟机。
# kubectl create -f vmi-flavor-small.yaml
# kubectl get vmis
NAME AGE
vmi-flavor-small 15h
vmi_pvc-windows 14h
# kubectl get pods
virt-launcher-vmi-flavor-small-7m2cj 2/2 Running 0 2h
virt-launcher-vmi-pvc-windows-wvg5c 1/1 Running 0 14d
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有