系列导航:Kubernetes 重建迁移教程系列。本文中的地址均使用 <...> 占位符,不包含真实网络信息。

同一个 Kubernetes 集群中同时出现多段 IP 并不代表网络混乱。节点、Pod、Service 本来就承担不同职责,真正的问题是:地址段是否互不重叠、组件配置是否一致、应用是否错误地依赖了某个临时 IP。

先看一次请求经过哪里

flowchart LR
  A["客户端 Pod"] --> B["Service DNS"]
  B --> C["ClusterIP"]
  C --> D["kube-proxy 或 eBPF Service 转发"]
  D --> E["EndpointSlice"]
  E --> F["目标 Pod IP"]
  F --> G["目标节点"]

这里至少有四类地址:

地址由谁分配是否直接绑定进程主要用途
Node IP物理网络、虚拟化平台或云平台是节点管理、跨节点承载
Pod IPCNI,例如 Calico是Pod 到 Pod 通信
Service ClusterIPkube-apiserver否稳定虚拟入口和负载转发
外部入口 IPLB、VIP、Ingress 或路由器视实现而定集群外访问

Kubernetes 官方网络模型要求 Node、Pod 和 Service 使用互不重叠的地址范围。Service 只是逻辑入口,后端由 EndpointSlice 持续更新。Cluster Networking 和 Service 对此有完整定义。

Node IP:数据包最终要到达的机器

kubectl get nodes -o wide
kubectl get node <node> -o jsonpath='{.status.addresses}'

Node IP 来自现有基础网络。Calico、kubelet、API Server、存储挂载和运维 SSH 都可能使用它。

规划时记录:

  • 节点管理地址段。
  • 默认网关和 MTU。
  • 物理机或虚拟化宿主机故障域。
  • 防火墙允许的 Pod 地址段。
  • 是否存在 VPN、办公网或专线重叠。

不要为了“统一”把 Node IP 并入 Pod CIDR。它们位于不同网络层。

Pod CIDR:CNI 分配给工作负载

Pod CIDR 在 kubeadm 中常写为:

networking:
  podSubnet: <pod-cidr>

Calico 也必须使用相同地址池:

kubectl get ippools.crd.projectcalico.org -o wide
kubectl get pod -A -o wide

每个普通 Pod 获得一个 Pod IP。Pod 重建后 IP 可能改变,因此:

  • 不能把 Pod IP 写进 Nacos 配置。
  • 不能让客户端保存某个 Pod IP。
  • 应通过 Service 或 Headless Service 发现后端。

跨节点 Pod IP 不通时,优先检查 CNI 路由、封装模式、MTU 和 firewalld,而不是修改 Service DNS。

Service CIDR:没有网卡的虚拟地址池

Service CIDR 在 kubeadm 中常写为:

networking:
  serviceSubnet: <service-cidr>

ClusterIP 不会像 Node IP 一样出现在某块网卡上。kube-proxy 的 iptables、IPVS,或 CNI 的 eBPF 数据面负责将它转发到 Endpoint。

kubectl get service -A -o wide
kubectl get endpointslice -A

Service CIDR 只应在集群内部使用。应用应该配置 DNS:

<service>.<namespace>.svc.cluster.local

而不是:

<cluster-ip>

Service 删除重建后 ClusterIP 可能变化,DNS 名称只要 Service 名和 namespace 不变就仍然有效。

CoreDNS 没有创建第四套业务网络

CoreDNS 监听 Kubernetes API,为 Service 和 Pod 生成 DNS 记录。普通 ClusterIP Service 的 DNS 最终解析为 ClusterIP;Headless Service 则返回后端 Pod IP。

kubectl run dns-check --rm -it --restart=Never \
  --image=<approved-dns-image> -- \
  nslookup <service>.<namespace>.svc.cluster.local

DNS 正常只证明名称能够解析,不代表:

  • Service selector 正确。
  • Endpoint 非空。
  • 目标端口正在监听。
  • kube-proxy 转发表正确。

因此还要继续检查:

kubectl -n <namespace> get service <service> -o yaml
kubectl -n <namespace> get endpointslice \
  -l kubernetes.io/service-name=<service> -o wide

为什么不能把三类 IP 统一成一段

假设 Node、Pod 和 Service 使用重叠范围,一个目标地址可能同时被理解为:

  • 本地二层网络中的某台服务器。
  • 需要交给 Calico 的远端 Pod。
  • 需要交给 kube-proxy 的虚拟 Service。

最终路由优先级可能把流量送到错误接口,常见现象包括:

No route to host
connect timed out
某些节点能访问,某些节点不能访问
访问一个 Service 却命中另一台真实主机

“统一”应该指统一规划和统一配置,而不是把所有用途塞进同一个 CIDR。

第 1 步:迁移前收集全部网络

创建 network-plan.csv:

type,cidr,owner,purpose,changeable
node,<node-cidr>,network-team,node-management,false
pod,<pod-cidr>,kubernetes-team,calico,true
service,<service-cidr>,kubernetes-team,clusterip,true
vpn,<vpn-cidr>,network-team,remote-access,false

还要收集:

kubectl -n kube-system get configmap kubeadm-config -o yaml
kubectl get service -A -o json
kubectl get pod -A -o wide
ip route

第 2 步:检查重叠

使用团队认可的 IPAM 或 CIDR 工具检查:

Pod CIDR ∩ Service CIDR = 空集
Pod CIDR ∩ Node CIDR = 空集
Service CIDR ∩ Node CIDR = 空集
三者 ∩ VPN/办公网/专线 = 空集

还要为未来扩容预留余量。不能只按当前 Pod 数计算;滚动发布、Job、DaemonSet 和故障漂移都会临时增加地址消耗。

第 3 步:冻结到版本化配置

至少固定:

manifests/kubeadm.yaml
manifests/calico.yaml
inventory/network-plan.csv
scripts/network-smoke.sh

在创建控制平面后临时修改 Pod CIDR 或 Service CIDR,通常不是普通配置变更,而是一次网络迁移。不要在业务启动期间尝试“顺手统一”。

第 4 步:执行四层冒烟

Pod 到 Pod

kubectl exec <source-pod> -- ping -c 3 <target-pod-ip>

Pod 到 ClusterIP

kubectl exec <source-pod> -- nc -vz <service-ip> <service-port>

Pod 到 Service DNS

kubectl exec <source-pod> -- \
  nc -vz <service>.<namespace>.svc.cluster.local <service-port>

集群外到 Ingress

curl --resolve app.example.com:443:<ingress-address> \
  https://app.example.com/<health-path>

测试 Pod 要覆盖不同节点,否则发现不了单节点 kube-proxy 或防火墙故障。

第 5 步:清理配置中的地址依赖

按以下规则治理:

发现的地址处理方式
Pod IP必须改为 Service
ClusterIP优先改为 Service DNS
Node IP + NodePort确认是否为必要外部入口
Kafka broker 地址单独处理 advertised listener
外部数据库或专线保留并登记所有者

不要盲目把所有 IPv4 字符串替换成 .svc.cluster.local。

完成定义

  • Node、Pod、Service、VPN 和办公网地址段互不重叠。
  • kubeadm 与 CNI 使用相同 Pod CIDR。
  • 所有节点都具备正确的 Pod 路由和防火墙规则。
  • 跨节点 Pod、ClusterIP、Service DNS 和 Ingress 冒烟通过。
  • Kubernetes 内部应用不再依赖 Pod IP。
  • 固定 ClusterIP 仅限经过评审的兼容白名单。

一个集群存在多段 IP 是正常设计;真正应该统一的是网络规划、配置来源和验证方法。