简介这份资源面向 Kubernetes 运维工程师、云原生网络开发者以及正在选型容器网络方案的技术团队系统讲解 CNCF 沙盒项目 Kube-OVN 的整体架构与落地实践。内容围绕其三大优势展开子网管理、静态 IP 分配、VPC 多租户、跨集群互联、ACL、流量镜像等丰富网络虚拟化功能借助 eBPF、DPDK、SmartNIC Offload 及 OVN 流表裁剪实现接近主机网络的延迟与吞吐并支撑数千节点、数万 Pod 的大规模集群一键安装脚本、Grafana 监控面板与 kubectl-ko 插件则显著降低日常运维门槛。资源包为 1 个 docx 文档约 1.77MB结构紧凑涵盖组件分类、安装环境与流程、kube-ovn-controller 与 kube-ovn-cni 等核心组件职责以及 LoadBalancer、EIP/SNAT、集中式网关、Pod 级 QoS 等功能验证要点。目前已有 433 人学习适合希望深入理解 Kube-OVN 控制平面与数据平面协作机制、快速搭建生产级容器网络的读者参考。1. 从一次 Pod 跨节点不通说起kube-ovn 到底在解决什么很多团队第一次认真看 kube-ovn都不是主动选型而是被一个具体故障逼出来的两个节点上的 Podping不通kubectl get pod一切正常describe也看不出问题最后发现是底层 OVS 流表没下发对。Kubernetes 自带的网络方案在中小规模够用但一旦你要做多租户隔离、固定 IP、子网规划、VPC 互通、QoS 限速原生 CNI 就开始捉襟见肘。kube-ovn 就是在这个缝隙里长出来的它把 OVNOpen Virtual Network这套成熟的 SDN 控制面和 OVSOpen vSwitch这套数据面整体搬进了 Kubernetes让集群网络从「能通就行」变成「可编排、可观测、可治理」。它由 CNCF 孵化定位是面向企业的 Kubernetes 网络编排系统。和 Calico、Cilium 这类以路由或 eBPF 为核心的方案不同kube-ovn 走的是经典 SDN 路线控制面用 OVN 做逻辑网络抽象数据面用 OVS 做转发再通过 CNI 插件把 Pod 网络接进来。这意味着你能拿到子网、VPC、静态 IP、ACL、NAT、QoS 这些传统网络设备才有的能力而且全部用 CRD 声明式管理。适合谁适合那些已经把 Kubernetes 跑起来、开始遇到网络治理问题的团队——尤其是需要多租户、需要固定 IP 对接外部系统、需要把 K8s 网络和现有物理网络打通的场景。这篇就把这套东西从选型理由、部署、参数、排错到进阶用法按我实际踩过的路讲一遍。2. kube-ovn 的架构拆解OVN、OVS 和 CNI 各自干什么2.1 控制面与数据面的分工理解 kube-ovn先要理解它把「网络该长什么样」和「包实际怎么走」拆成了两层。控制面是 OVN它不碰数据包只负责把逻辑网络拓扑翻译成流表。OVN 里有几个核心概念Logical Switch 对应一个子网Logical Router 对应一个 VPC 内的路由域Logical Port 对应一个 Pod 的网卡。你在 Kubernetes 里创建一个 Subnet CRDkube-ovn 的控制器就会在 OVN 里建一个 Logical Switch你创建一个 Pod它就在对应 Switch 上建一个 Logical Port。数据面是 OVS它跑在每个节点上接收 OVN 下发的流表真正决定一个包从 veth 出来之后往哪走。节点上的ovn-controller负责把 OVN 北向数据库的变更翻译成本地 OVS 流表。所以当你发现 Pod 不通时排查链路是CNI 有没有分配 IP → OVN 北向有没有对应 Logical Port → 节点 ovn-controller 有没有把流表下发到 OVS → OVS 流表里有没有匹配规则。这条链路任何一环断了包就丢了。CNI 插件是 kube-ovn 和 kubelet 之间的接口。kubelet 创建 Pod 时调用 CNIkube-ovn 的 CNI 二进制负责创建 veth pair、把一端塞进 Pod 的 netns、配置 IP 和路由另一端接到节点上的 OVS 网桥。默认网桥是br-intPod 的流量从这里进入 OVS 流水线。2.2 一次 Pod 创建背后的完整链路把上面三层串起来看一次 Pod 创建kubelet 调 CNI → kube-ovn CNI 向 kube-ovn-controller 请求 IP → controller 在对应 Subnet 里分配 IP 并在 OVN 北向建 Logical Port → OVN 北向同步到南向 → 节点 ovn-controller 收到变更生成 OVS 流表 → OVS 开始按流表转发这个 Pod 的流量。整个过程是异步的这也是为什么有时候 Pod 已经 Running但网络还没通——流表下发有延迟。这个异步特性带来一个很实际的排查习惯不要只看 Pod 状态要看 OVN 和 OVS 的状态。我一般会按这个顺序查# 1. 看 Pod 的 IP 和所在子网 kubectl get pod -o wide -n namespace # 2. 看 kube-ovn 是否为该 Pod 建了 Logical Port kubectl get lsp -n namespace | grep pod-name # 3. 进节点看 OVS 流表是否包含该 Pod 的 IP ovs-ofctl dump-flows br-int | grep pod-ip # 4. 看 ovn-controller 日志有没有下发失败 kubectl logs -n kube-system ovn-controller-pod --tail100这几条命令覆盖了从 K8s 到 OVN 再到 OVS 的完整链路。参数上dump-flows输出很大一定要grep具体 IP否则刷屏。ovn-controller日志里如果出现failed to install flows基本就是流表下发问题常见原因是 OVS 版本和 OVN 版本不匹配。2.3 为什么选 OVN 而不是自己写控制面有人会问为什么 kube-ovn 不自己写一套控制面而要依赖 OVN我的理解是OVN 已经把逻辑网络抽象、分布式路由、ACL、NAT 这些做得很成熟而且有独立的北向数据库和南向协议天然适合做声明式网络。自己写控制面意味着要重新实现一套分布式状态同步这是巨大的工程。kube-ovn 的价值在于把 OVN 的能力「翻译」成 Kubernetes 的 CRD 和 CNI 语义而不是重新造轮子。代价是引入了额外的组件OVN 北向数据库、南向数据库、ovn-controller、OVS。这些组件本身有运维成本比如数据库的 raft 集群、ovn-controller 的版本兼容。所以 kube-ovn 更适合有一定网络运维能力的团队纯小规模测试集群用原生 CNI 可能更省事。这个取舍要在选型阶段就想清楚。3. 部署 kube-ovn从零到 Pod 互通的最小路径3.1 环境准备与前置检查部署前有几件事必须先确认否则后面全是坑。第一节点内核版本要够kube-ovn 依赖 OVS 内核模块建议 4.19 以上。第二节点上不能已经有其他 CNI 在跑否则网桥冲突。第三确认节点间网络互通OVN 的隧道默认 Geneve需要节点间能通 UDP 6081。# 检查内核版本 uname -r # 检查是否已有 OVS 网桥 ovs-vsctl show # 检查节点间 Geneve 端口是否可达在另一节点抓包 tcpdump -i any udp port 6081 -c 10如果ovs-vsctl show显示已有br-int且上面挂着其他 CNI 的端口要先清理干净。我见过最典型的翻车是集群之前装过其他 CNI卸载不彻底kube-ovn 装上去后两个 CNI 抢网桥Pod 时通时不通。所以前置检查里确认没有残留网桥和 CNI 配置比什么都重要。3.2 用官方脚本安装与关键参数kube-ovn 提供了一键安装脚本但生产环境我建议先看脚本内容再执行因为默认参数不一定适合你。核心参数集中在install.sh的环境变量里。# 下载安装脚本以实际发布版本为准这里演示参数含义 # 关键参数通过环境变量传入 export POD_CIDR10.16.0.0/16 # Pod 默认子网 export SVC_CIDR10.96.0.0/12 # Service 网段要和 kube-apiserver 一致 export JOIN_CIDR100.64.0.0/16 # 节点间隧道网段 export TUNNEL_TYPEgeneve # 隧道类型默认 geneve export NETWORK_TYPEgeneve # 网络类型 export IFACEeth0 # 节点用于隧道通信的网卡必须显式指定 # 执行安装 bash install.sh参数说明POD_CIDR是默认子网的网段后面可以再建自定义 SubnetSVC_CIDR必须和集群 Service 网段一致写错会导致 Service 不通IFACE是最容易忽略的如果不指定脚本可能选错网卡导致隧道建不起来。TUNNEL_TYPE选 geneve 还是 vxlan取决于你的网络设备支持geneve 扩展性更好vxlan 兼容性更广。安装完成后检查核心组件kubectl get pod -n kube-system | grep -E ovn|kube-ovn正常应该看到ovn-central、ovn-controller、kube-ovn-controller、kube-ovn-cni这几类 Pod 全部 Running。如果ovn-central起不来多半是 raft 集群选主问题看日志里有没有leader election相关报错。3.3 验证 Pod 互通与子网创建装完之后先别急着上业务用最小用例验证。创建一个测试 Subnet 和两个 Pod跨节点跑。# test-subnet.yaml apiVersion: kubeovn.io/v1 kind: Subnet metadata: name: test-subnet spec: cidrBlock: 10.20.0.0/24 gateway: 10.20.0.1 protocol: IPv4 namespaces: - defaultkubectl apply -f test-subnet.yaml # 创建两个跨节点 Pod kubectl run test-a --imagebusybox --overrides{spec:{nodeName:node1}} -- sleep 3600 kubectl run test-b --imagebusybox --overrides{spec:{nodeName:node2}} -- sleep 3600 # 拿到 IP 后互 ping kubectl get pod -o wide | grep test- kubectl exec test-a -- ping -c 3 test-b-ip如果 ping 不通按第 2 章的排查链路走一遍。这里有个细节Subnet 的namespaces字段决定哪些 namespace 的 Pod 能用这个子网不写的话默认子网生效。生产环境我建议每个业务 namespace 绑定独立 Subnet方便做隔离和 IP 规划。4. 子网、VPC 与固定 IPkube-ovn 的进阶网络编排4.1 多租户隔离与 VPC 划分kube-ovn 的 VPC 是逻辑路由域不同 VPC 之间默认隔离需要显式配置互通。这在多租户场景下非常有用每个租户一个 VPC各自有独立的子网和路由互不干扰。# tenant-a-vpc.yaml apiVersion: kubeovn.io/v1 kind: Vpc metadata: name: tenant-a spec: namespaces: - tenant-a --- apiVersion: kubeovn.io/v1 kind: Subnet metadata: name: tenant-a-subnet spec: cidrBlock: 10.100.0.0/24 gateway: 10.100.0.1 vpc: tenant-a namespaces: - tenant-a关键参数是vpc字段Subnet 绑定到 VPC 后这个子网的流量就在该 VPC 的路由域内。不同 VPC 的子网 CIDR 可以重叠因为逻辑上隔离。这一点比原生 CNI 强很多——原生方案里 CIDR 重叠基本就是灾难。VPC 之间要互通需要建 VPC Peering 或者通过外部网关。我一般建议默认隔离只在明确需要时开互通因为一旦互通ACL 就要仔细配否则隔离形同虚设。4.2 固定 IP 与 IP 池管理对接外部系统时经常需要 Pod 有固定 IP比如数据库白名单、监控采集目标。kube-ovn 支持通过 annotation 指定 IP。apiVersion: v1 kind: Pod metadata: name: fixed-ip-pod annotations: ovn.kubernetes.io/ip_address: 10.20.0.100 ovn.kubernetes.io/logical_switch: test-subnet spec: containers: - name: app image: nginxip_address指定固定 IPlogical_switch指定子网。注意 IP 必须在子网 CIDR 内且未被占用否则 Pod 会卡在 ContainerCreating。我踩过的坑是固定 IP 的 Pod 重建后如果旧 IP 还没释放新 Pod 会分配失败。解决方法是确认旧 Pod 完全删除、OVN 里的 Logical Port 也清理了再重建。IP 池管理上kube-ovn 支持在 Subnet 里排除特定 IP 段比如留给网关或外部设备spec: cidrBlock: 10.20.0.0/24 gateway: 10.20.0.1 excludeIps: - 10.20.0.1..10.20.0.10excludeIps支持范围写法把网关和保留地址排除掉避免分配冲突。4.3 ACL 与 QoS把网络策略落到流表kube-ovn 支持通过 ACL CRD 做细粒度访问控制比 Kubernetes 原生 NetworkPolicy 更底层。原生 NetworkPolicy 依赖 CNI 实现kube-ovn 直接把它翻译成 OVN ACL落到 OVS 流表。apiVersion: kubeovn.io/v1 kind: Acl metadata: name: deny-tenant-a-egress spec: action: drop direction: from-lport match: ip4.src 10.100.0.0/24 ip4.dst 10.200.0.0/24 priority: 2001direction的from-lport表示从逻辑端口出方向match是 OVN 流表语法。优先级数值越大越优先。QoS 则通过 Subnet 或 Pod 的 annotation 配置限速annotations: ovn.kubernetes.io/ingress_rate: 100 ovn.kubernetes.io/egress_rate: 100单位是 Mbps。限速在 OVS 层做对 Pod 透明。注意限速值不要设得太低否则会影响健康检查等基础流量。5. 避坑与排查kube-ovn 最常见的 5 个翻车现场5.1 Pod 一直 ContainerCreating事件显示 IP 分配失败现象Pod 卡在 ContainerCreatingkubectl describe显示failed to allocate ip。原因通常是子网 IP 耗尽或者固定 IP 冲突或者 Subnet 的 namespace 绑定不对。解决先看 Subnet 剩余 IPkubectl get subnet name -o yaml看status里的可用数如果是固定 IP 冲突删掉旧 Pod 等 Logical Port 清理如果是 namespace 绑定问题检查 Subnet 的namespaces字段是否包含目标 namespace。5.2 跨节点 Pod 不通同节点正常现象同节点 Pod 互通跨节点不通。原因多半是隧道没建起来或者IFACE选错。解决在节点上ovs-vsctl show看隧道端口ip -d link show看 Geneve 接口确认IFACE指定的网卡是节点间实际通信的网卡。我遇到过节点有多张网卡安装时没指定IFACE脚本选了管理网卡但业务流量走另一张导致隧道不通。5.3 Service 不通但 Pod 直连正常现象Pod 之间直连正常但访问 Service 不通。原因通常是SVC_CIDR和 kube-apiserver 的 Service 网段不一致或者 kube-proxy 和 kube-ovn 的 Service 实现冲突。解决核对SVC_CIDR如果 kube-ovn 接管了 Service要确认 kube-proxy 的模式。kube-ovn 支持用 OVN 做 Service 负载均衡这时 kube-proxy 可以不用或改用其他模式。5.4 ovn-central 频繁重启raft 选主失败现象ovn-centralPod 反复重启日志里leader election报错。原因通常是三个副本之间时钟不同步或者网络不通。解决确认节点 NTP 同步确认ovn-central副本间 6641/6642 端口互通。raft 对时钟敏感时钟漂移大会导致选主震荡。5.5 升级后流表异常Pod 网络抖动现象升级 kube-ovn 或 OVS 后部分 Pod 网络抖动。原因通常是版本不兼容OVN 和 OVS 有版本对应关系。解决升级前查兼容矩阵先升级控制面再升级数据面逐节点滚动。升级期间避免同时改网络配置否则出问题很难定位是升级还是配置导致。6. 用 OVN 追踪流表定位疑难杂症前面讲的排查偏「看状态」但有些问题状态全正常就是不通这时候要靠 OVN 的追踪工具。ovn-trace能模拟一个包在逻辑网络里的完整路径告诉你它在哪一跳被 drop 了。这是我压箱底的技巧比盲猜流表高效得多。用法是先在 OVN 北向数据库里找到源 Pod 的 Logical Port然后构造一个 trace# 找到源 Pod 的 Logical Port 和目的 IP kubectl get lsp -n default | grep test-a # 用 ovn-trace 模拟从源到目的的路径 ovn-trace --ctnew source-lsp \ inportsource-lsp eth.dstdst-mac ip4.dstdst-ip输出会逐跳显示经过哪些 Logical Switch、Logical Router以及在哪条 ACL 被 drop。如果看到drop且带 ACL 名字直接去查那条 ACL 的 match 条件。如果看到output to tunnel说明逻辑路径没问题问题在物理层或 OVS 流表。几个参数要点--ctnew表示模拟新连接如果要模拟已建立连接用--ctestinport必须写源 Logical Port 名ip4.dst写目的 IP。输出里next表示下一跳drop表示被丢弃output表示从某个端口出去。我一般会先用ovn-trace确认逻辑路径如果逻辑路径通但实际不通再去节点上看 OVS 流表# 看 br-int 上是否有匹配目的 IP 的流表 ovs-ofctl dump-flows br-int table0 | grep dst-ip如果 OVS 流表里没有对应规则说明 ovn-controller 没下发去看它的日志。如果有规则但包还是丢用ovs-appctl ofproto/trace做数据面追踪ovs-appctl ofproto/trace br-int \ in_portport,dl_srcsrc-mac,dl_dstdst-mac,ip,nw_srcsrc-ip,nw_dstdst-ip这个命令会模拟包在 OVS 流水线里的处理输出最终动作。两个 trace 配合逻辑面和数据面都能覆盖基本没有定位不了的问题。最后说个习惯我每次改网络配置前都会先ovn-trace存一份正常状态的路径改完再 trace 对比。网络问题最怕「改了什么忘了」有对比就有后悔药。这套方法我用了两年比任何监控都直接。希望帮到你。本文还有配套的精品资源点击获取