ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

KubeVirt VirtualMachine(VM)对象深度指南:CRD 设计、runStrategy 状态机与控制器实现

KubeVirt VirtualMachine(VM)对象深度指南:CRD 设计、runStrategy 状态机与控制器实现 云原生【免费下载链接】kubevirtKubernetes Virtualization API and runtime in order to define and manage virtual machines.项目地址https://gitcode.com/gh_mirrors/ku/kubevirt点击查看免费下载本篇技术指南以 KubeVirt 仓库的开发者文档 docs/devel/virtual-machine.md 为核心系统讲解 VirtualMachineVM这一 Kubernetes 自定义资源CRD的设计动机、kubectl / REST API 操作方式、对象结构与字段语义并结合源码剖析其控制器实现与生命周期行为。读完本文你将能够独立编写、启动、停止、删除 VirtualMachine 清单理解 runStrategy 各取值的行为差异并能顺着源码定位 VM 控制器的工作原理。VirtualMachine 是什么为停机态虚拟机提供统一入口几乎所有虚拟机管理系统都同时允许你管理运行中和已停止两种状态的虚拟机既能编辑两类对象的配置也能查看它们的状态。KubeVirt 中负责承载运行中虚拟机的是 VirtualMachineInstanceVMI对象——它提供运行态虚拟机的配置与状态而 VirtualMachineVM正是为了补齐已停止虚拟机这一侧而引入的二者设计上成对工作tandem。从类型定义看staging/src/kubevirt.io/api/core/v1/types.go 中 VirtualMachine 是一个标准的 Kubernetes 资源结构type VirtualMachine struct { metav1.TypeMeta json:,inline metav1.ObjectMeta json:metadata,omitempty // Spec contains the specification of VirtualMachineInstance created Spec VirtualMachineSpec json:spec valid:required // Status holds the current state of the controller and brief information // about its associated VirtualMachineInstance Status VirtualMachineStatus json:status,omitempty }VirtualMachine 本身是 Kubernetes 的 custom resource definitionCRD这意味着它可以复用 Kubernetes 原生机制来存储对象、通过 API 暴露对象因此天然支持 kubectl、RBAC、etcd 持久化等能力。不过其 CRD 声明与控制器实现细节见下文如何实现章节。VirtualMachine 的核心能力VirtualMachine 提供的功能可归纳为四点以模板形式存储 VirtualMachineInstanceVM 对象内部持有一个 VMI 模板spec.template控制器按需从模板实例化出真正的 VMI通过 kubectl 操作 VMI借助 Kubernetes 命令行事例式地创建、更新、删除对象通过 Kubernetes API 操作 VMI对外暴露标准 REST 端点便于外部程序编程访问监听 VMI 变化并做出反应包括把模板转换为 VMI 从而启动虚拟机以及停止 VMI 并把状态同步回 VirtualMachine。这四条能力在控制器源码中都有对应实现。VM 控制器位于 pkg/virt-controller/watch/vm/vm.goNewController同文件 L134 附近注册了对 VirtualMachine 与 VirtualMachineInstance 两类对象的 informer 监听工作队列驱动execute()完成状态同步。通过 kubectl 操作 VirtualMachinekubectl 允许以命令式方式操作 Kubernetes 对象你可以创建、删除、更新和查询 API 中的对象。以下命令序列完整覆盖了 VirtualMachine 的典型生命周期# 定义创建一个 VirtualMachine kubectl create -f myvm.yaml # 启动一个 VirtualMachine把运行策略改为 Always kubectl patch virtualmachine myvm --typemerge -p \ {spec:{runStrategy: Always}} # 查看 VirtualMachine 状态与关联事件 kubectl describe virtualmachine myvm # 查看随之创建的 VirtualMachineInstance 状态与关联事件 kubectl describe virtualmachine myvm # 停止一个 VirtualMachine把运行策略改为 Halted kubectl patch virtualmachine myvm --typemerge -p \ {spec:{runStrategy: Halted}} # 隐式级联删除先删除 VMI再删除 VM kubectl delete virtualmachine myvm # 显式级联删除同上显式声明 kubectl delete virtualmachine myvm --cascadetrue # 孤儿删除运行中的 VMI 仅被脱离不会被删除 # 重新创建同名 VM 时该 VMI 会被收养并重新建立关联 kubectl delete virtualmachine myvm --cascadefalse需要说明的是启动与停止本质上都是修改spec.runStrategy控制器检测到策略变化后自动创建或销毁对应的 VMI无需手工管理 VMI 对象--cascadetrue默认会先删除由 VM 派生的 VMI再删除 VM 本体--cascadefalse则只删除 VM保留下运行中的 VMI并在同名 VM 重建时通过 OwnerReference 完成收养adoption详见删除策略一节若使用的是较新版本的 kubectl级联删除语义由--cascadebackground/foreground/orphan等取值表达效果与上面对应。仓库自带的 examples/vm-cirros.yaml 是一个开箱即用的真实 VM 清单可直接kubectl create -f后按上述命令操作。通过 Kubernetes REST API 操作 VirtualMachinekubectl 适合交互式操作但编写外部应用时更应直接使用 Kubernetes 提供的原生 REST API——它集中、可扩展且因为 VirtualMachine 是 CRDKubernetes 会自动为其生成 API 端点。原始文档给出的 API 路径为当时的 v1alpha2 版本your-api-server-address/apis/kubevirt.io/v1alpha2/virtualmachine/注意apiVersion与 KubeVirt 的发布周期绑定当前仓库中的清单已演进到kubevirt.io/v1见 examples/vm-cirros.yaml 第 2 行因此实际访问时应以集群中部署的 KubeVirt 版本所对应的 group/version 为准。以 v1alpha2 路径为例全部 CRUD 操作如下POST /apis/kubevirt.io/v1alpha2/namespaces/{namespace}/virtualmachine GET /apis/kubevirt.io/v1alpha2/namespaces/{namespace}/virtualmachine GET /apis/kubevirt.io/v1alpha2/namespaces/{namespace}/virtualmachine/{name} DELETE /apis/kubevirt.io/v1alpha2/namespaces/{namespace}/virtualmachine/{name} PUT /apis/kubevirt.io/v1alpha2/namespaces/{namespace}/virtualmachine/{name} PATCH /apis/kubevirt.io/v1alpha2/namespaces/{namespace}/virtualmachine/{name}各方法的语义POST把新对象写入 etcdGET获取全部 VirtualMachine 列表或获取指定名称的单个对象DELETE从 etcd 中移除对象及其所有关联资源PUT整体更新已存在的 VirtualMachine 对象PATCH只修改对象内部某个字段如仅改runStrategy。与 API 通信的数据格式为 JSON通过Content-Type: application/json请求头指定也可以使用application/yaml。KubeVirt 的 OpenAPI 描述文件位于 api/openapi-spec/swagger.json可用于生成客户端、校验请求或查阅字段定义。VirtualMachine 对象内容详解VirtualMachine 与任何 Kubernetes 对象一样可用 YAML 或 JSON 表达。原始文档给出的结构示例如下apiVersion: kubevirt.io/v1alpha2 kind: VirtualMachine metadata: name: myvm spec: runStrategy: Halted template: metadata: labels: my: label spec: domain: resources: requests: memory: 8Mi devices: disks: - name: disk0 volumeName: mypcv volumes: - name: mypvc persistentVolumeClaim: claimName: myclaim提示示例中的volumeName: mypcv与volumes[].name: mypvc在早期版本写法中存在不一致现代清单见 examples/vm-cirros.yaml要求盘内name与对应volumes项的name严格对应例如name: containerdisk对应volumes[0].name: containerdisk。字段语义以 Kubernetes 官方指南为基准apiVersion关联 KubeVirt 发布周期metadata中name为必填spec中runStrategy声明 VM 期望的运行状态template则是 VMI 模板。下面逐字段展开。Name命名与唯一标识metadata.name对 VirtualMachine 至关重要它直接派生出所创建 VMI 的名字——若 VM 名为testvm其 VMI 也叫testvm。同时namespace/metadata.name这对组合构成 VirtualMachine 的唯一标识同一命名空间下出现两个相同名字即视为错误。TemplateVirtualMachineInstance 模板spec.template就是用来创建真实 VMI 的规格它与 staging/src/kubevirt.io/api/core/v1/types.go 中定义的 VirtualMachineInstance 结构完全一致只是不含kind与apiVersion——这两个字段在创建 VMI 时由控制器隐式补全。因此spec.template内可支持的全部字段与 VirtualMachineInstance 文档API 定义见 staging/src/kubevirt.io/api/core/v1/types.go保持一致。runStrategy声明期望运行状态spec.runStrategy指示与该 VM 关联的 VirtualMachineInstance 的期望运行状态。源码中types.go定义了完整的取值集合取值语义摘自源码注释AlwaysVMI 应始终保持运行被停止后控制器会立即重新创建HaltedVMI 应始终处于停止状态永不运行ManualVMI 可通过 API 端点手动启停通过 subresource 发 Start/Stop 请求RerunOnFailureVMI 初始运行失败后重启正常成功后不再重启OnceVMI 只运行一次无论以 Failure 还是 Success 结束都不再重启WaitAsReceiver创建等待迁移入站的接收 Pod之后切换为期望的 RunStrategy另有两个值得注意的机制spec.running字段已废弃早期版本使用Running *bool控制启停false映射为Haltedtrue映射为Always。源码 types.go 明确标注其已被RunStrategy取代且两者互斥——同时设置会报错见RunStrategy()方法的校验逻辑types.gofunc (vm *VirtualMachine) RunStrategy() (VirtualMachineRunStrategy, error) { if vm.Spec.Running ! nil vm.Spec.RunStrategy ! nil { return RunStrategyUnknown, fmt.Errorf(running and runstrategy are mutually exclusive) } RunStrategy : RunStrategyHalted if vm.Spec.Running ! nil { if (*vm.Spec.Running) true { RunStrategy RunStrategyAlways } } else if vm.Spec.RunStrategy ! nil { RunStrategy *vm.Spec.RunStrategy } return RunStrategy, nil }启动失败退避在Always等策略下若 VMI 连续启动失败控制器会记录StartFailureConsecutiveFailCount、RetryAfterTimestamp等字段见 types.go并按退避时间延迟下一次启动见 vm.go 中startFailureBackoffTimeLeft的调用避免崩溃循环。VirtualMachineSpec 的其他字段从 types.go 可以看到spec除runStrategy与template外还包含instancetype/preference引用 InstanceType 与 Preference 资源用于填充模板中的 CPU、内存等字段dataVolumeTemplatesDataVolume 模板列表供 VMI 模板引用这些 DataVolume 随 VM 生命周期动态创建与回收updateVolumesStrategy卷更新策略取值为Migration或Replacementtypes.go。控制器对应处理逻辑见 vm.go 中的handleDataVolumesL510、handleVolumeRequestsL806、handleVolumeUpdateRequestL887等函数。VirtualMachine 行为与 VMI 的同步机制VirtualMachine 必须与其 VMI 保持同步VM 控制器同时观察 VM 与由其创建的 VMI 两个对象通过 OwnerReference 建立关联后把配置变更翻译下发到 VMI再把 VMI 的状态变化回写为 VM 的状态。Status状态回写原始文档给出的 status 示例为status: observedGeneration: 124 # 当前观察到的版本generation virtualMachine: my-vm created: true # 关联的 VirtualMachineInstance 是否已创建 ready: true # 基于 http 就绪检查的 libvirt 信息 conditions: [] # 附加的可能状态从 VMI 回写propagate到 VM status 的信息包括VMI 是否存在于集群中、VMI 的就绪状态、VMI 的名称。更细的信息需要直接查看 VMI 对象本身。现代实现中types.goVirtualMachineStatus字段已大幅扩展核心成员有createdVMI 是否已在集群中创建readyVMI 是否运行并就绪printableStatus面向人类的可读状态默认StoppedconditionsVM 与其 VMI 的状态信息集合observedGeneration/desiredGeneration用于判断 VMI 与期望规格是否同步stateChangeRequests需要施加到 VMI 上的动作列表如先停止某 VMI 再启动新 VMIvolumeRequests热插拔hotplug场景下增删卷的请求startFailureVMI 连续启动失败记录服务于崩溃循环退避runStrategy最近一次生效的 RunStrategy供RerunOnFailure等策略正确衔接下一次决策。printableStatus的枚举types.go包括Stopped、Provisioning、Starting、Running、Paused、Stopping、Terminating、CrashLoopBackOff、Migrating、Unknown、ErrorUnschedulable、ErrImagePull、ImagePullBackOff、ErrorPvcNotFound、DataVolumeError、WaitingForVolumeBinding、WaitingForReceiver等可通过kubectl get vm直接观察。原始文档还提及 conditions 可用于展示 VMI 的附加状态信息例如记录停机方式status: conditions: - lastShutdown: 12.12.2018 00:00:00 Reason: error该字段写法随版本演进已抽象为结构化 Condition 对象此处保留原始示例以说明设计意图。OwnerReference程序化关联父对象同名只是关联的第一步要在 Kubernetes 中程序化地找到 VMI 的父 VM必须借助 OwnerReference。它位于对象的metadata段由控制器自动创建示例如下apiVersion: kubevirt.io/v1alpha2 kind: VirtualMachine metadata: name: myvm ownerReferences: - controller: true uid: 1234-1234-1234-1234 kind: VirtualMachine version: kubevirt.io/v1alpha2VM 控制器在创建 VMI 时会为其附加metadata.ownerReference详见 vm.go 中 VMI 创建路径由此把 VM 与 VMI 双向链接起来支撑组合状态展示与级联删除。Update strategy更新策略当前实现为隐式的OnDelete未来如需可扩展为 RollingUpdate。含义是对spec的修改不会直接影响已在运行的 VMI也不会立即下发到 VMI。只有当 VMI 被关闭VMI 对象被删除、或操作系统内关机等后控制器才会按新规格重新创建 VMI。Delete strategy删除策略删除带有级联行为默认级联会一并删除由 VM 创建的 VMI。若关闭级联--cascadefalseVMI 成为孤儿orphaned并继续运行当创建了与孤儿 VMI 同名的 VM 时该 VMI 会被收养OwnerReference 相应更新。Reset 与 Reboot这两个操作不由 VirtualMachine 本体承担而是通过 VirtualMachine 的subresource命令式接口实现且不会导致 VM 对象或其 Pod 被重建。从 KubeVirt 视角看VirtualMachine 始终处于运行态因此在 reset/reboot 场景下对spec的修改不会被传播到 VMI。这也与Manual策略下通过 Start/Stop 请求StateChangeRequestAction的StartRequest/StopRequest见 types.go控制 VMI 的设计一脉相承。如何实现CRD 与控制器VirtualMachine 的第一版实现由两部分组成一是 VirtualMachine 自定义资源定义二是监听变化并更新状态的控制器。自定义资源定义CRD原始文档给出的 CRD 骨架如下apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: virtualmachines.kubevirt.io spec: scope: Namespaced group: kubevirt.io version: v1alpha2 names: kind: VirtualMachine plural: virtualmachines singular: virtualmachine shortNames: - vm - vms要点解读scope: NamespacedVirtualMachine 是命名空间级资源与namespace/name唯一标识的语义吻合shortNames:vm/vms正是kubectl get vm、kubectl describe vm myvm等短命令可用的原因CRD 定义中的 API 规范会用于自动生成Kubernetes 客户端、lister 与 watcher 等资源这也是控制器能够监听 VM 变化的基础。实际部署时完整 CRD 由 KubeVirt 的清单生成流程产出可参考 manifests/generated/kubevirt-cr.yaml.in 与 manifests/release/kubevirt-operator.yaml.in其中包含全部 API 版本的 schema 与校验规则。控制器Controller控制器负责监听已注册虚拟机的变化并更新系统状态其职责包括当设置了合适的runStrategy时创建新的 VirtualMachineInstance为创建的 VMI 附加metadata.ownerReference从而把 VM 与 VMI 链接起来并展示组合状态。核心调度逻辑是 vm.go 的syncRunStrategy函数它按当前策略走不同的分支——例如Always策略下若 VMI 已进入终态vmi.IsFinal()或存在强制重启请求则调用stopVMI停掉旧 VMI 并让下一轮同步重新创建Halted策略下则确保不创建 VMI。启动失败时还会结合退避时间把对象重新入队c.Queue.AddAfter实现优雅的重试节奏。架构上该控制器被设计为运行在独立 Pod中的独立服务。KubeVirt 整体采用模块化架构这种设计让核心代码保持精简且控制器可在需要时单独扩容。VM 控制器入口在 cmd/virt-controller/virt-controller.go由 pkg/virt-controller/watch/application.go 装配各 informer 与控制器。完整实战示例基于仓库清单创建一台 VM以仓库自带的 examples/vm-cirros.yaml 为例这是一份完整的、可直接运行的 VirtualMachine 清单--- apiVersion: kubevirt.io/v1 kind: VirtualMachine metadata: labels: kubevirt.io/vm: vm-cirros name: vm-cirros spec: runStrategy: Halted template: metadata: labels: kubevirt.io/vm: vm-cirros spec: domain: devices: disks: - disk: bus: virtio name: containerdisk - disk: bus: virtio name: cloudinitdisk memory: guest: 128Mi resources: {} terminationGracePeriodSeconds: 0 volumes: - containerDisk: image: registry:5000/kubevirt/cirros-container-disk-demo:devel name: containerdisk - cloudInitNoCloud: userData: | #!/bin/sh echo printed from cloud-init userdata name: cloudinitdisk实操路径将containerDisk.image替换为你环境中实际可拉取的容器磁盘镜像kubectl create -f examples/vm-cirros.yaml创建 VM此时runStrategy: HaltedVMI 不会启动kubectl patch virtualmachine vm-cirros --typemerge -p {spec:{runStrategy: Always}}启动kubectl get vm vm-cirros观察printableStatus从Starting变为Running需要停止时改回Halted彻底删除用kubectl delete virtualmachine vm-cirros。仓库 examples/ 下还有更多场景化清单vm-alpine-datavolume.yaml、vm-cirros-with-sidecar-hook-configmap.yaml、vm-pool-cirros.yaml等适合进一步对照学习 template 与 DataVolume、sidecar 等特性的组合用法。延伸阅读VirtualMachine 与 VirtualMachineInstance 的完整 API 类型定义staging/src/kubevirt.io/api/core/v1/types.goVM 控制器实现与单测pkg/virt-controller/watch/vm/vm.go、pkg/virt-controller/watch/vm/vm_test.goOpenAPI 规范可用于生成客户端api/openapi-spec/swagger.json各类 VM 示例清单examples/VM 配置相关的使用文档docs/vm-configuration.md、docs/virtual-machine.md注仓库 docs 根目录另有一份同名使用向文档与本文开发者向文档互补。赞分享云原生【免费下载链接】kubevirtKubernetes Virtualization API and runtime in order to define and manage virtual machines.项目地址https://gitcode.com/gh_mirrors/ku/kubevirt点击查看免费下载相关推荐如何用 ticket-purchase 自动抢大麦门票一份从零开始的完整指南如何用 ticket purchase 自动抢大麦门票一份从零开始的完整指南 热门演出开售那几分钟你盯着页面疯狂点击票还是秒没ticket purcha云原生Ceph Watch/Notify 机制深度解析从 librados 对象通知接口到 OSD 侧状态机实现Ceph Watch/Notify 机制深度解析从 librados 对象通知接口到 OSD 侧状态机实现 导读 Watch/Notify 是 Ceph R存储分布式文件系统对象存储后端高可用Gyroflow镜头校准深度解析高级配置与参数调优技术实践Gyroflow镜头校准深度解析高级配置与参数调优技术实践 Gyroflow作为一款基于陀螺仪数据的专业视频稳定软件其镜头校准功能是实现高精度防抖的核心技术视频处理桌面应用音视频上一篇Calico CI 故障复现指南在 GCP VM 上复现 Felix 测试失败含 BPF 内核校验器问题下一篇解锁本地语音转文字whisper.cpp全场景应用指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表