本文已超过一年。较早的文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。
认识 Kubevirt
一旦你习惯了在 Kubernetes 上运行 Linux 容器工作负载,你可能会发现自己希望也能在你的 Kubernetes 集群上运行其他类型的工作负载。也许你需要运行一个并非为容器设计的应用程序,或者它需要不同版本的 Linux 内核——甚至完全不同的操作系统——而非容器主机上提供的版本。
这类工作负载通常非常适合在虚拟机 (VM) 中运行,而 KubeVirt,一个适用于 Kubernetes 的虚拟机管理附加组件,旨在让用户能够在他们的 Kubernetes 或 OpenShift 集群中将 VM 与容器并行运行。
KubeVirt 通过 Kubernetes 的 自定义资源定义 API (CRD) 添加 VM 和 VM 集合的资源类型来扩展 Kubernetes。KubeVirt VM 在常规的 Kubernetes Pod 中运行,它们可以在其中访问标准的 Pod 网络和存储,并且可以使用标准的 Kubernetes 工具(例如 kubectl)进行管理。
在 Kubernetes 中运行 VM 与使用 oVirt 或 OpenStack 等工具相比有所不同,理解 KubeVirt 的基本架构是一个很好的起点。
在这篇文章中,我们将从高层次讨论 KubeVirt 涉及的一些组件。我们将要介绍的组件包括 CRD、KubeVirt 的 virt-controller、virt-handler 和 virt-launcher 组件、libvirt、存储和网络。
KubeVirt 组件

自定义资源定义
Kubernetes 资源是 Kubernetes API 中的端点,用于存储相关 API 对象的集合。例如,内置的 pods 资源包含 Pod 对象的集合。Kubernetes 的 自定义资源定义 API 允许用户通过定义具有给定名称和模式的新对象来扩展 Kubernetes 的附加资源。一旦你将自定义资源应用到你的集群,Kubernetes API Server 就会为你的自定义资源提供服务并处理其存储。
KubeVirt 的主要 CRD 是 VirtualMachine (VM) 资源,它在 Kubernetes API Server 内部包含 VM 对象的集合。VM 资源定义了虚拟机本身的所有属性,例如机器和 CPU 类型、RAM 和 vCPU 的数量,以及 VM 中可用的网卡 (NIC) 的数量和类型。
virt-controller
virt-controller 是一个 Kubernetes Operator,负责集群范围内的虚拟化功能。当新的 VM 对象被发送到 Kubernetes API Server 时,virt-controller 会注意到并创建 VM 将要运行的 Pod。当 Pod 被调度到特定的节点上时,virt-controller 会用节点名称更新 VM 对象,并将进一步的职责移交给一个节点特定的 KubeVirt 组件 virt-handler,virt-handler 的一个实例运行在集群中的每个节点上。
virt-handler
与 virt-controller 类似,virt-handler 也是反应式的,它会监控 VM 对象的变更,并执行所有必要的操作以使 VM 达到所需的状态。virt-handler 会引用 VM 规格,并使用 VM Pod 中的 libvirtd 实例来发出创建对应域的信号。当一个 VM 对象被删除时,virt-handler 会观察到此删除操作并关闭该域。
virt-launcher
对于每个 VM 对象,都会创建一个 Pod。此 Pod 的主容器运行 virt-launcher KubeVirt 组件。virt-launcher Pod 的主要目的是提供将用于托管 VM 进程的 cgroups 和 namespaces。
virt-handler 通过将 VM 的 CRD 对象传递给 virt-launcher 来信号通知 virt-launcher 启动 VM。virt-launcher 随后使用其容器内的本地 libvirtd 实例启动 VM。之后,virt-launcher 监控 VM 进程,并在 VM 退出后终止。
如果 Kubernetes 运行时尝试在 VM 退出之前关闭 virt-launcher Pod,virt-launcher 会将来自 Kubernetes 的信号转发给 VM 进程,并尝试阻止 Pod 终止,直到 VM 成功关闭。
# kubectl get pods
NAME READY STATUS RESTARTS AGE
virt-controller-7888c64d66-dzc9p 1/1 Running 0 2h
virt-controller-7888c64d66-wm66x 0/1 Running 0 2h
virt-handler-l2xkt 1/1 Running 0 2h
virt-handler-sztsw 1/1 Running 0 2h
virt-launcher-testvm-ephemeral-dph94 2/2 Running 0 2h
libvirtd
每个 VM Pod 中都存在一个 libvirtd 实例。virt-launcher 使用 libvirtd 来管理 VM 进程的生命周期。
存储与网络
KubeVirt VM 可以配置磁盘,由卷作为后端支持。
持久卷声明 (Persistent Volume Claim) 卷将 Kubernetes 持久卷作为直接附加到 VM 的磁盘提供。这是为 KubeVirt VM 提供持久存储的主要方式。目前,持久卷必须是 iscsi 块设备,尽管正在进行工作以启用基于文件的 pv 磁盘。
临时卷 (Ephemeral Volumes) 是本地的写入时复制 (copy on write) 镜像,它们使用网络卷作为只读后端存储。KubeVirt 在 VM 启动时动态生成与 VM 关联的临时镜像,并在 VM 停止时丢弃这些临时镜像。目前,临时卷必须由 pvc 卷作为后端支持。
Registry Disk 卷引用嵌入 qcow 或 raw 磁盘的 Docker 镜像。顾名思义,这些卷是从容器镜像仓库拉取的。就像常规的临时容器镜像一样,这些卷中的数据仅在 Pod 存活期间持久存在。
CloudInit NoCloud 卷为 VM 提供 cloud-init NoCloud 用户数据源,它作为磁盘添加到 VM,在那里可以为安装了 cloud-init 的访客提供配置详情。Cloud-init 详情可以以明文形式提供,作为 base64 编码的 UserData 文件,或通过 Kubernetes Secret 提供。
在下面的示例中,配置了一个 Registry Disk 来提供用于引导 VM 的镜像。提供了一个 CloudInit NoCloud 卷,以及存储在 userData 字段中的明文 ssh-key,用于与 VM 进行认证。
apiVersion: kubevirt.io/v1alpha1
kind: VirtualMachine
metadata:
name: myvm
spec:
terminationGracePeriodSeconds: 5
domain:
resources:
requests:
memory: 64M
devices:
disks:
- name: registrydisk
volumeName: registryvolume
disk:
bus: virtio
- name: cloudinitdisk
volumeName: cloudinitvolume
disk:
bus: virtio
volumes:
- name: registryvolume
registryDisk:
image: kubevirt/cirros-registry-disk-demo:devel
- name: cloudinitvolume
cloudInitNoCloud:
userData: |
ssh-authorized-keys:
- ssh-rsa AAAAB3NzaK8L93bWxnyp test@test.com
就像常规的 Kubernetes Pod 一样,基本的网络功能会自动提供给每个 KubeVirt VM,并且可以使用常规的 Kubernetes Service 将特定的 TCP 或 UDP 端口暴露给外部世界。不需要特殊的网络配置。
参与其中
KubeVirt 的开发正在加速,项目渴望新的贡献者加入。如果你有兴趣参与其中,请查看项目的开放问题并查看项目日历。
如果你需要帮助或想聊天,可以通过 freenode IRC 的 #kubevirt 频道或通过 KubeVirt 邮件列表与团队联系。用户文档可在 https://kubevirt.gitbooks.io/user-guide/ 找到。