首页
/ Kubernetes The Hard Way 实战:为集群手动配置 Pod 网络路由(Provisioning Pod Network Routes)

Kubernetes The Hard Way 实战:为集群手动配置 Pod 网络路由(Provisioning Pod Network Routes)

2026-09-05 09:25:22作者:管翌锬

本篇基于 kubernetes-the-hard-way 教程中的“Provisioning Pod Network Routes”实验,讲解在纯静态部署(无脚本、无 CNI 自动编排)的 Kubernetes 集群中,为什么需要为每个 worker 节点手动添加 Pod CIDR 路由,以及如何利用 machines.txt 机器数据库配合 ip route 命令完成跨节点 Pod 网络互通。读完本文,你可以理解 Kubernetes 网络模型中“每个节点一个 Pod 网段”的设计,并掌握路由规划、配置与验证的完整操作流程。

为什么需要手动配置 Pod 网络路由

在 Kubernetes 的网络模型中,Pod 被调度到某个节点后,会获得一个来自该节点 Pod CIDR 范围的 IP 地址。但在完成本实验之前,同一节点上的 Pod 可以通信,不同节点上的 Pod 之间却无法通信——原因是各节点之间缺少把对端 Pod 网段指向对端节点内部 IP 的网络路由。

本实验的目标就是:为每个 worker 节点创建一条路由,把“节点 A 的 Pod CIDR 网段 → 经由节点 A 的内部 IP 转发”这一映射写入其余节点的 Linux 路由表。

需要说明的是,这并非实现 Kubernetes 网络模型的唯一方式,Flannel、Calico 等 CNI 插件可以自动完成这些路由/Overlay 工作。本教程(以及 README 的定位)刻意选择“the hard way”,即用最原始的手工方式完成每一步,目的是让学习者彻底理解集群引导的每个底层环节。

前置条件:理解 machines.txt 机器数据库

本实验所有操作都在 jumpbox 上执行,依赖前面实验创建的 machines.txt 文件(见 Provisioning Compute Resources)。该文件作为“机器数据库”,每行一台机器,字段格式为:

IPV4_ADDRESS FQDN HOSTNAME POD_SUBNET
  • 第 1 列 IPV4_ADDRESS:机器内部 IP 地址;
  • 第 2 列 FQDN:完全限定域名,如 node-0.kubernetes.local
  • 第 3 列 HOSTNAME:主机名,如 node-0
  • 第 4 列 POD_SUBNET:分配给该节点用于 Pod 地址的唯一 IP 网段。

教程示例中的机器数据库(IP 已做掩码处理)如下:

XXX.XXX.XXX.XXX server.kubernetes.local server
XXX.XXX.XXX.XXX node-0.kubernetes.local node-0 10.200.0.0/24
XXX.XXX.XXX.XXX node-1.kubernetes.local node-1 10.200.1.0/24

注意 server(控制平面节点)没有 POD_SUBNET 列——它只承载控制平面组件,不运行 Pod,因此无需为其配置 Pod 路由。

Pod 网段从哪里来:CNI bridge 配置与集群 CIDR

理解路由之前,值得先看看 Pod IP 实际是如何分配的。在 worker 节点引导阶段(Bootstrapping the Kubernetes Worker Nodes),教程把 CNI 配置模板下发到每台节点,并用 sedSUBNET 占位符替换为该节点在 machines.txt 中的 POD_SUBNET

for HOST in node-0 node-1; do
  SUBNET=$(grep ${HOST} machines.txt | cut -d " " -f 4)
  sed "s|SUBNET|$SUBNET|g" \
    configs/10-bridge.conf > 10-bridge.conf
  ...
done

替换后的 CNI 配置(模板见 10-bridge.conf)结构如下:

{
  "cniVersion": "1.0.0",
  "name": "bridge",
  "type": "bridge",
  "bridge": "cni0",
  "isGateway": true,
  "ipMasq": true,
  "ipam": {
    "type": "host-local",
    "ranges": [
      [{"subnet": "10.200.0.0/24"}]
    ],
    "routes": [{"dst": "0.0.0.0/0"}]
  }
}

从这份配置可以看出:

  • 每个节点通过 cni0 网桥为 Pod 创建网络命名空间,host-local IPAM 插件从本节点的 SUBNET 网段中分配 Pod IP;
  • routes: [{"dst": "0.0.0.0/0"}] 表示容器内默认路由指向网桥网关,Pod 出节点流量由节点 IP 转发;
  • 节点侧的 kubelet-config.yamlmaxPods: 16 限制了单节点 Pod 数量,而 /24 的 Pod 网段(254 个可用地址)足以覆盖这一上限。

与此同时,集群层面使用统一的 10.200.0.0/16 作为集群 CIDR:在 kube-controller-manager.service 中通过 --cluster-cidr=10.200.0.0/16 传入,kube-proxy-config.yaml 中也声明了 clusterCIDR: "10.200.0.0/16"。各节点的 10.200.0.0/2410.200.1.0/24 正好是这个 /16 网段下的子网,三者共同构成了完整的地址规划:

集群 CIDR:  10.200.0.0/16
├── node-0 Pod CIDR: 10.200.0.0/24
└── node-1 Pod CIDR: 10.200.1.0/24

创建路由:提取变量并写入各节点路由表

打印各 worker 实例的内部 IP 与 Pod CIDR

jumpbox 上执行以下命令块,从 machines.txt 中用 grep 按主机名匹配行、cut 按空格切列,提取出控制平面和两个 worker 节点的 IP 与 Pod 网段:

{
  SERVER_IP=$(grep server machines.txt | cut -d " " -f 1)
  NODE_0_IP=$(grep node-0 machines.txt | cut -d " " -f 1)
  NODE_0_SUBNET=$(grep node-0 machines.txt | cut -d " " -f 4)
  NODE_1_IP=$(grep node-1 machines.txt | cut -d " " -f 1)
  NODE_1_SUBNET=$(grep node-1 machines.txt | cut -d " " -f 4)
}

这里 cut -d " " -f 1 取第 1 列(IPV4_ADDRESS),-f 4 取第 4 列(POD_SUBNET)。这些变量在同一个 shell 会话中保持有效,供后续路由命令使用。

在 server 节点添加两条路由

控制平面节点需要能访问两个 worker 节点上的所有 Pod,因此在 server 上添加指向两个 Pod 网段的路由:

ssh root@server <<EOF
  ip route add ${NODE_0_SUBNET} via ${NODE_0_IP}
  ip route add ${NODE_1_SUBNET} via ${NODE_1_IP}
EOF

展开后等价于:

ip route add 10.200.0.0/24 via <node-0 内部 IP>
ip route add 10.200.1.0/24 via <node-1 内部 IP>

在两个 worker 节点上互加对方网段路由

worker 节点只需路由到对端节点的 Pod 网段(本网段内的 Pod 通过本地 cni0 网桥直接可达,无需路由)。

node-0 上添加指向 node-1 Pod 网段的路由:

ssh root@node-0 <<EOF
  ip route add ${NODE_1_SUBNET} via ${NODE_1_IP}
EOF

node-1 上添加指向 node-0 Pod 网段的路由:

ssh root@node-1 <<EOF
  ip route add ${NODE_0_SUBNET} via ${NODE_0_IP}
EOF

至此,任意两个节点间都建立了“对端 Pod CIDR → 对端节点内部 IP”的路由映射,跨节点 Pod 通信路径打通:

node-0 上的 Pod (10.200.0.x)
  → node-0 内核路由:10.200.1.0/24 via <node-1 IP>
  → node-1 内核路由:目标 IP 属于本地 cni0 网段,直接投递
  → node-1 上的 Pod (10.200.1.x)

验证路由表

分别登录三台机器查看路由表,确认新路由已生效。

ssh root@server ip route

预期输出(XXX 为掩码后的实际地址):

default via XXX.XXX.XXX.XXX dev ens160
10.200.0.0/24 via XXX.XXX.XXX.XXX dev ens160
10.200.1.0/24 via XXX.XXX.XXX.XXX dev ens160
XXX.XXX.XXX.0/24 dev ens160 proto kernel scope link src XXX.XXX.XXX.XXX

server 上应同时出现两条 Pod 网段路由。

ssh root@node-0 ip route
default via XXX.XXX.XXX.XXX dev ens160
10.200.1.0/24 via XXX.XXX.XXX.XXX dev ens160
XXX.XXX.XXX.0/24 dev ens160 proto kernel scope link src XXX.XXX.XXX.XXX
ssh root@node-1 ip route
default via XXX.XXX.XXX.XXX dev ens160
10.200.0.0/24 via XXX.XXX.XXX.XXX dev ens160
XXX.XXX.XXX.0/24 dev ens160 proto kernel scope link src XXX.XXX.XXX.XXX

node-0 上只有 10.200.1.0/24(node-1 的网段),node-1 上只有 10.200.0.0/24(node-0 的网段),各节点仅保留对端路由,符合“本网段本地可达、对端网段走路由”的预期。

小结与后续步骤

  • 地址规划是前提machines.txt 第 4 列的 POD_SUBNET 与集群 CIDR(10.200.0.0/16,见 kube-controller-manager.servicekube-proxy-config.yaml)共同决定了路由目标网段的划分,三者必须一致。
  • 路由是跨节点互通的关键一环:CNI bridge 配置(10-bridge.conf)只解决了“节点内 Pod 拿 IP”的问题;本实验用三条 ip route add 命令解决了“跨节点 Pod 可达”的问题。
  • 适用前提与限制:该手工路由方案假设所有节点位于同一二层/可路由网络,且 ip route add 写入的是非持久化路由——节点重启后需要重新执行,这也是生产环境中使用 Flannel/Calico 等 CNI 自动管理路由的原因。教程 README 也明确说明,该集群的搭建结果不视为生产就绪。

路由配置完成后,集群的 Pod 网络层即全部就绪,下一步可执行 Smoke Test 实验,通过创建 nginx Deployment、Port Forward、NodePort 服务等实际操作验证整个集群(包括跨节点 Pod 通信)是否正常工作。

登录后查看全文
热门项目推荐
相关项目推荐