目录
Please enable Javascript to view the contents

K8s网络-概念与入门

 ·  ☕ 12 分钟

系列导航

本系列从 Pod 网络连通入手,逐步展开到 K8s 网络全景。

① 概念 → ② Flannel → ③ Calico → ④ 流量路径 → ⑤ Cilium → ⑥ 对比 → ⑦ 排障 ‖ ⑧ 开发 → ⑨ 多网卡 → ⑩ AI 演进

顺序文章定位
本篇 - 概念与入门基础——主机网络、Docker 网络、CNI 标准、方案分类树
Flannel 详解CNI 实现——Overlay 封装(UDP/VXLAN/HostGW)与抓包
Calico 详解CNI 实现——三层路由(BGP/IPIP)+ NetworkPolicy
流量路径全解析全貌——Pod/Service/Ingress/Egress,揭示 CNI 的边界
Cilium 详解超越 CNI——eBPF 统一 Pod + Service + L7 + Hubble
插件对比与选型选型——5 插件横向对比 + 决策树
排障思路与常用命令运维——工具链 + 场景排查 + 性能
核心路径 ↑扩展展望 ↓
CNI 插件开发指南扩展——基于 CNI 规范开发自定义插件
多网卡方案详解进阶——Multus + SR-IOV/ipvlan 多网口实战
AI 时代网络演进展望——GPU 网络、eBPF 加速、未来方向

重要

本文是系列地基,回答一个问题:K8S 为什么需要 CNI。

脉络按两条线索展开,在 跨主机 Pod 为什么不通 处汇合:

  • 自底向上——找出问题:主机网络 → Docker 单机网络 → 跨主机 Pod 不通 → CNI 补了什么
  • 自顶向下——给出方案:K8S 网络假设 → IPAM + 路由转发 → Overlay / 路由方案分类树

先补齐 Linux 和 Docker 网络地基,再看跨主机问题为什么必须引入 CNI,最后给出方案分类全貌。后续文章按分类树的枝叶逐一深入。


1. 主机网络基础

理解 K8S 网络之前,需要先搞清楚一台 Linux 主机是怎么收发包的。无论物理机、虚拟机还是容器,都遵循同一套协议栈逻辑。

2.1 路由表:内核如何决定下一跳

为网卡配置 IP 地址和子网掩码后,内核自动生成两类路由:

路由类型生成条件目标网段网关含义
直连路由网卡配置了 IP/掩码该接口所在子网0.0.0.0同子网直接发送,不需要网关
默认路由配置了默认网关0.0.0.0/0指定的网关 IP不在子网的目标IP,交给网关

发包时内核查路由表,按最长前缀匹配决定下一跳:

同子网通信 → 匹配直连路由 → 下一跳 = 目标 IP 本身
跨子网通信 → 匹配默认路由 → 下一跳 = 网关 IP

2.2 ARP:IP 如何找到 MAC

路由决策只确定了「下一跳 IP」,但二层封帧需要的是「下一跳 MAC」。ARP 协议负责这个映射:

场景下一跳 IPARP 请求目标
同子网目标主机 IP直接找目标主机的 MAC
跨子网网关 IP找网关的 MAC

流程:

查 `ARP 缓存`(`ip neigh` 或 `arp -n`)
  ├─ 命中 → 直接封装 `二层帧`(目标 MAC = 下一跳 MAC,目标 IP 不变)
  └─ 未命中 → 广播 `ARP请求` → 收到应答后学习 MAC → 封装帧发送

同子网:下一跳就是 目标IP,ARP 查目标 MAC。
跨子网:下一跳就是 网关,ARP 查网关 MAC。目标 IP 首尾不变。

2.3 二层交换与跨网段转发

帧离开源主机后,经过的设备分两类:

设备类型工作层行为
交换机 / Linux 网桥二层只看目标 MAC,查 CAM 表转发端口,不解封 IP 头
路由器三层剥离二层头,查目标 IP,查路由表决定下一跳,重新封装二层头

二层设备的转发规则:

目标 MAC 类型行为
广播/多播泛洪到所有端口
单播且 MAC 在 CAM 表中从对应端口转发
单播但 CAM 未命中泛洪(未知单播)

跨网段转发时,数据包经过多个路由器,目标 IP 自始至终不变,每跳的源/目标 MAC 都在变

源主机 → 路由器1 → 路由器2 → ... → 目标主机
  目标IP = 10.0.2.55(始终不变)
  目标MAC = 路由器1.MAC → 路由器2.MAC → ... → 目标主机.MAC(每跳变化)

2.4 主机网络小结

发包流程:
  1. 查路由表 → 确定下一跳 IP(同网段 = 目标IP / 跨网段 = 网关IP)
  2. 查 ARP 缓存 → 确定下一跳 MAC(同网段 = 目标MAC / 跨网段 = 网关MAC)
  3. 封装二层帧(目标 MAC = 下一跳 MAC,目标 IP 不变)→ 从网卡发出
  4. 二层设备按 MAC 转发 → 到达下一跳
  5. 若需跨网段,路由器重复步骤 1-4
理解这套逻辑是理解容器网络的前提——Docker 容器网络只是在此基础上用虚拟设备模拟了 网卡网桥路由

2. Docker 单机容器网络

Docker 没有发明新协议,完全基于 Linux 内核已有的网络能力:

Docker容器网络 = Linux NetworkNamespace + veth pair + 网桥 + 自动生成的标准路由配置 + 宿主机NAT规则

3.1 网络栈与 network namespace

网络栈是进程发起和响应网络请求的基本环境,包括:网卡、回环设备、路由表、iptables 规则。

Linux 通过 network namespace 实现网络栈隔离。每个容器拥有独立的 namespace,里面有自己的网卡、路由表、iptables 规则,与宿主机和其他容器互不干扰。

3.2 Veth Pair:连接不同命名空间的网线

Veth Pair 是一对虚拟网卡,从一端写入的数据包会直接出现在另一端,即使两端在不同的 namespace 中。因此常被用来连接不同 NS:

容器 NS                    宿主机 NS
┌──────────┐               ┌──────────┐
│  eth0    │◄──veth pair──►│ veth001  │
└──────────┘               └──────────┘

3.3 网桥 docker0

docker0 是一个 Linux 网桥,根据目标 MAC 将数据包转发到自身不同的端口上。每个容器启动时,其 veth 对端会插入 docker0。

关键点: veth 网卡一旦插入网桥,就从独立网卡降级为网桥的一个端口,不再调用协议栈处理数据包,转发决策完全由网桥接管。

1
2
3
4
5
brctl show

# 网桥名称     网桥ID               STPenabled    网卡
# docker0     8000.0242d8e4dfc1    no            veth001
#                                                veth002

3.4 容器内的路由表

容器启动后,eth0 配置 IP(如 172.17.0.2/16),内核自动生成两条路由,与 §2 主机网络的路由规则一致:

目标网络        网关          掩码            Flags  网卡
default         172.17.0.1    0.0.0.0         UG     eth0    ← 默认路由
172.17.0.0      0.0.0.0       255.255.0.0     U      eth0    ← 直连路由
  • 直连路由172.17.0.0/16):同网段流量走 eth0,目标 MAC 从 ARP 缓存查
  • 默认路由default):其他流量走 eth0,下一跳是 docker0 的 IP(172.17.0.1),目标 MAC = docker0 的 MAC

3.5 容器 A ping 容器 B(同主机)

假设容器 A(172.17.0.2)ping 容器 B(172.17.0.3),两台容器在同一台宿主机上。

容器A eth0 ──vethA── docker0 ──vethB── 容器B eth0
172.17.0.2                             172.17.0.3

完整流程:

1. 容器A 查路由表
   目标 172.17.0.3 ∈ 172.17.0.0/16 → 匹配直连路由
   下一跳 = 172.17.0.3(目标本身),走 eth0

2. 容器A 查 ARP 缓存:172.17.0.3 → 未命中
   → 从 eth0 发送 ARP 广播:"谁是 172.17.0.3?"

3. ARP 广播经 vethA 到达 docker0 网桥
   → ARP 是广播帧 → docker0 泛洪到所有端口(vethA, vethB, ...)

4. 容器B 的 eth0(通过 vethB)收到 ARP 广播
   → 目标 IP == 自身 IP → 回复 ARP 应答(MAC_B)

5. 容器A 获得容器B 的 MAC → 封装二层帧
   目标 MAC = MAC_B,目标 IP = 172.17.0.3

6. 数据包经 eth0 → vethA → docker0
   → docker0 查 CAM 表:MAC_B → 端口 vethB → 转发到 vethB

7. 数据包经 vethB → eth0 进入容器B
   → 容器B 协议栈处理 → 回复 pong

整个过程依赖:容器路由规则 → VethPair → 网桥 CAM 转发 → VethPair → 目标容器。

3.6 docker0 的双重角色与报文分岔

docker0 既是二层网桥,也是三层接口:

角色触发条件功能特性
二层网桥目标 MAC ≠ docker0 自身 MAC查 CAM 表,按 MAC 转发到对应的 veth端口与网桥docker0绑定的veth网卡会自动降级成端口,失去报文解析、转发的能力
三层接口目标 MAC = docker0 自身 MAC上交宿主机协议栈(路由、iptables)docker0需要具备IP和MAC

报文分岔逻辑:

数据包到达 docker0
  ├─ 目标 MAC == docker0 自身 MAC
  │    → 上交宿主机 IP 层 → 走路由、iptables、协议栈处理
  │
  ├─ 目标 MAC == 某端口 MAC
  │    → 查 CAM 表 → 转发到对应端口(不进宿主机 IP 层)
  │
  └─ 目标 MAC == 广播/多播/CAM 未命中的单播
       → 泛洪到所有端口

举例:容器访问外网

容器内 ping baidu.com,目标不在 172.17.0.0/16 网段,匹配默认路由:

1. 容器查路由表 → 匹配 默认路由 → 下一跳 = 172.17.0.1(docker0 的 IP)
2. ARP 解析 → 获取 docker0 的 MAC
3. 数据包目标 MAC = docker0.MAC
   → docker0 判定目标是自身 → 上交宿主机协议栈
4. 宿主机 iptables NAT(SNAT)→ 源 IP 替换为宿主机 IP
5. 从宿主机 eth0 发出 → 走宿主机路由 → 出外网

3.7 容器网络与 Linux 协议栈的关系

所有转发决策均遵循内核固有的路由/ARP/二层交换逻辑。容器内外协议栈行为完全一致,差别只在于容器使用的是虚拟设备(veth、网桥)而非物理设备。


3. K8S 网络模型假设

K8S 不对具体网络实现做限制,只强制约定 4 条网络假设:

序号假设说明
1Pod 间直接通信任意两个 Pod 可以直接用对方 Pod IP 通信,不需要 NAT
2节点与 Pod 间直接通信节点和 Pod 可以直接通信,不需要 NAT
3Pod 所见 IP = 外部所见 IPPod 内部感知到的 IP 地址,与其他 Pod 或节点看到的 IP 完全一致
4Service 抽象集群内可通过 Service IP 访问 Pod,Service 做负载均衡和 DNS 解析

这 4 条假设的核心是:

IP 地址的端到端一致性 —— 无论流量经过多少节点和网络转换,IP 地址本身不被篡改。

这避免了传统虚拟化网络中 “网络地址转换 NAT” 带来的复杂性,为服务发现、负载均衡、可观测性提供了统一基础。


4. 跨主机容器通信问题:Docker bridge 为什么不够

4.1 单机能解决什么

  • 同主机,容器间通信:
容器.路由表 + VethPair + docker0网桥(veth降级为端口 + CAM根据mac查端口)
  • 容器 访问 其他宿主机或外网:
容器.路由表(匹配默认路由,下一跳 = docker0 IP)
  → VethPair
  → docker0 三层设备(目标 MAC = docker0.MAC,上交宿主机协议栈)
  → 宿主机.路由表(根据目标 IP 决定从哪个网卡出)
  → 宿主机对应网卡发出

4.2 跨主机容器通信为什么失败

当容器 A(节点1,172.17.0.2)要访问容器 C(节点2,172.17.0.5)时:

节点1                                    节点2
容器A (172.17.0.2)                      容器C (172.17.0.5)
  │ eth0                                   │ eth0
  │ vethA                                  │ vethC
docker0 (172.17.0.1)                    docker0 (172.17.0.1)
  │ eth0                                   │ eth0
  └────────────────────── 物理网络 ─────────┘

问题出在三个层面:

问题说明
容器路由表不感知外部拓扑容器A 查路由表,172.17.0.5 匹配直连路由,认为在 eth0 直连可达。实际上容器C 在另一台物理机上
ARP 无法跨主机容器A 发 ARP 广播找 172.17.0.5 的 MAC,广播只到达 docker0 和同节点的其他容器,永远到不了节点2
两个 docker0 网桥互相不感知每台宿主机有独立的 docker0,各自维护独立的 CAM 表,彼此不知道对方有哪些端口

根本原因:

docker0 是单机二层网桥,不具备跨主机路由能力。

容器看到的直连路由是基于 所有容器都在同一个 docker0 下 的假设,这个假设在跨节点时崩塌。

4.3 跨主机需要什么能力

要打通跨主机容器通信,必须额外补充三个能力:

能力说明谁负责
全局 IPAM两个节点的容器子网不能冲突,需要统一的 IP 分配CNI 插件
跨节点路由信息节点1 需要知道「172.17.0.5 在节点2」CNI 插件
数据包送达机制跨节点时通过封装(Overlay)或直接路由CNI 插件

这就是 CNI 要做的事情——在 Docker 单机网络的基础上,补齐跨主机能力。


5. CNI 标准与调用链

5.1 什么是 CNI

CNI (Container Network Interface) 是 CNCF 定义的容器网络接口标准。它规定了:

  • Kubelet 调用网络插件的接口格式
  • 插件必须实现的生命周期操作:ADD、DEL、CHECK、VERSION
  • 插件返回结果的数据结构

CNI 解决的是 “Pod 网络怎么配置” 的标准化问题,让不同网络方案可以按同样的接口接入 K8S,而不需要修改 K8S 核心代码。

CNI 不管的事: Service 抽象(kube-proxy 负责)、Ingress/Egress(Ingress Controller 负责)、网络策略(NetworkPolicy 实现负责)、可观测性。Cilium 这类"超 CNI"方案把这些全部整合进一个内核级数据路径。

5.2 CNI 解决两件事

CNI 标准本质上只解决两件事:

  1. IPAM(IP 地址管理)——给 Pod 分什么 IP、怎么避免冲突
  2. 连通性(路由转发)——包怎么从源 Pod 送到目的 Pod

所有 CNI 插件的能力都可以归到这两个维度。后续文章中 Flannel、Calico 的各种后端模式,都是沿「连通性」这条线展开的不同实现:

CNI 解决的两件事
├── IPAM:给 Pod 分 IP
│   ├── host-local(静态子网分配)
│   ├── calico-ipam(动态分配)
│   └── dhcp
│
└── 连通性:怎么送达
    ├── Overlay — 构造特殊通路
    │   ├── UDP(应用层封装,用户态,性能差,仅演示)
    │   ├── VXLAN(内核态 L2-in-UDP,生产通用)
    │   └── IPIP(内核态 IP-in-IP,纯三层封装)
    └── Underlay — 维护节点路由
        ├── HostGW(静态路由,要求二层互通)
        └── BGP(动态路由,三层互通)

本篇只讲分类逻辑和每类的核心思想。具体封装细节、路由表长什么样、抓包验证,留给 Flannel 详解Calico 详解 展开。

5.3 K8S 中的 CNI 调用链

用户创建 Pod
    ↓
API Server 写入 Etcd
    ↓
Scheduler 调度到某节点
    ↓
Kubelet 监听到本节点 Pod 创建
    ↓
读取 /etc/cni/net.d/ 目录下的 CNI 配置文件
    ↓
执行配置中指定的 CNI 插件二进制文件(在 /opt/cni/bin/)
    ↓
CNI 插件进入 Pod 网络命名空间
    ↓
创建 veth 网卡对 → 分配 IP → 配置路由 → 设置 iptables
    ↓
返回 Pod IP 等信息给 Kubelet
    ↓
Pod 启动

关键配置位置:

  • CNI 配置文件:/etc/cni/net.d/*.conf
  • CNI 二进制文件:/opt/cni/bin/
  • IPAM 存储:etcd(Flannel)或 CRD(Calico)

6. 跨节点通信的两条路

跨主机 Pod 通信的所有方案,最终都落在「连通性」维度的两个分支上。

6.1 Overlay:构造特殊通路

Overlay 的核心理念:用隧道封装在物理网络之上构建叠加网络。 底层网络不知道 Pod IP,只看到封装后的宿主机间流量。属于"构造特殊通路"的方式。

层次由内层报文决定,不看底层隧道:

方案报文结构层次特点场景
UDPHostIP|UDP|内层IP|DataL3用户态封装,28B 开销,性能最差仅演示
VXLANHostIP|UDP|VXLAN|内层MAC|内层IP|DataL2内核态 VTEP 封装,~50B 开销,生产通用公有云、虚拟化环境
IPIPHostIP|IPIP|内层IP|DataL3内核态封装,~4B 开销,更轻量但只支持 IP 单播三层互通

底层隧道都是 UDP(L4),但层次由 内层报文 决定——内层含 MAC 头就是 L2,只有 IP 就是 L3。

6.2 Underlay:维护节点路由

路由模式的核心理念:不做封装,直接维护宿主机路由表。 跨节点流量按标准 IP 路由转发。

方案路由方式要求典型实现
HostGW静态路由,下一跳 = 目标节点 IP所有节点必须在同一个 L2 广播域Flannel-HostGW
BGP动态路由协议,每个节点宣告自己的 Pod 子网机房间允许 BGP 协议Calico-BGP

6.3 分类决策

两类方案的选择本质是 通用性 vs 性能 的权衡:

维度Overlay(构造通路)Underlay(维护路由)
通用性高,适配任何底层网络低,要求 L2 互通或支持 BGP
性能有 10-20% 封装开销接近裸机网络
典型场景公有云、虚拟化环境自建 IDC 机房

具体各方案的包流向、抓包分析、配置示例,详见 Flannel 详解Calico 详解。多插件横向对比和选型决策,见 插件对比与选型


参考链接

Kubernetes CNI 规范
Calico 网络模式对比
Flannel 后端模式说明
CNI 插件开发指南

分享

Hex
作者
Hex
CloudNative Developer