Kubernetes 网络模型:CNI 插件、Service 发现与负载均衡
聊到 Kubernetes,网络这块是绕不过去的坎。很多人刚开始接触 K8s 时,会被它那套「每个 Pod 都有独立 IP」的模型搞懵。我当年第一次部署集群,Pod 之间 ping 不通,折腾了一整天才发现是 CNI 插件没配好。嗯,今天我们就来把这套网络模型彻底讲透。
一、K8s 网络模型的核心原则
Kubernetes 对网络有几个硬性要求,说白了就是三条铁律:
- 所有 Pod 可以不经过 NAT 直接通信——不管它们在哪个节点上
- 所有节点可以直接访问所有 Pod——节点和 Pod 是对等的
- Pod 看到的自身 IP 就是其他 Pod 访问它的 IP——没有地址转换
这个模型的好处很明显:你不需要操心端口映射,也不用管 NAT 规则。Pod 就像一台独立的物理机,IP 就是它的身份证。
关键理解:K8s 网络模型是「扁平 IP 空间」。每个 Pod 拿到一个真实可路由的 IP,而不是 Docker 默认的 NAT 桥接模式。这意味着从集群内任何位置,都能直接用 Pod IP 访问它。
二、CNI 插件:谁在背后干活?
K8s 本身不实现网络,它只定义接口。这个接口就是 CNI(Container Network Interface)。CNI 插件负责给 Pod 分配 IP、配置网络接口、维护路由规则。
市面上主流的 CNI 插件有几种,我挑几个常用的说说:
| 插件 | 网络模式 | 特点 | 适用场景 |
|---|---|---|---|
| Flannel | Overlay(VXLAN) | 简单易用,性能一般 | 小规模集群、学习环境 |
| Calico | 纯三层(BGP) | 高性能,支持网络策略 | 生产环境、大规模集群 |
| Cilium | eBPF 驱动 | 极高性能,可观测性强 | 云原生、安全敏感场景 |
| Weave | Overlay(fastdp) | 加密通信,跨云部署 | 多集群、混合云 |
我的建议:如果你刚开始学,用 Flannel 上手最快。但生产环境我推荐 Calico,它用 BGP 直接路由,没有 Overlay 的封装开销。我在一个 200 节点的集群上用过 Calico,延迟表现非常稳定。
三、Service 发现:Pod 挂了怎么办?
Pod 是脆弱的,随时可能被调度到别的节点,IP 也会变。那客户端怎么找到它?K8s 的答案是 Service。
Service 是一个抽象层,它有一个固定的虚拟 IP(ClusterIP)。你访问这个 IP,K8s 会把流量转发到后端的某个 Pod 上。Pod 挂了?没关系,Service 会自动剔除它。
Service 的发现方式有两种:
- 环境变量:Pod 启动时,K8s 会把 Service 的 IP 和端口注入到环境变量里。比如
MY_SERVICE_SERVICE_HOST和MY_SERVICE_SERVICE_PORT。 - DNS:K8s 集群内部有一个 CoreDNS,它会为每个 Service 创建一条 A 记录。你直接用 Service 名字就能访问,比如
my-service.namespace.svc.cluster.local。
我个人更推荐 DNS 方式。环境变量有个坑:如果 Pod 在 Service 创建之前启动,它就拿不到环境变量。DNS 就没这个问题,随时都能解析。
四、负载均衡:iptables vs IPVS
Service 的流量转发,底层靠的是 kube-proxy。kube-proxy 有三种模式,最常用的是 iptables 和 IPVS。
4.1 iptables 模式
这是默认模式。kube-proxy 会为每个 Service 创建一堆 iptables 规则。当请求到达 Service IP 时,iptables 通过 DNAT 规则把目标地址改成某个 Pod 的 IP。
举个例子,你创建一个 Service,后端有 3 个 Pod。kube-proxy 会生成类似这样的规则:
-A PREROUTING -m comment --comment "default/my-service" -j KUBE-SERVICES
-A KUBE-SVC-XXXXX -m statistic --mode random --probability 0.33 -j KUBE-SEP-AAAAA
-A KUBE-SVC-XXXXX -m statistic --mode random --probability 0.50 -j KUBE-SEP-BBBBB
-A KUBE-SVC-XXXXX -j KUBE-SEP-CCCCC
每条规则对应一个 Pod,概率值决定了流量分配。iptables 是线性匹配的,规则越多,性能越差。我在一个集群里见过上万条 iptables 规则,那延迟……嗯,不提了。
避坑指南:我曾经在一个大集群里用 iptables 模式,Service 数量超过 5000 个时,节点上的 iptables 规则达到了 10 万条。每次更新规则都要好几秒,Pod 调度都受影响。后来切到 IPVS 才解决。
4.2 IPVS 模式
IPVS 是 Linux 内核自带的 L4 负载均衡器。它用哈希表来存储转发规则,查找时间复杂度是 O(1),不管有多少条规则,性能都很稳定。
启用 IPVS 模式很简单,在 kube-proxy 配置里设置:
mode: "ipvs"
IPVS 支持多种调度算法:
- rr:轮询,默认算法
- lc:最少连接
- dh:目标地址哈希
- sh:源地址哈希
- sed:最短预期延迟
- nq:永不排队
你想想看,如果你的服务对延迟敏感,用 lc 或 sed 会更合理。我一般用 rr,简单够用。
五、一张图看懂 K8s 网络模型
下面这张图展示了从客户端到 Pod 的完整流量路径:
六、如何选择?
说了这么多,到底用哪个?我总结一下:
- 小集群(< 50 个 Service):iptables 完全够用,配置简单,不用额外操心。
- 中大规模集群(> 100 个 Service):建议切到 IPVS。性能稳定,规则更新快。
- 对延迟极度敏感:IPVS + Cilium(eBPF)是绝配,延迟几乎为零。
一个小技巧:如果你不确定当前集群用的是哪种模式,可以查看 kube-proxy 的 Pod 日志:kubectl logs -n kube-system kube-proxy-xxxxx | grep "Using"。它会告诉你当前是 iptables 还是 IPVS。
好了,K8s 网络模型的核心内容就这些。CNI 插件负责 Pod 的网络连通,Service 解决了 Pod IP 动态变化的问题,而 iptables 和 IPVS 是流量转发的底层实现。理解这三层,你就能搞定大部分 K8s 网络问题了。