跳转至

Kubernetes CNI 部署与调优实践

这篇文章解决什么问题

如果你要去做云服务实施工程师,对方要求“有 CNI 部署调优实践经验”,那面试官真正想确认的通常不是你会不会背 CNI = Container Network Interface,而是想知道:

  • 你是否理解 Kubernetes Pod 网络为什么要靠 CNI 实现
  • 你是否知道不同 CNI 插件的网络模型差异
  • 你是否能把 CNI 部署起来,并知道部署前要检查什么
  • 你是否排查过 Pod 不通、Service 不通、DNS 慢、跨节点丢包这类问题
  • 你是否知道 MTU、iptables、IPVS、eBPF、NetworkPolicy、Pod CIDR 这些关键词背后的工程影响

这篇文章会按“理解原理 -> 部署实施 -> 调优排障 -> 面试表达”的顺序整理。目标不是一次变成网络专家,而是先建立一套能落地、能解释、能排障的 CNI 知识框架。

CNI 到底是什么

CNI,全称 Container Network Interface,是容器网络接口规范。它本身不是某一个具体网络组件,而是一套标准接口。

在 Kubernetes 里,Pod 创建出来以后,不能只是有容器进程,还必须拥有符合 Kubernetes 网络模型的网络能力。这里至少包括:

  • 每个 Pod 有自己的 IP
  • Pod 之间默认可以直接互通
  • Pod 访问 Service 能被正确转发
  • 跨节点 Pod 能互通
  • 网络策略可以按命名空间、Pod 标签、端口等维度做访问控制

Kubernetes 自己并不直接实现这些底层网络细节,而是把“给 Pod 接入网络”的动作交给 CNI 插件。常见插件包括 FlannelCalicoCiliumCanalWeave Net 等。

更准确地说,CNI 负责的是“容器网络命名空间如何接入宿主机和集群网络”。当 kubelet 创建 Pod sandbox 时,会通过容器运行时调用 CNI 插件。CNI 插件会完成分配 IP、创建 veth、配置路由、设置网桥或隧道、写入 iptables 或 eBPF 规则等动作。

Kubernetes 网络模型

理解 CNI 之前,先要理解 Kubernetes 对网络的基本假设。

Kubernetes 的 Pod 网络模型可以概括成三句话:

  • 每个 Pod 都有独立 IP
  • 任意 Pod 可以通过对方 Pod IP 直接通信,不需要 NAT
  • 节点上的组件也可以和 Pod IP 通信

这套模型看起来简单,但工程上并不简单。因为 Pod 会分布在不同节点上,节点之间可能在同一个二层网络,也可能跨交换机、跨可用区、跨 VPC,甚至底层网络不支持直接路由 Pod CIDR。

所以 CNI 插件的核心任务就是让下面这件事成立:

Pod A 10.244.1.10 on Node 1
        |
        | 跨节点通信
        v
Pod B 10.244.2.20 on Node 2

不同 CNI 插件的差异,本质上就是它们用什么方式让 Pod IP 在集群里可达。

Pod 创建时 CNI 做了什么

一次典型 Pod 启动过程中,网络相关流程大致如下:

用户提交 Pod YAML
    |
apiserver 写入期望状态
    |
scheduler 把 Pod 调度到某个 Node
    |
kubelet 发现本节点有新 Pod
    |
containerd 创建 Pod sandbox
    |
containerd 调用 CNI 插件
    |
CNI 插件分配 IP、创建网卡、配置路由和规则
    |
Pod 进入 Running

在节点上,Pod 一般运行在自己的 network namespace 里。CNI 会创建一对 veth pair,一端放进 Pod 的网络命名空间,作为 Pod 内看到的 eth0;另一端留在宿主机上,连接到 Linux bridge、路由表、隧道设备或 eBPF datapath。

可以用下面的简化图理解:

Pod network namespace
  eth0 10.244.1.10
    |
    | veth pair
    |
Host network namespace
  vethxxxx
    |
    | bridge / route / vxlan / eBPF
    |
Node network

如果你能把这张图讲清楚,面试官基本会认为你不是只背概念,而是真的理解 Pod 网络是怎么接到宿主机网络里的。

CNI 配置文件在哪里

在大多数 Linux 节点上,CNI 相关文件通常位于:

/etc/cni/net.d/
/opt/cni/bin/
/var/lib/cni/

常见含义如下:

  • /etc/cni/net.d/ 保存 CNI 配置文件,例如 10-calico.conflist
  • /opt/cni/bin/ 保存 CNI 二进制插件,例如 bridgeloopbackcalico
  • /var/lib/cni/ 保存 IP 分配记录等运行时状态

排查 CNI 问题时,这几个目录很重要。比如节点重装、CNI 切换、IP 分配异常时,经常需要检查这里是否存在旧配置、旧缓存或多个 CNI 配置文件冲突。

主流 CNI 插件对比

Flannel

Flannel 是入门最常见的 CNI 之一,部署简单,理解成本低,适合实验环境、小规模集群或对网络策略要求不高的场景。

Flannel 常见后端包括:

  • vxlan:通过 VXLAN 隧道封装跨节点流量,最常见
  • host-gw:通过宿主机路由转发,性能较好,但要求节点二层可达
  • udp:老方案,性能较差,生产环境很少使用

Flannel 的优点是简单稳定,缺点是默认不提供完整 NetworkPolicy 能力。如果实施场景要求网络隔离、租户隔离、东西向访问控制,Flannel 往往不够。

Calico

Calico 是生产环境非常常见的 CNI。它的核心特点是基于三层路由模型,可以支持 BGP,也可以使用 IP-in-IP 或 VXLAN 封装。

Calico 的优势:

  • 支持 Kubernetes NetworkPolicy
  • 支持 Calico 自己更强的网络策略能力
  • 性能和可控性较好
  • 适合生产集群、多租户集群和需要访问控制的场景

Calico 常见模式:

  • BGP:通过 BGP 分发 Pod 路由,适合网络条件可控的生产环境
  • IPIP:通过 IP-in-IP 封装跨节点流量,兼容性较好
  • VXLAN:通过 VXLAN 封装跨节点流量,不依赖 BGP
  • CrossSubnet:同网段不封装,跨网段才封装,兼顾性能和兼容性

如果面试问“你用过哪个 CNI”,选择 Calico 来讲通常更容易展开,因为它既能讲部署,也能讲 NetworkPolicy、BGP、MTU、封装模式和排障。

Cilium

Cilium 是近年来很受关注的 CNI,核心技术是 eBPF。它可以用 eBPF 替代一部分传统 iptables 转发路径,在可观测性、安全策略和性能方面都有优势。

Cilium 常见能力:

  • 基于 eBPF 的网络转发
  • 支持 L3/L4/L7 网络策略
  • 支持 Hubble 做网络可观测性
  • 可替代 kube-proxy
  • 适合云原生平台、微服务治理、安全可观测要求较高的场景

Cilium 的学习曲线比 Flannel 和 Calico 更高,但如果你目标是云服务实施工程师,了解 Cilium 是加分项。尤其是现在很多云厂商和大规模集群开始关注 eBPF 网络方案。

CNI 选型思路

实施项目里选 CNI,不应该只看“哪个更流行”,而要看底层网络、隔离要求、性能要求和团队维护能力。

可以按下面几个问题判断:

  • 是否需要 NetworkPolicy
  • 节点是否在同一个二层网络
  • 是否允许 BGP 和路由打通
  • 是否跨可用区、跨网段、跨 VPC
  • 是否对性能和延迟敏感
  • 是否需要网络可观测性
  • 团队是否熟悉 eBPF、BGP、iptables、Linux 网络排障

常见建议:

  • 学习环境、小规模演示:Flannel
  • 通用生产集群:Calico
  • 需要强网络策略、云原生可观测、eBPF 能力:Cilium
  • 云厂商托管 Kubernetes:优先使用云厂商官方 CNI,例如 AWS VPC CNI、Azure CNI、Terway 等

部署前要确认什么

部署 CNI 之前,一定要先确认集群的网络规划。很多 CNI 问题不是安装命令错了,而是一开始网段规划就有问题。

Pod CIDR

Pod CIDR 是 Pod IP 使用的地址段。它不能和下面这些网段冲突:

  • 节点物理网段
  • Service CIDR
  • VPC CIDR
  • 机房已有内网网段
  • VPN、专线、对端系统网段

例如:

Node CIDR:    10.0.0.0/16
Service CIDR: 10.96.0.0/12
Pod CIDR:     10.244.0.0/16

如果 Pod CIDR 和已有内网冲突,后面可能出现非常隐蔽的问题:某些外部服务访问不了、跨网络访问走错路由、Pod 到机房数据库偶发不通。

Service CIDR

Service CIDR 是 Kubernetes ClusterIP 使用的地址段,一般在集群初始化时确定。它也不能和 Pod CIDR、节点网段、已有业务网段冲突。

Service CIDR 后期修改成本很高,生产环境要在初始化前确认清楚。

MTU

MTU 是 CNI 调优里非常容易被忽略的一点。

如果 CNI 使用 VXLAN、IPIP、Geneve 等封装方式,会额外增加报文头开销。底层网卡 MTU 如果是 1500,Pod 侧 MTU 就不能也简单设置成 1500,否则可能出现分片、丢包、连接卡顿、TLS 握手失败等问题。

常见经验值:

Underlay MTU 1500
VXLAN overhead 50
Pod MTU usually 1450

不同插件和云厂商环境会有差异,实施时要查官方建议,并结合 ping -M do -stracepath、业务压测确认。

内核参数

部署前常见检查项:

sysctl net.ipv4.ip_forward
sysctl net.bridge.bridge-nf-call-iptables
sysctl net.bridge.bridge-nf-call-ip6tables
lsmod | grep br_netfilter

常见要求:

net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1

这些参数会影响 Linux 转发和 bridge 流量进入 iptables 的行为。不同发行版、不同 kubeadm 版本、不同 CNI 对这些参数的依赖不完全一样,但作为实施工程师,至少要知道它们和 Pod 网络转发有关。

以 Calico 为例的部署流程

下面用 Calico 举例说明 CNI 部署思路。实际生产部署时建议以官方文档和目标 Kubernetes 版本为准。

1. 初始化集群时指定 Pod CIDR

如果使用 kubeadm,可以在初始化时指定:

kubeadm init --pod-network-cidr=192.168.0.0/16

Calico 默认常见 Pod CIDR 是 192.168.0.0/16,但生产环境不一定照抄,应该根据企业内网规划调整。

2. 安装 Calico

常见方式是应用官方 manifest 或使用 Operator。

kubectl apply -f calico.yaml

安装后检查:

kubectl get pods -n kube-system | grep calico
kubectl get nodes -o wide
kubectl describe node <node-name>

重点看:

  • calico-node 是否 Running
  • 节点是否从 NotReady 变为 Ready
  • Pod 是否能获得 IP
  • CoreDNS 是否正常启动
  • 跨节点 Pod 是否互通

3. 验证 Pod 网络

可以创建两个测试 Pod,分别调度到不同节点,然后互相访问。

kubectl run test-a --image=busybox:1.36 -- sleep 3600
kubectl run test-b --image=busybox:1.36 -- sleep 3600
kubectl get pod -o wide
kubectl exec -it test-a -- ping <test-b-pod-ip>

还要验证 Service:

kubectl expose pod test-b --port=80 --target-port=80
kubectl get svc
kubectl exec -it test-a -- wget -S -O- http://<service-cluster-ip>

如果 Pod IP 能通但 Service 不通,问题可能不在 CNI 本身,而在 kube-proxy、iptables、IPVS、CoreDNS 或 Service Endpoints。

CNI 调优关注点

封装模式

封装模式直接影响性能、兼容性和网络复杂度。

以 Calico 为例:

  • IPIP Always:所有跨节点流量都封装,兼容性好,但有额外开销
  • IPIP CrossSubnet:同网段不封装,跨网段封装
  • VXLAN Always:使用 VXLAN 封装,常见于不方便使用 BGP 的环境
  • BGP:直接通过路由打通 Pod CIDR,性能好,但对网络规划和运维能力要求更高

实施建议是:如果客户网络能力一般、项目交付周期紧,优先选择兼容性更好的封装方案;如果是自建机房、大规模生产集群、网络团队能配合,则可以考虑 BGP 或 CrossSubnet 来降低封装开销。

MTU 优化

MTU 不合理的表现经常不是“完全不通”,而是:

  • 小包能通,大包不通
  • ping 正常,HTTP 上传卡住
  • TLS 握手偶发失败
  • 跨节点访问比同节点访问更容易出问题
  • 大量重传导致吞吐下降

排查命令:

ip link show
tracepath <pod-ip>
ping -M do -s 1472 <target-ip>
ping -M do -s 1420 <target-ip>

如果底层 MTU 是 1500,而 CNI 使用 VXLAN,Pod MTU 设置到 1450 往往更稳。云环境里还要考虑云厂商 VPC、Overlay 网络、负载均衡、专线网关的限制。

kube-proxy 模式

kube-proxy 常见模式有 iptablesipvs

iptables 模式简单通用,但 Service 数量很多时规则膨胀明显,排查也会比较痛苦。

ipvs 模式适合 Service 数量较多、并发较高的集群,性能和可观测性通常更好,但要求内核模块支持。

检查方式:

kubectl get configmap kube-proxy -n kube-system -o yaml
ipvsadm -Ln
iptables-save | grep KUBE-SVC

如果使用 Cilium 的 kube-proxy replacement,则要换成 Cilium 自己的诊断方式,例如 cilium statuscilium service list

NetworkPolicy

NetworkPolicy 是很多生产环境必须考虑的能力。它可以限制哪些 Pod 能访问哪些 Pod,按命名空间、标签、端口做控制。

需要注意:Kubernetes 定义了 NetworkPolicy API,但具体执行依赖 CNI 插件。不是所有 CNI 都支持 NetworkPolicy。

简单示例:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-from-frontend
  namespace: app
spec:
  podSelector:
    matchLabels:
      app: backend
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: frontend
      ports:
        - protocol: TCP
          port: 8080
  policyTypes:
    - Ingress

实施时要提醒客户:NetworkPolicy 一旦启用默认拒绝策略,很容易误伤 DNS、监控、日志采集、Ingress Controller 到后端服务的访问。上线前必须做流量梳理和灰度验证。

DNS 性能

很多人把 DNS 问题归到 CoreDNS,其实 CNI、kube-proxy、conntrack、节点负载也会影响 DNS 体验。

常见表现:

  • Pod 内解析域名慢
  • 偶发 Temporary failure in name resolution
  • CoreDNS CPU 高
  • conntrack 表满
  • NodeLocal DNSCache 未启用时高并发服务大量打到 CoreDNS

排查命令:

kubectl get pods -n kube-system -l k8s-app=kube-dns -o wide
kubectl logs -n kube-system deploy/coredns
kubectl exec -it <pod> -- nslookup kubernetes.default
conntrack -S
sysctl net.netfilter.nf_conntrack_max

调优方向:

  • 给 CoreDNS 配合理的副本数和资源限制
  • 高并发集群启用 NodeLocal DNSCache
  • 检查 conntrack 表容量
  • 避免应用频繁短连接和过度 DNS 查询

conntrack

conntrack 是 Linux 连接跟踪表,Service NAT、iptables 转发、DNS 短连接等场景都可能依赖它。

conntrack 表满时,典型现象是网络偶发失败,而且很难从应用日志直接看出来。

检查方式:

sysctl net.netfilter.nf_conntrack_max
cat /proc/sys/net/netfilter/nf_conntrack_count
dmesg | grep conntrack

如果 nf_conntrack_count 长期接近 nf_conntrack_max,就需要结合节点规格、业务连接数、DNS 行为和 Service 访问模式做调优。

常见故障排查路径

Pod 一直 ContainerCreating

先看事件:

kubectl describe pod <pod-name>

如果看到类似 CNI add failed、failed to setup network、plugin not found,就重点查:

  • CNI DaemonSet 是否正常
  • /etc/cni/net.d/ 是否有配置
  • /opt/cni/bin/ 是否有插件二进制
  • kubelet 日志是否有 CNI 错误
  • 节点是否存在旧 CNI 配置残留

常用命令:

kubectl get pods -n kube-system -o wide
journalctl -u kubelet -f
ls /etc/cni/net.d/
ls /opt/cni/bin/

Pod IP 互相不通

先判断是同节点不通,还是跨节点不通。

kubectl get pod -o wide
kubectl exec -it <pod-a> -- ping <pod-b-ip>

如果同节点通、跨节点不通,通常关注:

  • 节点之间防火墙或安全组是否放通
  • CNI 封装端口是否被拦截
  • 路由是否正确
  • MTU 是否异常
  • Calico BGP 邻居是否正常
  • VXLAN 设备是否存在

例如 VXLAN 常用 UDP 端口 4789,IPIP 使用协议号 4。云安全组或机房防火墙没放通时,会出现跨节点 Pod 不通。

Pod 能通,Service 不通

这类问题要把 CNI 和 Service 转发分开看。

检查顺序:

kubectl get svc
kubectl get endpoints
kubectl get endpointslice
kubectl get pods -o wide

如果 Endpoints 为空,说明 Service selector 没匹配到 Pod,和 CNI 没直接关系。

如果 Endpoints 正常,但 ClusterIP 不通,再看 kube-proxy:

kubectl get pods -n kube-system | grep kube-proxy
iptables-save | grep KUBE-SVC
ipvsadm -Ln

使用 Cilium 替代 kube-proxy 时,要用 Cilium 的命令检查 Service 转发。

DNS 不稳定

DNS 问题不要只盯 CoreDNS。建议按下面顺序拆:

  • Pod 到 CoreDNS Service IP 是否通
  • CoreDNS Pod 是否健康
  • CoreDNS 到上游 DNS 是否通
  • kube-proxy 或 CNI 转发是否异常
  • conntrack 是否接近上限
  • 应用是否高频创建短连接并重复解析

验证命令:

kubectl exec -it <pod> -- nslookup kubernetes.default.svc.cluster.local
kubectl exec -it <pod> -- cat /etc/resolv.conf
kubectl logs -n kube-system deploy/coredns

节点 Ready 但新 Pod 没有 IP

这种情况经常和 IPAM 有关。

IPAM 负责 IP 地址管理。不同 CNI 的 IPAM 实现不同,比如 host-local、Calico IPPool、云厂商 ENI IP 分配等。

排查方向:

  • Pod CIDR 是否耗尽
  • Calico IPPool 是否配置正确
  • 云厂商 ENI 辅助 IP 是否达到节点上限
  • /var/lib/cni/ 是否有异常缓存
  • CNI 控制器是否正常运行

云上 Kubernetes 特别要注意节点可分配 Pod 数。比如基于 ENI 的 CNI,单节点 Pod 数可能受实例规格、网卡数量和辅助 IP 数限制。

实施工程师应该怎么积累 CNI 经验

如果你现在经验不足,最有效的方式不是只看文章,而是搭一个小实验环境,把关键链路跑一遍。

建议按这个顺序练:

  1. 用 kubeadm 搭一个 2 到 3 节点集群
  2. 先安装 Flannel,观察 Pod IP、路由、veth、cni 配置文件
  3. 重建集群或清理后安装 Calico
  4. 测试同节点 Pod、跨节点 Pod、Service、DNS
  5. 开启一个 NetworkPolicy,验证访问被允许或拒绝
  6. 故意改错 MTU 或阻断 VXLAN 端口,观察故障表现
  7. 对比 iptables 和 IPVS 模式下 Service 转发规则
  8. 整理一份自己的排障记录

你不需要一开始就做特别大的项目。一个 3 节点实验集群,只要你真的看过路由表、iptables、CNI 配置、Pod 网络命名空间,就已经比单纯背概念强很多。

面试中可以怎么表达

如果面试官问:“你有没有 CNI 部署调优经验?”

可以这样答:

我做过 Kubernetes 集群 CNI 的部署和基础排障练习,主要以 Calico 为主,也了解 Flannel 和 Cilium 的差异。部署前我会先确认 Pod CIDR、Service CIDR、节点网段和客户内网是否冲突,然后根据底层网络选择封装模式,比如 VXLAN、IPIP 或 BGP。部署后会验证节点 Ready、CoreDNS、跨节点 Pod 通信、Service ClusterIP、DNS 解析和 NetworkPolicy。

调优方面我会重点关注 MTU、kube-proxy 模式、conntrack、CoreDNS 压力和 NetworkPolicy 规则影响。比如 Overlay 网络下如果底层 MTU 是 1500,Pod MTU 设置不合理就可能导致大包丢包或连接卡顿;Service 规模较大时也会关注 iptables 规则膨胀,必要时考虑 IPVS 或 eBPF 方案。

排障时我一般先拆分问题边界:Pod 创建失败先看 kubelet 事件和 CNI 插件日志;Pod IP 不通先区分同节点和跨节点;Pod 能通但 Service 不通就看 Endpoints 和 kube-proxy;DNS 慢则会同时检查 CoreDNS、Service 转发、conntrack 和节点负载。

这段回答比较稳,因为它既承认你不是在吹“大规模生产经验”,又能体现你知道实施时真正要看什么。

可落地的检查清单

部署前:

  • 确认 Kubernetes 版本和 CNI 插件版本兼容
  • 确认 Pod CIDR、Service CIDR、节点网段不冲突
  • 确认节点安全组、防火墙、路由策略
  • 确认是否需要 NetworkPolicy
  • 确认是否跨网段、跨可用区、跨 VPC
  • 确认底层 MTU 和 CNI 封装模式

部署后:

  • kubectl get nodes 节点 Ready
  • kubectl get pods -n kube-system CNI Pod Running
  • CoreDNS Running
  • Pod 能分配 IP
  • 同节点 Pod 互通
  • 跨节点 Pod 互通
  • Pod 能访问 Service ClusterIP
  • Pod DNS 解析正常
  • NetworkPolicy 行为符合预期

调优和巡检:

  • 检查 CNI 插件日志
  • 检查 kube-proxy 模式和规则规模
  • 检查 MTU
  • 检查 conntrack 使用率
  • 检查 CoreDNS 延迟和错误日志
  • 检查节点路由表和安全组
  • 检查 Pod CIDR 或 IPPool 是否接近耗尽

最后总结

CNI 是 Kubernetes 网络最核心的落地点。真正的重点不是记住某个插件安装命令,而是理解 Pod 网络如何接入宿主机、跨节点流量如何转发、Service 流量如何被 kube-proxy 或 eBPF 处理、NetworkPolicy 如何生效,以及故障发生时如何拆分边界。

对云服务实施工程师来说,CNI 能力可以分成三层:

  • 第一层:能部署,让节点 Ready,让 Pod 正常分配 IP
  • 第二层:能验证,确认 Pod、Service、DNS、NetworkPolicy 都符合预期
  • 第三层:能排障和调优,知道 MTU、conntrack、封装模式、安全组、路由、iptables/IPVS/eBPF 对业务访问的影响

如果你能围绕这三层准备,再结合一个自己动手搭建的 Calico 实验记录,面试时就不会显得空。CNI 这块确实有点深,但它的学习路径很清楚:先跑通,再看链路,最后练排障。