当前位置: 首页 > news >正文

【Kubernetes从入门到精通】第43篇:K8s网络模型——“每个Pod一个独立IP“背后的大智慧

上一篇【第42篇】CSI——容器存储接口标准深度解析
下一篇【第44篇】Flannel——最简单的K8s网络方案,但别小看它


摘要

恭喜你,存储模块终于通关了!CSI让你见识了K8s是怎么用一套gRPC接口搞定万国牌存储的。现在咱们进入一个更魔幻的领域——K8s网络。

你有没有想过一个问题:K8s集群里可能有几千个Pod,这些Pod分布在几十台Node上,它们是怎么互相"找到彼此"的?在传统的Docker世界里,容器跟容器通信得靠端口映射、NAT、网桥,搞得巨复杂。但K8s的做法简单粗暴——“每个Pod一个独立IP,所有Pod之间直连,不搞NAT那套虚的”。

这篇文章是模块5的"开篇宪法"——咱们不聊具体哪个网络插件(Flannel、Calico、Cilium后面有的是篇幅),先把K8s网络的基础逻辑掰扯清楚:(1)三大基本原则为什么这么设计;(2)NAT在什么层次存在(不在Pod层面,在Service层面);(3)CNI标准到底定义了哪些接口;(4)选网络插件时你应该关心什么。

读完这篇,你就知道为什么"每个Pod一个IP"是K8s网络最精妙的设计——它的核心思想不是帮你"节省IP",而是让你"简化网络"。


一、K8s网络的三大基本原则——“网络的宪法”

1.1 先来个全景图

在聊细节之前,先看一张图,理解K8s网络到底要解决什么问题:

【K8s网络模型全景——"三通一平"】 ┌──────────────┐ │ Pod A │ │ 10.244.1.5 │ └──────┬───────┘ │ ① Pod-to-Pod (同Node) │ 同一个网桥上,直接通信 ▼ ┌──────────────┐ │ Pod B │ │ 10.244.1.6 │ └──────────────┘ ┌─────────────────────────────────────────────────┐ │ Node 1 (10.0.0.1) │ │ ┌────────────────────────────────────────────┐ │ │ │ cni0 / docker0 网桥 │ │ │ │ 10.244.1.0/24 │ │ │ └────────────────────────────────────────────┘ │ └──────────────────────┬──────────────────────────┘ │ ② Pod-to-Pod (跨Node) │ 走网络插件隧道/路由 ▼ ┌──────────────────────┴──────────────────────────┐ │ Node 2 (10.0.0.2) │ │ ┌────────────────────────────────────────────┐ │ │ │ cni0 / docker0 网桥 │ │ │ │ 10.244.2.0/24 │ │ │ └────────────────────────────────────────────┘ │ │ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ Pod C │ ③ Pod │ Pod D │ │ │ │ 10.244.2.5 │◄───to───►│ 10.244.2.6 │ │ │ └──────────────┘ Service └──────────────┘ │ │ │ │ │ │ └──── ④ Pod-to-外部 ──────┘ │ └─────────────────────────────────────────────────┘

要点:K8s网络有四个核心场景——同Node Pod通信、跨Node Pod通信、Pod到Service、Pod到外部。其中前三个是K8s的"宪法级"要求——必须实现,不得有误。第四个(出站/入站)是CNI插件的可选能力。

1.2 三大原则原文翻译

Kubernetes官方对网络模型的要求就三句话,但它们比看起来深刻得多:

原则官方定义大白话翻译为什么这么设计
原则1:Pod互通Pods can communicate with all other Pods on any other Node without NATPod A在Node1上,Pod B在Node2上,它们必须能用各自的Pod IP直接通信,中间不能做任何地址转换如果做NAT,Pod就不知道"谁在跟我说话"了——源IP被改了,服务端拿到的是Node的IP,不是Pod的IP
原则2:Agent互通Agents on a Node (e.g. system daemons, kubelet) can communicate with all Pods on that NodeNode上的kubelet、监控Agent等系统进程,必须能用Pod IP直接访问本节点的Pod健康检查(kubelet→Pod)、日志采集(agent→Pod)都需要直接通信,做NAT会疯掉
原则3:宿主机互通Pods in the host network can communicate with all Pods on all Nodes without NAT用了hostNetwork的Pod,跟其他Pod通信也不需要NAT保持一致——不能有的Pod要NAT有的不要,那网络插件就乱套了

要点:这三条原则的核心精髓就一个词——扁平网络。K8s希望把整个集群变成一个"大二层"网络,所有Pod IP在集群内都是直接可达的,就像所有Pod都插在同一个交换机的不同端口上一样。


二、为什么不做NAT?——“kube-proxy的职责边界”

2.1 NAT在哪里?不在Pod层面,在Service层面!

这是最多人搞混的地方。很多人刚学K8s时会问:“K8s不是有个叫kube-proxy的东西做NAT吗?那怎么又说Pod间不做NAT?”

答案是——两个层面的NAT是两码事

【NAT的两个层面——"Pod层的NAT" vs "Service层的NAT"】 ┌─────────────────────────────────────────────────────────────────┐ │ Pod 层的通信 (K8s宪法禁止NAT) │ │ │ │ Pod A ──── 直接用Pod IP ────► Pod B │ │ 10.244.1.5 │ 10.244.2.5 │ │ │ │ │ [CNI 插件负责] │ │ (Flannel/Calico/Cilium) │ │ ───────────────────── │ │ 源IP: 10.244.1.5 ← 不变! │ │ 目的IP: 10.244.2.5 ← 不变! │ └─────────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────────┐ │ Service 层的通信 (kube-proxy做NAT) │ │ │ │ Pod A ──── 访问 ClusterIP ────► kube-proxy ────► Pod B │ │ 10.244.1.5 10.96.0.1 (iptables/IPVS) 10.244.2.5 │ │ │ │ │ [kube-proxy负责] │ │ ────────────── │ │ DNAT: 10.96.0.1 → 10.244.2.5 │ │ 源IP: 10.244.1.5 → 不变! │ └─────────────────────────────────────────────────────────────────┘

要点:Pod间直接通信走的是CNI插件的路由/隧道,IP地址原封不动——这叫"源IP保留"。而Service的ClusterIP是一个虚拟IP,需要通过kube-proxy做DNAT把ClusterIP转换成后端Pod的IP——但这只改目的IP,不改源IP。所以K8s说的是Pod层面不做NAT,Service层面该做还是做

2.2 为什么保留源IP这么重要?

你可能会问:“反正数据包能送到就行了,管它源IP改不改呢?”

来看看如果Pod间也做NAT会怎样:

【NAT vs 不NAT——"谁在叫我?"的问题】 ▸ 不做NAT (K8s的方式): Pod B 的日志里看到的来源是 10.244.1.5 (Pod A的IP) → 做网络策略、做审计日志、做调用链追踪,所有东西清清楚楚 ▸ 如果做NAT (Docker默认方式): Pod B 的日志里看到的来源是 10.0.0.1 (Node 1的IP) → "到底是谁在调我?Node 1上有20个Pod,我tm怎么知道是哪个?" → NetworkPolicy 直接废了——因为所有Pod经过NAT后看起来都一样

现在你明白了吧——保留源IP不是K8s的强迫症,而是NetworkPolicy、审计、分布式追踪这些上层功能的基础


三、CNI标准解读——“网络的USB接口”

3.1 CNI是什么——“不是你写插件,是插件配合你”

CNI(Container Network Interface)跟上一篇文章讲的CSI是一个路子——都是定义了一套标准接口,让实现方和调用方解耦。

但CNI和CSI有个关键区别:CNI是CNCF主导的通用标准,不光K8s用,Mesos、Cloud Foundry也用。它的设计哲学极其简洁:

【CNI 接口全景——"就两个操作,但涵盖了一切"】 ┌─────────────────────────────────────────────────────────┐ │ CNI 规范 (Spec) │ │ ───────────────── │ │ │ │ ┌─────────────────────────────────────────────────────┐│ │ │ 核心操作 (就两个!) ││ │ │ ││ │ │ ADD: 创建容器时调用 ││ │ │ • 分配IP地址 ││ │ │ • 创建网络接口 (veth pair) ││ │ │ • 配置路由 ││ │ │ • 返回结果 (IP/网关/DNS等) ││ │ │ ││ │ │ DEL: 删除容器时调用 ││ │ │ • 回收IP地址 ││ │ │ • 删除网络接口 ││ │ │ • 清理路由 ││ │ │ ││ │ │ CHECK: (可选) 检查容器网络是否正常 ││ │ │ VERSION: 查询插件支持的CNI版本 ││ │ └─────────────────────────────────────────────────────┘│ │ │ │ ┌─────────────────────────────────────────────────────┐│ │ │ 输入/输出格式 ││ │ │ ││ │ │ 输入: 通过 stdin 传入 JSON 配置 + 环境变量 ││ │ │ 输出: 通过 stdout 返回 JSON 结果 ││ │ │ 错误: 通过 stderr 输出错误信息 ││ │ └─────────────────────────────────────────────────────┘│ └─────────────────────────────────────────────────────────┘

要点:CNI的设计比你想象的简单得多——它就定义了一个可执行文件的调用规范。kubelet在创建Pod时,会调用类似这样的命令:echo '{"cniVersion":"0.3.1","name":"mynet",...}' | /opt/cni/bin/bridge,然后插件干活,返回结果。没有gRPC、没有长连接、没有守护进程——就是一个简单的命令行调用。这种"极简主义"让CNI插件的开发门槛极低。

3.2 CNI配置文件在哪里

每家CNI插件的配置方式都差不多,但格式各有不同:

# CNI配置文件默认位置ls/etc/cni/net.d/# 输出示例:# 10-flannel.conflist (Flannel)# 10-calico.conflist (Calico)# 05-cilium.conf (Cilium)# CNI插件二进制文件位置ls/opt/cni/bin/# 输出示例:# bridge host-local loopback portmap bandwidth flannel calico cilium-cni

3.3 CNI配置示例(Flannel)

{"name":"cbr0","cniVersion":"0.3.1","plugins":[{"type":"flannel","delegate":{"hairpinMode":true,"isDefaultGateway":true}},{"type":"portmap","capabilities":{"portMappings":true}}]}

3.4 网络插件的职责边界——“CNI管什么,kube-proxy管什么”

这是很多新手最困惑的地方。看了前面的内容你应该知道了——网络通信涉及的组件不止一个。

组件负责的事不负责的事
CNI插件(Flannel/Calico/Cilium)① Pod IP分配 ② 创建Pod网络接口(veth) ③ 跨Node路由/隧道 ④ NetworkPolicy执行① Service ClusterIP ② 负载均衡 ③ DNS解析
kube-proxy① Service → Pod的负载均衡 ② ClusterIP→Pod IP的DNAT ③ NodePort的监听① Pod间直连路由 ② Pod IP分配 ③ 网络策略
CoreDNS① Service名称→ClusterIP的DNS解析 ② 外部域名转发 ③ 自定义域名解析① 网络连通性 ② 负载均衡 ③ 安全策略
【分工协作全景图——"谁管哪一段"】 用户请求 │ ▼ ┌─────────┐ DNS解析 ┌──────────┐ │ CoreDNS │◄──────────────────►│ Service │ └─────────┘ svc.ns.local │ 10.96.x.x│ │ → 10.96.x.x └────┬─────┘ │ │ │ ┌─────▼─────┐ │ │ kube-proxy │ ← "这段我管!" │ │ iptables/ │ 做 DNAT + 负载均衡 │ │ IPVS │ │ └─────┬─────┘ │ │ DNAT → Pod IP │ ┌─────▼─────┐ │ │ CNI 插件 │ ← "这段我管!" │ │ Flannel/ │ 负责把包送到Pod │ │ Calico/ │ │ │ Cilium │ │ └─────┬─────┘ │ │ ▼ ▼ ┌──────────────────────────────────────────┐ │ 目标 Pod │ │ 10.244.2.5 │ └──────────────────────────────────────────┘

要点:把这个职责边界刻在脑子里——CNI管Pod到Pod的原始IP包传输,kube-proxy管Service到Pod的负载均衡和地址转换,CoreDNS管名字到IP的翻译。三者各司其职、互不越界。很多人排查网络问题时抓瞎,就是因为没搞清楚"现在该找谁"。


四、网络插件的选型框架——“斗地主指南”

4.1 三大流派的对比

【K8s网络插件三大流派——"你选哪条路?"】 ┌─────────────────────────────────────────────────────────────────┐ │ 流派1: Overlay (叠加网络) │ │ ───────────────────────── │ │ 代表: Flannel(VXLAN), Calico(IPIP/VXLAN), Weave, Cilium(VXLAN) │ │ │ │ 原理: 在宿主机网络上再包一层虚拟网络 │ │ Pod 包 → 封装 → 走物理网络 → 解封装 → Pod 包 │ │ │ │ 优点: 不依赖物理网络,对底层设备无要求,部署简单 │ │ 缺点: 封包/解封有性能损耗,带宽打折扣(通常5-15%) │ │ 适合: 公有云环境、对底层网络不可控的场景 │ └─────────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────────┐ │ 流派2: Underlay (底层网络) │ │ ───────────────────────── │ │ 代表: Calico(BGP), Macvlan, SR-IOV │ │ │ │ 原理: Pod直接使用物理网络通信,没有封装开销 │ │ Pod 包 → 直接走物理网络 → Pod 包 │ │ │ │ 优点: 性能最佳,几乎没有损耗 │ │ 缺点: 需要物理网络支持(BGP/路由配置),IP地址规划要求高 │ │ 适合: 自建机房、对网络性能有极致要求的场景 │ └─────────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────────┐ │ 流派3: eBPF (内核级网络) │ │ ──────────────────────── │ │ 代表: Cilium(eBPF) │ │ │ │ 原理: 用eBPF在内核里直接处理数据包,连iptables/IPVS都省了 │ │ 包 → eBPF程序 → 直接转发 │ │ │ │ 优点: 性能最佳,可观测性最强,支持L7策略 │ │ 缺点: 要求内核4.9+,学习曲线陡峭 │ │ 适合: 新项目、对可观测性和安全有高要求的场景 │ └─────────────────────────────────────────────────────────────────┘

4.2 核心能力对比

能力FlannelCalicoCiliumWeave
Overlay支持VXLAN/UDPIPIP/VXLANVXLANVXLAN
Underlay支持host-gwBGP原生路由
NetworkPolicy✅ 深度集成✅ L3/L4/L7
eBPF✅ 核心
加密WireGuardWireGuard/IPSec
部署复杂度中高
性能中等(封装损耗)高(BGP模式)极高(eBPF)中等
适用规模中小集群中大集群各种规模小集群

五、实战:验证你的K8s网络模型

5.1 验证Pod IP的"全局唯一且可达"

# 1. 获取所有namespace下所有Pod的IPkubectl get pods-A-owide|awk'{print $1, $6, $7}'# 输出示例:# NAMESPACE IP NODE# default 10.244.1.5 node1# default 10.244.2.5 node2# kube-system 10.244.1.3 node1# kube-system 10.244.2.3 node2# 2. 在Pod A里直接ping Pod B的IPkubectlexec-itpod-a --ping-c310.244.2.5# PING 10.244.2.5 (10.244.2.5): 56 data bytes# 64 bytes from 10.244.2.5: icmp_seq=0 ttl=62 time=0.523 ms# ✅ 能通!验证了"跨Node Pod直接通信"# 3. 查看Pod的网络接口kubectlexec-itpod-a --ipaddr show# 1: lo: <LOOPBACK,UP,LOWER_UP># 3: eth0@if7: <BROADCAST,MULTICAST,UP,LOWER_UP># inet 10.244.1.5/32 brd 10.244.1.5 scope global eth0# # ↑ 注意 /32 掩码——每个Pod只看得到自己的IP# 4. 查看Pod的路由表kubectlexec-itpod-a -- route-n# Kernel IP routing table# Destination Gateway Genmask Flags Metric Ref Use Iface# 0.0.0.0 10.244.1.1 0.0.0.0 UG 0 0 0 eth0# 10.244.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0# # 默认网关指向 Node 上的网桥 (10.244.1.1)# # 所有出Pod的流量都先到网桥,然后由CNI决定怎么走

5.2 在Node上观察veth pair

# 在Node上查看veth设备iplinkshow|grepveth# 输出示例:# 7: veth1234@if3: <BROADCAST,MULTICAST,UP,LOWER_UP># # ↑ veth一端在host(namespace),另一端在Pod(namespace)# # @if3 表示对端的interface index是3(就是Pod里的eth0)# 查看哪个Pod对应哪个vethforvethin$(iplinkshow|grep-oP'veth[^@]+');dopod=$(crictl pods--name".*"-q2>/dev/null|head-1)echo"$veth->$pod"done

六、IP地址规划的坑——“/24到底够不够?”

6.1 默认配置的隐藏限制

很多人用Flannel默认配置时,看到Pod CIDR是10.244.0.0/16,就以为能跑65535个Pod。但实际上:

【Flannel默认配置的真实含义】 --pod-cidr=10.244.0.0/16 ← 整个集群的Pod IP池 (65536个IP) 每个Node分配一个 /24 子网: Node1 → 10.244.1.0/24 (254个Pod) Node2 → 10.244.2.0/24 (254个Pod) Node3 → 10.244.3.0/24 (254个Pod) ... 最多支持 256 个Node (因为 /16 ÷ /24 = 2^8 = 256) 每个Node最多 254 个Pod (因为 /24 减去网络地址和广播地址) 所以: 最大Pod数 = 256 Node × 254 Pod = 65024 最大Node数 = 256

要点:Flannel默认/16的Pod CIDR意味着最多256个Node。如果你预计集群会超过这个数,部署时要改--pod-cidr=10.244.0.0/12,这样就有1048576个Node子网可用。但更大的CIDR意味着更大的路由表——Calico的BGP模式尤其受此影响,每个Node的子网都是一条BGP路由。

6.2 跟现有网络冲突怎么办

# 当你的办公网络也在10.0.0.0/8里时,# 用默认的10.244.0.0/16可能"恰好不冲突",# 但如果Pod CIDR和宿主机网络、VPN网络路由冲突——# 解法1: 换IP段# kubeadm init --pod-network-cidr=172.16.0.0/12# 或者用 192.168.0.0/16# 解法2: 确认当前所有网络的CIDRiproute show# default via 192.168.1.1 dev wlan0# 10.0.0.0/8 via 10.0.0.1 dev tun0 ← VPN占用了10段# 172.17.0.0/16 dev docker0 ← Docker占用了172.17段# 所以 Pod CIDR 只能选 172.18-31 或 192.168 段# 解法3: 用Cilium的cluster-pool模式# Cilium可以单独指定IPv4和IPv6的CIDR,更灵活

本篇小结

K8s网络模型的"宪法"其实就三句话:所有Pod可以直连、不要NAT、Node也能直连Pod。这三条原则的核心目的是保留源IP——没了源IP,你的NetworkPolicy废了、审计日志废了、调用链废了。这个设计思想跟Docker那种"NAT糊一脸"的方式完全相反——K8s选择了用更多IP地址来换取更干净的网络语义。

CNI是这个模型的"执行器"——两个核心接口(ADD/DEL),一个可执行文件的简单调用,就让几十种网络插件百花齐放。但你要记住职责边界:CNI管Pod到Pod的包怎么传,kube-proxy管Service到Pod的负载均衡,CoreDNS管名字翻译。后面几篇文章咱们挨个拆解Flannel、Calico、Cilium,看看这些执行器是怎么各显神通的。


上一篇【第42篇】CSI——容器存储接口标准深度解析
下一篇【第44篇】Flannel——最简单的K8s网络方案,但别小看它


http://www.jsqmd.com/news/1395207/

相关文章:

  • Mac 版 Navicat 试用期到期怎么办?一篇讲透无限试用重置原理、三种方案与避坑清单
  • 单片机毕设选题推荐:基于 STM32 的健康体征检测与声光告警终端开发 基于 STM32 的便携式人体心率血氧监测仪设计(013203)
  • Windows 11 卡顿的元凶不在你装的软件里:用 Win11Debloat 清理预装应用与遥测,3 步告别系统臃肿
  • 3 分钟免费把 GIMP 变成 Photoshop:PhotoGIMP 界面补丁完整上手指南
  • 前端构建安全:防范资源中毒与依赖风险实战指南
  • 2026年8月无锡市锡山区电信200M单宽带避坑全攻略 - 找卡家园
  • MathType与Word集成故障排查:COM插件加载失败与快捷键冲突修复指南
  • 北京离婚财产分割律师哪家专业?看这篇就够了 - 品牌排行榜
  • Codex部署实战:从安装失败到稳定集成的工程化指南
  • 十分钟搞定精灵图打包:Free Texture Packer 免费纹理打包工具上手全记录
  • Cesium三维GIS动效开发:Geo-Effect-Kit v0.4核心功能与实战指南
  • 2026年8月邢台市广宗县联通500M宽带怎么报装 - 找卡家园
  • 零基础快速把照片变3D打印模型,免费开源的ImageToSTL了解一下
  • ArcGIS Pro擦除工具详解:从原理到实战解决空间叠加分析
  • Windows窗口美化终极指南:DWMBlurGlass让全系统标题栏拥有毛玻璃特效
  • 大模型知识蒸馏攻击:技术原理、检测机制与行业合规挑战
  • 【计算机毕业设计单片机案例】STM32 驱动的感应式智能垃圾桶及其 Android 客户端开发 基于多传感器融合的智能垃圾桶物联网终端设计(013103)
  • 还在用命令行折腾蓝牙?Blueman 教你 3 步完成配对、传文件和网络共享
  • 基于ComfyUI API与MiniMax-H3构建多模态AI视频生成流水线
  • 2026直播公会退会机制实测 **零卡点自由解约维权避坑指南 - nuanyin
  • 2026年8月无锡市锡山区电信100M单宽带避坑与办理指南 - 找卡家园
  • 二手车采销实战:基于天远车辆vin码查车辆信息详版构建自动化库存网关
  • 告别“消息已撤回“:RevokeMsgPatcher 防撤回工具 5 步上手保姆级指南
  • AMQP、Kafka与Pulsar:消息中间件核心概念、Spring集成实战与选型指南
  • Windows XP
  • 游戏AI智能教练系统:从行为克隆到个性化决策推荐
  • 从PSP蓝光电影解析视频编码:原盘、重编码与MP4封装技术详解
  • 微信缓存清理攻略:用 CleanMyWechat 三步抢回 30GB 磁盘空间
  • YOLO医学影像组织结构目标检测数据集-15878张
  • 花不到25美元,把普通眼镜变成AI智能眼镜:OpenGlass从零搭建全指南