一、K8s 网络要解决的四类通信问题
Kubernetes 网络设计的核心目标是解决以下四类通信问题:
| 通信类型 | 说明 | 关键组件 |
|---|---|---|
| Pod 内通信 | 同一个 Pod 内多个容器间的通信(通过 localhost) | 共享网络命名空间(pause 容器) |
| Pod 间通信 | 不同 Pod 之间的直接通信 | CNI 网络插件(Calico/Flannel/Cilium) |
| Pod 与 Service 通信 | Pod 如何通过稳定的 Service 域名访问彼此 | kube-proxy(iptables/IPVS)+ CoreDNS(域名解析) |
| 外部与 Service 通信 | 集群外部如何访问集群内的服务 | Service(NodePort/LoadBalancer)+ Ingress |
三大核心组件
K8s网络的实现,依赖于几个关键的组件协同工作
| 组件 | 作用 | 运行位置 |
|---|---|---|
| CNI 插件 | 为 Pod 创建网络接口、分配 IP、设置路由 | 每个节点上,被 kubelet 调用 |
| kube-proxy | 实现 Service 的负载均衡,维护 iptables/IPVS 规则 | 每个节点上的 DaemonSet |
| CoreDNS | 为 Service 提供域名解析服务 | 集群内的 Deployment |
二、容器网络基础(Docker 网络模型)
在学习 K8s 网络之前,必须先理解 Docker 容器网络的工作原理,因为 K8s 的网络模型正是建立在这之上的。
2.1 Docker0 网桥与 veth 对
安装 Docker 后,宿主机上会自动创建一个名为docker0的网桥,它充当虚拟交换机的角色。所有容器都连接到这个网桥上,使得容器之间的通信就像在同一局域网中一样。
关键概念解析:
- veth(Virtual Ethernet):veth 是一个成对出现的虚拟网络设备,就像一根虚拟的网线。它的一端连接在容器的网络命名空间中(命名为
eth0),另一端连接在宿主机的docker0网桥上。 - 数据流向:当 Container1 发送数据包时,数据从它的
eth0出发,通过 veth 对到达宿主机的docker0网桥,再由网桥转发给 Container2 或外部网络。
为什么要用 veth 对?因为容器运行在自己的网络命名空间中,拥有独立的网络栈,无法直接使用宿主机的网络接口。veth 对就像一根虚拟网线,连接了容器的网络命名空间和宿主机网络,让容器能够“看见”外界。
2.2 容器访问外部网络
当容器需要访问外部网络(如访问百度)时,数据包需要经过宿主机的网络转发。Docker 默认在宿主机上创建了如下 iptables 规则来实现:
-APOSTROUTING-s172.17.0.0/16!-odocker0-jMASQUERADE这条规则的含义:
-s 172.17.0.0/16:匹配源 IP 为容器网段的流量! -o docker0:排除目标是 docker0 网桥的流量(即容器间通信不处理)-j MASQUERADE:进行源地址转换(SNAT),将容器的源 IP 替换为宿主机的 IP
通俗理解:当容器访问外网时,它报出的是自己的私有 IP(如 172.17.0.2),外网不认识这个 IP,无法回包。MASQUERADE 就是将这个私有 IP 替换为宿主机的公网 IP,让外网能够把数据包回复给宿主机,宿主机再转交给容器。
2.3 外部访问容器(端口映射)
容器的 IP 地址只在宿主机内部有效,外部网络无法直接访问容器。因此,Docker 提供了-p参数将宿主机端口映射到容器端口:
[root@hd1 ~]# docker run -d --name web -p 8080:80 nginx访问宿主机IP:8080就能访问到容器的 80 端口。这个映射通过 iptables 规则实现:
-APREROUTING-tnat-ptcp--dport8080-jDNAT --to-destination172.17.0.2:80这条规则的含义:当外部访问宿主机的 8080 端口时,将目标地址转换为容器的 IP:80,从而实现访问容器。
三、Kubernetes Pod 网络模型
3.1 Pod 网络配置流程
在 Kubernetes 中,Pod 的网络配置与 Docker 容器类似,但更加标准化。
整个网络配置流程由 kubelet 和 CNI 插件协同完成:
第一步:kubelet 收到创建 Pod 的请求后,首先调用容器运行时(如 containerd)创建pause 容器。
第二步:kubelet 调用 CNI 插件为 pause 容器配置网络。
CNI 插件是位于
/opt/cni/bin/目录下的可执行文件,它们根据配置文件(通常在/etc/cni/net.d/)为 Pod 创建网络接口、分配 IP 地址、设置路由规则。
第三步:kubelet 调用容器运行时创建应用容器,并将它们加入 pause 容器的网络命名空间中。这样,同一 Pod 内的所有容器共享同一个网络栈,可以通过localhost互相通信。
第四步:当 Pod 被删除时,kubelet 通过 CNI 插件进行网络资源的清理和回收(释放 IP、删除 veth 接口等)。
3.2 为什么需要 pause 容器?
pause 容器是一个极其轻量级的容器(运行一个永远阻塞的进程),它的核心作用是充当网络命名空间的“持有者”。同一 Pod 内的所有业务容器都加入 pause 容器的网络命名空间,共享同一个 IP 地址和端口空间。
这样做的好处:
- 简化网络管理:Pod 内的所有容器共享同一个 IP,对外表现为一个整体。
- 生命周期管理:pause 容器作为网络命名空间的“锚点”,即使业务容器重启,网络命名空间也不会销毁,保证了 IP 地址的稳定性。
- 资源隔离:网络命名空间独立于容器生命周期,由 pause 容器统一管理。
四、跨节点 Pod 通信 —— CNI 网络插件
在单节点上,Pod 通过 docker0 网桥或类似的网桥就能通信。但 Kubernetes 集群通常包含多个节点,Pod 可以被调度到任意节点上,这就需要不同节点上的 Pod 之间也能够直接通信。
这完全由 CNI 网络插件来实现。其核心问题是:如何让不同节点上的 Pod IP 能够互相路由?
4.1 覆盖网络(Overlay Network)
代表插件:Flannel(VXLAN 模式)
覆盖网络在现有物理网络之上构建一个虚拟的二层网络。跨节点通信时,数据包会被封装在 UDP 包中(常用 VXLAN 协议),通过节点的物理 IP 进行路由,到达目标节点后再解封装还原为原始 Pod IP 数据包。
优点:对底层网络无特殊要求,只要节点之间 IP 可达即可。
缺点:封装和解封装带来性能开销。
4.2 路由模式(Routing Mode)
代表插件:Calico(BGP 模式)
路由模式不使用封装,而是将 Kubernetes 集群当作一个大型路由器来运作。每个节点都配置了到其他节点 Pod 子网的路由,并通过BGP 协议(边界网关协议)将这些路由信息同步给集群路由器,或让节点间相互学习路由。
优点:数据包直接根据 IP 路由转发,性能更高,没有封装开销。
缺点:需要底层网络支持路由配置,节点通常需要在同一二层网络内。
选择建议:
- 公有云环境(如阿里云、AWS):推荐 Flannel 的 host-gw 模式,配置简单
- 私有数据中心:Calico 能覆盖更多场景,提供更强的网络策略能力
五、Calico 三种工作模式详解
Calico 是目前最流行的 Kubernetes CNI 插件之一,支持三种工作模式,分别适用于不同的网络环境。
5.1 IPIP 模式(默认模式)
IPIP 模式是 Calico 的默认模式。当 Pod 跨节点通信时,Calico 使用 IP-in-IP 隧道技术来封装原始 Pod IP 数据包,确保数据包能够通过非本地网络传输。
IPIP模式:原始IP包进入tunl0设备,就会被Linux内核的IPIP驱动劫持,将这个IP包直接封装在一个宿主机网络的IP包中,目的地址为Node2的IP
通信流程:
node1的10.233.1.2和node2的10.233.2.2通信的过程:
请求从10.233.1.2出去,此时:src:10.233.1.2,dest:10.233.2.2
请求会进入tunl0,tunl0会把这个请求封装在一个宿主机网络的IP包中,目的地址为Node2的IP,此时src: 192.168.1.1 dest:192.168.2.2
将src和dest都进行了封装,拆包就能获得真实的src和dest。需要注意这里并不是DNAT和SNAT
请求经过路由,进入node2的tunl0,进行解包,获取真正的dest目标地址,此时:src:10.233.1.2,dest:10.233.2.2
这样请求就到达了目标pod。目标pod回复的过程与这个过程一致。
tunl0(IPIP驱动):工作在内核态的三层(IP层)。它不关心数据内容,只是机械地在外面套一个IP头。不需要用户态进程介入。
工作原理:
- Pod A 发出的原始 IP 包(源 IP: Pod A IP,目标 IP: Pod B IP)进入
tunl0隧道设备。 - Linux 内核的 IPIP 驱动将这个原始 IP 包直接封装在一个新的 IP 包中,新 IP 包的源地址为 Node1 的 IP,目标地址为 Node2 的 IP。
- Node2 收到封装包后,解封装还原出原始 Pod IP 包,转发给 Pod B。
适用场景:节点处于不同网段,需要跨子网通信的环境。
5.2 BGP 模式(路由模式)
BGP 模式不使用任何隧道封装,允许pod与pod直接通信,节点上的路由表通过BGP协议(动态路由协议)直接获得。每个节点上的 Calico 组件通过 BGP 协议,将本节点的 Pod 子网路由信息通告给其他节点,数据包直接根据路由表进行转发。
Calico BGP模式的作用就在于:用BGP把“不同网段”的Node连成一个逻辑上的大二层,使得Pod IP可以直接作为源目地址跨越物理网段通信,且全程不拆包、不改地址。
BGP 模式是所有场景下(无论同网段还是跨网段)性能最佳的选择,因为它无隧道封装开销。唯一的限制是要求节点间三层路由可达(能互相 Ping 通)。只要物理网络能路由,BGP 就能跑,且性能远超 IPIP/VXLAN。
适用场景:追求最佳性能的数据中心环境。
BGP 模式适用于对网络性能要求极高的场景(无隧道损耗),且底层物理网络基础设施支持三层路由(无论是直连二层,还是通过交换机/路由器做三层转发)。在大型数据中心中,BGP 模式常结合架顶交换机(TOR)使用,以规避大二层广播域带来的风险。
5.3 VXLAN 模式
VXLAN(Virtual eXtensible Local Area Network,虚拟可扩展局域网)使用 VXLAN 封装技术在不同节点之间建立逻辑的二层网络。Pod 的 IP 数据包被封装在这个二层网络中,并通过底层物理网络进行通信。
关于 VXLAN 的层次定位(这点容易混淆):
- 从功能视角看:VXLAN 主要解决的是二层(L2)网络跨三层扩展的问题。它能让位于不同物理位置、甚至不同数据中心的虚拟机或容器,感觉像在同一个二层网络中一样通信。
- 从实现视角看:VXLAN 是在三层 IP 网络之上建立虚拟二层网络的技术。它“呈现”给用户的是一个二层网络,但“依赖”并“运行”在三层 IP 网络之上,并使用四层 UDP 协议(端口 4789)进行封装传输。
- 在 Calico 中的定位:Calico 将 VXLAN 作为一种隧道模式来使用,与 IPIP 模式并列,用于解决跨三层网络的 Pod 通信问题。但它与 Calico 的 BGP 模式(纯路由)有本质区别。
优势:突破传统 VLAN 的 4096 个数量限制,跨越三层网络边界,没有广播风暴的限制。
适用场景:大规模云数据中心,需要跨越多个网络区域的 Kubernetes 集群。
5.4 安装calicoctl查看和切换 Calico 工作模式
#下载对应版本的 calicoctl[root@hd1 ~]# curl -L https://github.com/projectcalico/calico/releases/download/<vX.Y.Z>/calicoctl-linux-amd64 -o calicoctl#赋予执行权限并移动到 PATH 目录[root@hd1 ~]# chmod +x calicoctl-linux-amd64[root@hd1 ~]# mv calicoctl-linux-amd64 /usr/local/bin/calicoctl# 查看 Calico 节点状态[root@hd1 ~]# calicoctl node status+--------------+-------------------+-------+----------+-------------+|PEER ADDRESS|PEER TYPE|STATE|SINCE|INFO|+--------------+-------------------+-------+----------+-------------+|192.168.1.12|node-to-node mesh|up|22:23:49|Established||192.168.1.13|node-to-node mesh|up|22:23:45|Established|+--------------+-------------------+-------+----------+-------------+# 查看 Calico 节点列表[root@hd1 ~]# calicoctl get nodes --allow-version-mismatcNAME hd1 hd2 hd3# 查看 IP 池配置(包含当前工作模式)[root@hd1 ~]# calicoctl get ippool -o wide --allow-version-mismatchNAME CIDR NAT IPIPMODE VXLANMODE SELECTOR default-ipv4-ippool10.244.0.0/16trueAlways Never all()# 字段说明:# IPIPMODE = Always → 启用 IPIP 模式(默认)# IPIPMODE = Never → 禁用 IPIP 模式# VXLANMODE = Never → 禁用 VXLAN 模式# VXLANMODE = Always → 启用 VXLAN 模式修改为 BGP 模式(注意:这里的ipipMode: Never表示关闭 IPIP 隧道,从而让 Calico 工作在以 BGP 路由为主的模式下):
[root@hd1 ~]# kubectl edit ippool default-ipv4-ippool修改前:
apiVersion:projectcalico.org/v3kind:IPPoolmetadata:name:default-ipv4-ippoolspec:cidr:10.244.0.0/16ipipMode:AlwaysnatOutgoing:truenodeSelector:all()vxlanMode:Never修改后:
apiVersion:projectcalico.org/v3kind:IPPoolmetadata:name:default-ipv4-ippoolspec:cidr:10.244.0.0/16ipipMode:Never# ← 关闭 IPIP 隧道natOutgoing:truenodeSelector:all()vxlanMode:Never修改后查看路由表,可以看到目标为其他节点 Pod 子网的流量直接走物理网卡(ens33),而非隧道设备(tunl0):
当同时禁用ipip和vxlan的时候,默认就是BGP模式
# IPIP 模式下的路由表(走 tunl0 隧道)[root@hd1 ~]# ip routedefault via192.168.100.2 dev ens33 proto static metric10010.244.59.128/26 via192.168.100.12 dev tunl0 proto bird onlink# BGP 模式下的路由表(直接走物理网卡)[root@hd1 ~]# ip routedefault via192.168.100.2 dev ens33 proto static metric10010.244.59.128/26 via192.168.100.12 dev ens33 proto bird选择哪种模式取决于你的具体需求和网络环境。BGP 模式是所有场景下(无论同网段还是跨网段)性能最佳的选择。如果你的环境需要跨多个网络区域,IP-in-IP 或 VXLAN 模式也是可考虑的。在选择模式时,需要综合考虑性能、安全性和部署的复杂性。
六、BGP 协议介绍
6.1 什么是 BGP?
BGP(Border Gateway Protocol,边界网关协议)是一个 Linux 内核原生支持的、专门用在大规模数据中心里维护不同自治系统(AS)之间路由信息的、无中心的路由协议。
BGP 的核心作用,是让不同网络之间互相筛选并通告最佳路径。
自治系统(AS):指一个组织管辖下的所有 IP 网络和路由器的全体。例如,一个大型企业、一家云服务商,或者整个 Kubernetes 集群,都可以被视为一个自治系统。
6.2 BGP 的工作原理
BGP 的工作流程可以概括为三个步骤:
第一步:建立可靠连接。BGP 使用 TCP 协议(端口 179)作为传输层协议,确保路由信息交换的可靠性。
第二步:建立对等体关系。运行 BGP 的路由器被称为BGP 发言者(Speaker),它们之间通过手动配置建立对等体(Peer)关系来交换路由信息。
第三步:交换和选择路由。对等体之间互相通告各自知道的路由信息,并根据策略选择最优路径加入到路由表中。
6.3 BGP 在 Kubernetes 中的应用场景
在 Calico 的 BGP 模式下,每个节点都扮演着 BGP 发言者的角色:
- 每个节点将自己的 Pod 子网(如 Node1 的
10.244.1.0/24)通过 BGP 通告给其他节点。 - 其他节点收到通告后,在本地路由表中添加对应的路由条目。
- 当某个 Pod 访问另一个节点的 Pod 时,数据包直接根据路由表转发,无需任何封装。
典型应用场景:
- 全球互联网骨干:BGP 是连接全球成千上万个 AS 的基石,承载着超过 90% 的跨国互联网流量。
- 多线接入与优化:云服务商通过 BGP 实现“单 IP 多线路”,让不同运营商的用户都能高速访问。
- 大型数据中心与云环境:在 Kubernetes 中,Calico 等 CNI 插件使用 BGP 来宣告 Pod 的路由,实现高性能的跨节点 Pod 通信。
七、路由反射器(重点)
7.1 为什么需要路由反射器?
在 Calico 的默认配置中,采用的是node-to-node mesh(全互联)模式。这意味着集群中的每个节点都需要与其他所有节点建立 BGP 连接,以交换路由信息。
全互联模式的问题:
- 当节点数量增加时,连接数呈指数级增长(组合数 C(n,2))。
- 每个节点都需要维护大量的 BGP 连接,消耗 CPU 和内存资源。
- 网络开销巨大,限制了集群的扩展能力。
7.2 路由反射器机制
为了解决全互联模式的可扩展性问题,Calico 引入了路由反射器(Route Reflector)机制:
核心思路:在集群中选择少数节点作为路由反射器(中心节点),其他普通节点只需要与这些路由反射器建立 BGP 连接。路由反射器负责收集所有节点的路由信息,并将它们反射(转发)给其他节点。
7.3 配置路由反射器
步骤 1:选择路由反射器节点,并设置集群 ID
选择节点hd1和hd2作为路由反射器,为它们添加集群 ID 注解:
[root@hd1 ~]# kubectl annotate node hd1 projectcalico.org/RouterReflectorclusterid=224.0.0.1node/hd1 annotated[root@hd1 ~]# kubectl annotate node hd2 projectcalico.org/RouterReflectorclusterid=224.0.0.1node/hd2 annotated集群 ID 的作用:集群 ID 用于标识路由反射器的“集群”。具有相同集群 ID 的反射器属于同一个反射器集群,它们之间相互备份。如果多个集群 ID 存在,每个反射器集群需要独立管理。
步骤 2:创建 BGP 对等体配置
创建一个 BGPPeer 资源,定义所有节点(all())与带有route-reflector == 'true'标签的节点建立 BGP 对等关系:
[root@hd1 ~]# cat bgppeer.yamlapiVersion: projectcalico.org/v3 kind: BGPPeer metadata: name: peer-with-route-reflectors spec: nodeSelector: all()# 所有节点都应用此配置peerSelector: route-reflector=='true'# 仅与带有此标签的节点建立对等关系#实际生产环境中,--allow-version-mismatch (忽略版本差异强制应用)不建议加[root@hd1 ~]# calicoctl apply -f bgppeer.yaml --allow-version-mismatch配置解析:
nodeSelector: all():表示所有节点都作为 BGP 客户端。peerSelector: route-reflector == 'true':表示这些 BGP 客户端仅与带有route-reflector == 'true'标签的节点建立对等关系。
在生产环境中,集群 ID 和节点名字要根据实际进行配置,节点名字要换成你实际选的 Master 或专用节点名。
步骤 3:给路由反射器节点打标签
[root@hd1 ~]# kubectl label node hd1 route-reflector=truenode/hd1 labeled[root@hd1 ~]# kubectl label node hd2 route-reflector=truenode/hd2 labeled这一步让步骤 2 中的peerSelector能够选中这些节点。
步骤 4:禁用BGP的全互联模式
[root@hd1 ~]# cat bgpconfig.yamlapiVersion: projectcalico.org/v3 kind: BGPConfiguration metadata: name: default spec: nodeToNodeMeshEnabled:false# 关闭全互联模式[root@hd1 ~]# calicoctl apply -f bgpconfig.yaml --allow-version-mismatch关闭全互联模式后,节点之间不再自动建立 BGP 连接,而是按照 BGPPeer 资源的定义,只与路由反射器建立连接。
验证配置结果
[root@hd1 ~]# calicoctl node statusCalico process is running. IPv4 BGP status +--------------+---------------+-------+----------+-------------+|PEER ADDRESS|PEER TYPE|STATE|SINCE|INFO|+--------------+---------------+-------+----------+-------------+|192.168.1.12|nodespecific|up|08:27:50|Established||192.168.1.13|nodespecific|up|08:27:50|Established|+--------------+---------------+-------+----------+-------------+当PEER TYPE显示为node specific而非mesh或其他时,说明路由反射器模式已成功启用。
不难看到,在私有部署环境里,Calico 项目能够覆盖更多的场景,Calico 的 IPIP/VXLAN 模式或者配合云厂商 ENI(弹性网卡) 的 CNI 插件,是现在公有云上的主流方案
八、K8s 网络优化建议
| 优化建议 | 适用场景 | 原理 |
|---|---|---|
| 节点在同一网段时使用 BGP 模式 | 私有数据中心、节点二层可达 | 避免隧道封装带来的性能开销,直接路由转发 |
| BGP 模式中使用路由反射器 | 集群节点超过 10 个 | 减少 BGP 连接数,从 O(n²) 降为 O(n) |
| 公有云环境使用 Flannel host-gw | 阿里云、AWS 等公有云 | 公有云网络环境简单,host-gw 模式性能好且配置方便 |
| 使用 NetworkPolicy 实现网络隔离 | 需要安全隔离的多租户环境 | Calico 原生支持 Kubernetes NetworkPolicy,Flannel 不支持 |
各插件的对比总结
| 特性 | Calico(BGP) | Calico(IPIP/VXLAN) | Flannel(host-gw) | Flannel(VXLAN) |
|---|---|---|---|---|
| 性能 | ★★★★★ | ★★★ | ★★★★ | ★★★ |
| 封装开销 | 无 | 有 | 无 | 有 |
| 网络策略 | ✅ 支持 | ✅ 支持 | ❌ 不支持 | ❌ 不支持 |
| 跨子网通信 | ❌ 需要 BGP 路由 | ✅ 支持 | ❌ 需要直连 | ✅ 支持 |
| 对底层网络要求 | 高(需 BGP 支持) | 低 | 中(需二层可达) | 低 |
| 推荐场景 | 私有数据中心 | 混合网络环境 | 公有云环境 | 跨子网且无需网络策略 |
核心知识速查卡
| 关键词 | 一句话总结 |
|---|---|
| docker0 网桥 | 宿主机的虚拟交换机,所有 Docker 容器通过它互联 |
| veth 对 | 一根虚拟网线,连接容器的网络命名空间和宿主机的网桥 |
| pause 容器 | Pod 内共享网络命名空间的“锚点容器”,所有业务容器加入它的网络命名空间 |
| CNI 插件 | Kubernetes 网络配置的标准化接口,负责为 Pod 分配 IP 和设置网络 |
| Calico IPIP | 使用 IP-in-IP 隧道封装跨子网流量,适用于三层不相通的环境 |
| Calico BGP | 节点通过 BGP 协议互相通告 Pod 子网路由,直接路由,性能最优 |
| Calico VXLAN | 使用 VXLAN 构建虚拟二层网络,允许跨越三层网络通信 |
| BGP 全互联 | 所有节点两两建立 BGP 连接,节点数增加时连接数指数级增长 |
| 路由反射器 | 解决 BGP 全互联扩展性问题的机制,将 O(n²) 连接降为 O(n) |
| BGP | 边界网关协议,用于 AS 之间交换路由信息,被 Calico 用于 Pod 路由通告 |