- 云原生
【免费下载链接】kubevirt
Kubernetes Virtualization API and runtime in order to define and manage virtual machines.
导读
KubeVirt 通过 hook sidecar 接口将passt网络绑定插件注册为一种网络绑定机制,在虚拟机(VMI)启动时由 sidecar 把 pod 网络接口改造成基于passt的 vhost-user 后端,从而让非 root 的 virt-launcher 进程也能以无特权方式收发 pod 网络流量。本文以 cmd/sidecars/network-passt-binding/README.md 为主线,结合仓库内 sidecar 服务端、domain 配置器、CNI 辅助插件与网络绑定插件的通用机制源码,完整讲解passt绑定的注册方法、VMI 声明方式、底层工作原理、端口转发与 Istio 兼容行为,以及配套 CNI 的部署方式。读完本文,你将能够在 KubeVirt 集群中注册并使用passt绑定插件,并理解其从 VMI spec 到 libvirt domain XML 的完整改造链路。
注意:
passt网络绑定目前仅支持 pod 网络接口(对应 VMI 的pod: {}网络),不适用于 multus 等其他网络类型。
一、Passt 绑定插件的定位与整体架构
1.1 什么是 Passt 绑定
passt(networking/passt)是一个无特权模式的网络地址转换与数据通路工具。KubeVirt 将passt包装为一种网络绑定插件:VMI 不再使用传统的 tap 设备挂接到 bridge,而是通过 libvirt 的vhostuser接口类型把 pod 网络接口直接暴露给passt后端,由passt在宿主命名空间内完成数据包转发。
从源码注释(cmd/sidecars/network-passt-binding/domain/configurator.go)可以看到 sidecar 会把 passt 日志写入/var/run/kubevirt/passt.log,供 KubeVirt 消费和记录:
const ( //nolint:gosec // PasstLogFilePath passt log file path Kubevirt consume and record PasstLogFilePath = "/var/run/kubevirt/passt.log" )1.2 与 KubeVirt hook sidecar 机制的关系
网络绑定插件属于 KubeVirt 的 hook sidecar 机制。KubeVirt 在定义域(define domain)阶段会调用注册的 sidecar,sidecar 以 gRPC 协议监听 unix socket 并对外暴露OnDefineDomain钩子;virt-launcher 在生成域配置之后、交给 libvirt 之前调用该钩子,让插件有机会修改(mutate)domain XML。
在 docs/network/network-binding-plugin.md 中描述了这一机制:
网络绑定 sidecar 通常会在
OnDefineDomain钩子中修改域配置(domain configuration)……sidecar 的实现逻辑需要添加到OnDefineDomain中。
passtsidecar 正是这一机制的典型实现。从 cmd/sidecars/network-passt-binding/main.go 可以看到它的启动流程:
- 在共享目录
hooks.HookSocketsSharedDirectory(即/var/run/kubevirt-hooks)下创建名为passt.sock的 unix socket; - 注册
InfoServer(对外声明自己支持的 API 版本为v1alpha3)与V1alpha3Server(实现具体的回调); - 从环境变量
NETWORK_BINDING_PLUGIN_NAME(常量定义见 pkg/hooks/hooks.go)读取绑定的插件名,未设置时默认为passt; - 启动 gRPC 服务并等待信号或
Shutdown回调触发优雅退出。
二、注册 Passt 绑定插件
在 KubeVirt CR 中通过spec.configuration.network.binding注册passt绑定插件,并指定 sidecar 镜像。以下示例与 cmd/sidecars/network-passt-binding/README.md 中的注册方式一致:
apiVersion: kubevirt.io/v1 kind: KubeVirt metadata: name: kubevirt namespace: kubevirt spec: configuration: network: binding: passt: sidecarImage: registry:5000/kubevirt/network-passt-binding:devel # ...参数说明:
| 字段 | 说明 |
|---|---|
configuration.network.binding.passt | 以插件名为 key 声明一个网络绑定插件,passt即该插件的注册名 |
sidecarImage | 承载 passt sidecar 逻辑的容器镜像,需要在 virt-launcher pod 所在的节点可拉取(私有仓库时需提前配置 imagePullSecret 或节点可访问) |
需要注意的是,sidecarImage中的镜像即 cmd/sidecars/network-passt-binding 目录所构建的镜像:它以main.go为入口启动 gRPC 服务,向 KubeVirt 声明自己支持OnDefineDomain与Shutdown两个钩子点(见 cmd/sidecars/network-passt-binding/server/server.go 的Info实现)。
三、在 VMI 中启用 Passt 绑定
注册插件后,在 VMI spec 中把接口的binding.name指向passt,并让该接口挂接 pod 网络:
apiVersion: kubevirt.io/v1 kind: VirtualMachineInstance metadata: name: vmi-passt spec: domain: devices: interfaces: - name: passt binding: name: passt # ... networks: - name: passt-net pod: {} # ...字段对应关系:
interfaces[].binding.name: passt:声明该接口使用已注册的passt绑定插件;networks[].name与接口name一致(示例中passt与passt-net需一一对应,实际使用时接口的name与网络的name必须匹配);networks[].pod: {}:pod 网络,这是 passt 绑定目前唯一支持的网络类型(README 明确强调)。
3.1 sidecar 对绑定声明的校验
从源码看,sidecar 在收到OnDefineDomain调用后会做严格的合法性校验(cmd/sidecars/network-passt-binding/domain/configurator.go):
- 在 VMI 的网络列表中查找 pod 网络(
LookupPodNetwork),找不到则报pod network not found; - 按网络名查找对应的接口,找不到则报
no interface found; - 校验该接口的
binding.name是否为passt(即 sidecar 从环境变量读到的绑定插件名),否则报interface %q is not set with Passt network binding plugin; - 从接口状态中查找主网络接口名(
PodInterfaceName),后续用它作为 passt 后端的设备名。
这解释了为什么 README 要求 pod 网络接口必须显式设置binding.name: passt:sidecar 只会对满足该条件的接口执行改造。
四、底层工作原理:从 VMI spec 到 domain XML
4.1 调用链
OnDefineDomain钩子的完整调用链如下(对应 cmd/sidecars/network-passt-binding/server/server.go):
- KubeVirt virt-launcher 生成原始 domain XML,通过 gRPC 传入;
- sidecar 将 VMI 反序列化为
VirtualMachineInstance对象,并读取UseVirtioTransitional与 Istio 注入注解; - 调用
domain.NewPasstNetworkConfigurator(...)构造配置器; - 调用
callback.OnDefineDomain(domainXML, configurator)完成 XML 反序列化、变更与重新序列化(实现见 cmd/sidecars/network-passt-binding/callback/callback.go)——注意这里会显式补回 qemu schema 命名空间,否则部分 domain 参数会因命名空间缺失而失效; - 返回修改后的 domain XML 给 virt-launcher。
4.2 域配置的改造内容
Mutate方法(cmd/sidecars/network-passt-binding/domain/configurator.go)主要做两件事:
(1)替换接口定义:按 VMI 接口的别名(alias)查找 domain XML 中对应的接口并整体替换为生成的 passt 接口;若不存在则追加。generateInterface(同文件 L141-L195)生成的接口具备以下特征:
Type: vhostuser,Source.Device指向主 pod 接口名;Backend.Type: passt,并携带日志文件PasstLogFilePath;- 模型(model)默认取
virtio:当UseVirtioTransitional开启时映射为virtio-transitional,否则为virtio-non-transitional(L151-L168); - 继承 VMI 上声明的
pciAddress、macAddress、acpiIndex。
(2)强制内存共享:passt 后端要求内存为共享模式。若 domain 已存在非shared的 memory backing access mode,Mutate会直接报错memory backing access mode must be 'shared';否则补齐MemoryBacking.Access.Mode = shared、MemoryBacking.Source.Type = memfd(L116-L125)。这也是使用 passt 绑定时的隐性资源要求:需保证 virt-launcher 能提供 memfd 共享内存。
4.3 端口转发(Port Forward)的生成
generatePortForward(cmd/sidecars/network-passt-binding/domain/configurator.go)根据 VMI 接口声明的ports生成 passt 的端口转发规则:
- 未声明任何端口时,默认生成
tcp与udp两个无范围的转发条目(即全端口转发); - 声明了端口时,按协议(默认
tcp)分组生成带Start起始端口的 range; - 非法端口号或 unsupported 协议会被日志记录并跳过(端口号合法性由 admission webhook 前置校验,因此源码中注释说明非法分支实际不可达);
- 与 Istio 兼容:当 VMI 带有
sidecar.istio.io/inject: "true"注解时,会把istio.ReservedPorts()中的保留端口以Exclude: "yes"的方式排除在 TCP 转发之外,避免与 Istio sidecar 的端口冲突(L200-L204)。
五、配套 CNI:passt-binding-cni
passt 绑定还附带一个 CNI 插件passt-binding-cni,用于在 pod 网络命名空间中调整 sysctl 参数,使非 root 的 virt-launcher(UID 107)也能使用 passt 完成低端口监听与 ping 报文收发。
5.1 CNI 插件行为
从 cmd/cniplugins/passt-binding/pkg/plugin/plugin.go 的实现看,ADD操作会在目标网络命名空间内执行:
net.ipv4.ip_unprivileged_port_start = 0:允许非特权进程绑定任意端口(低端口不需要 root 权限);net.ipv4.ping_group_range = 107 107:把 UID 107(virtLauncherUserID)加入 ping 组,允许其发送 ICMP echo。
sysctl 的写入通过 cmd/cniplugins/passt-binding/pkg/plugin/sysctl/sysctl.go 封装,最终落到底层sysctl工具;DEL与CHECK目前为空实现。该 CNI 还支持通过cni-args传入logicNetworkName用于日志标识(config.go)。
5.2 部署方式
仓库提供了安装 CNI 的 DaemonSet 清单 cmd/cniplugins/passt-binding/passt-binding-ds.yaml:
apiVersion: apps/v1 kind: DaemonSet metadata: name: passt-binding-cni namespace: kubevirt spec: # ... template: spec: containers: - name: installer image: registry:5000/kubevirt/network-passt-binding-cni:devel command: [ "/bin/sh", "-ce" ] args: - | ls -la "/cni/kubevirt-passt-binding" cp -f "/cni/kubevirt-passt-binding" "/opt/cni/bin" echo "passt binding CNI plugin installation complete..sleep infinity" sleep 2147483647 securityContext: privileged: true volumeMounts: - name: cnibin mountPath: /opt/cni/bin volumes: - name: cnibin hostPath: path: /opt/cni/bin该 DaemonSet 以特权容器把编译好的kubevirt-passt-binding二进制拷贝到各节点的/opt/cni/bin,从而让节点上的 CNI 链(如 Multus)能够调用它。这意味着使用 passt 绑定前需要在集群节点上安装该 CNI 二进制,否则 virt-launcher pod 网络命名空间不会获得上述 sysctl 调整,passt 的无特权数据通路可能受限。
六、Hook 点与生命周期
passtsidecar 通过InfoServer.Info声明了两个钩子点(cmd/sidecars/network-passt-binding/server/server.go):
| Hook 点 | 优先级 | 作用 |
|---|---|---|
OnDefineDomain | 0 | 在域定义阶段修改 domain XML,注入 vhost-user/passt 接口与共享内存配置 |
Shutdown | 0 | 收到 shutdown 通知后向Done通道发送信号,触发 gRPC 服务优雅退出 |
生命周期行为:
OnDefineDomain:解析 VMI → 校验绑定声明 → 构造配置器 → 回调执行 XML 变更(见 callback.go);Shutdown:记录日志Shutdown passt network binding并写入Done通道(server.go L125-L129);- 服务退出:
waitForShutdown同时监听操作系统信号(SIGHUP/SIGINT/SIGTERM/SIGQUIT)、gRPC 服务错误与 shutdown 通道,任一触发后调用server.GracefulStop()(server.go L131-L161)。
七、使用前提与限制汇总
- 仅支持 pod 网络:README 明确指出 passt 绑定只适用于 pod 网络接口(
pod: {}),multus 等附加网络不在支持范围; - 需要注册 sidecar 镜像:必须先在 KubeVirt CR 的
configuration.network.binding中注册passt并指定可拉取的sidecarImage; - 需要安装 CNI 插件:集群节点需通过 passt-binding-ds.yaml 之类的 DaemonSet 部署
kubevirt-passt-bindingCNI 到/opt/cni/bin; - 内存共享要求:domain 必须满足
memoryBacking.access.mode = shared且source.type = memfd,若已有冲突配置 sidecar 会拒绝启动(报错并保持原 XML); - Istio 兼容:启用 Istio 注入时 passt 会排除 Istio 保留端口,避免端口冲突;
- 接口模型:默认使用 virtio 模型,开启
useVirtioTransitional时映射为virtio-transitional。
八、深入阅读
- 本文主体文档:cmd/sidecars/network-passt-binding/README.md
- Sidecar 入口与 gRPC 服务:cmd/sidecars/network-passt-binding/main.go、cmd/sidecars/network-passt-binding/server/server.go
- 域配置改造与端口转发:cmd/sidecars/network-passt-binding/domain/configurator.go
- XML 回调处理:cmd/sidecars/network-passt-binding/callback/callback.go
- Sidecar 测试用例:cmd/sidecars/network-passt-binding/domain/configurator_test.go、cmd/sidecars/network-passt-binding/callback/callback_test.go
- CNI 插件:cmd/cniplugins/passt-binding/pkg/plugin/plugin.go、cmd/cniplugins/passt-binding/pkg/plugin/config.go
- CNI 安装清单:cmd/cniplugins/passt-binding/passt-binding-ds.yaml
- 网络绑定插件通用机制:docs/network/network-binding-plugin.md
- 云原生
【免费下载链接】kubevirt
Kubernetes Virtualization API and runtime in order to define and manage virtual machines.
相关推荐
Babel 提案插件 @babel/plugin-proposal-discard-binding 全解析:void 绑定语法、配置与转换原理
Babel 提案插件 @babel/plugin proposal discard binding 全解析:void 绑定语法、配置与转换原理 @babel/p
编译器开发工具Babel Codemod 插件 @babel/plugin-codemod-optional-catch-binding 实战指南:自动移除未使用的 catch 绑定
Babel Codemod 插件 @babel/plugin codemod optional catch binding 实战指南:自动移除未使用的 catc
编译器开发工具Babel 可选 catch 绑定转换插件 @babel/plugin-transform-optional-catch-binding 完整指南
Babel 可选 catch 绑定转换插件 @babel/plugin transform optional catch binding 完整指南 本文以 Ba
编译器开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考