2. Pod网络与Service网络基础
在OpenShift中,容器网络并不是“一张网”,而是由多个相互叠加的地址平面共同构成:Pod网络负责容器之间的直接可达性,Service网络负责为动态变化的Pod集合提供稳定入口,而kube-proxy与OVN则负责把“稳定入口”翻译成“当前真实的后端地址”。理解这三层关系,是排查网络问题的起点。
Pod IP:每个Pod一个可路由地址
OpenShift默认使用OVN-Kubernetes作为网络插件,为每个Pod分配一个集群内唯一的IP地址。这个地址来自集群配置的clusterNetwork网段,例如10.128.0.0/14,并按节点进一步细分为hostSubnet。每个节点从自己的子网中为Pod分配IP,因此Pod IP天然带有“节点归属”信息。
Pod IP的特点是:生命周期与Pod绑定,Pod重建即更换。这意味着任何直接依赖Pod IP的访问方式都不稳定。例如一个Deployment扩容到3个副本,三个Pod分别获得10.128.2.5、10.128.2.6、10.128.3.7,一旦某个Pod被驱逐重建,新Pod会拿到新IP。因此,业务之间不应直接写Pod IP,而应通过Service访问。
在节点上可以用以下命令观察Pod IP与节点子网的对应关系:
oc get pod -o wide
oc get hostsubnet
oc get pod my-app-7d9f8c6b5-abcde -o jsonpath='{.status.podIP}'
Service:三种对外暴露方式
Service为一组Pod提供固定虚拟IP(VIP),即ClusterIP。它通过标签选择器(selector)动态关联后端Pod,无论Pod如何变化,Service的ClusterIP保持不变。OpenShift支持三种主要类型:
- ClusterIP:仅集群内部可达,分配一个
serviceNetwork网段内的虚拟IP,例如172.30.0.0/16中的172.30.45.10。适合内部微服务调用。 - NodePort:在每个节点上开放一个固定端口(默认范围
30000-32767),外部可通过节点IP:NodePort访问。适合测试或没有负载均衡器的环境。 - LoadBalancer:在NodePort基础上,向底层基础设施(如云平台或MetalLB)申请一个外部IP,形成
外部IP:端口 → Service → Pod的完整链路。适合生产环境对外暴露。
三种类型并非互斥,而是层层叠加:LoadBalancer包含NodePort,NodePort包含ClusterIP。创建示例如下:
apiVersion: v1
kind: Service
metadata:
name: web-svc
spec:
type: NodePort
selector:
app: web
ports:
- port: 80
targetPort: 8080
nodePort: 30080
其中port是Service端口,targetPort是Pod容器实际监听端口,nodePort是节点暴露端口。三者关系是排查Service不通时的第一检查点。
Endpoint与EndpointSlice:Service背后的真实地址
Service本身只是规则,真正承载流量的是Endpoint。当Service创建后,Endpoint控制器会根据selector筛选出匹配的Pod,把它们的IP:targetPort写入Endpoint对象。若selector匹配不到任何Pod,Endpoint为空,Service访问就会失败。
在大规模集群中,单个Endpoint对象可能包含数千个地址,更新时全量推送会造成性能瓶颈。因此Kubernetes引入EndpointSlice,把Endpoint按100个地址一组切片,并附加endpointslice.kubernetes.io/managed-by等标签。EndpointSlice支持按需更新,显著降低控制面压力。OpenShift中默认启用EndpointSlice,Endpoint对象仍保留以兼容旧组件。
观察命令:
oc get endpoints web-svc
oc get endpointslice -l kubernetes.io/service-name=web-svc
oc describe endpointslice web-svc-abcde
如果EndpointSlice中endpoints列表为空,或conditions.ready为false,说明Pod未通过就绪探针,流量不会转发到该Pod。
kube-proxy与OVN流表:把VIP翻译成Pod IP
Service的ClusterIP是一个虚拟地址,并不配置在任何网卡上。真正完成“VIP → Pod IP”转换的,是数据面组件。传统Kubernetes使用kube-proxy,通过iptables或IPVS规则实现;OpenShift默认使用OVN-Kubernetes,由ovn-controller在每个节点上把Service和Endpoint信息编译成OpenFlow流表,写入OVS网桥。
当Pod访问ClusterIP时,流量进入OVS网桥,命中流表后执行DNAT,把目的地址改为某个Endpoint的Pod IP,并可能伴随SNAT以保证回程对称。整个过程对应用透明。可以用以下命令查看流表:
oc get svc web-svc -o jsonpath='{.spec.clusterIP}'
oc rsh -n openshift-ovn-kubernetes ovnkube-node-xxxxx
ovs-ofctl dump-flows br-int | grep 172.30.45.10
流表中通常能看到ct(commit)、nat(dst=10.128.2.5:8080)等动作,说明该ClusterIP已被正确解析到后端Pod。若流表缺失,常见原因是Endpoint未就绪、OVN控制器未同步或节点间隧道异常。
三层地址的排障顺序
当Service访问异常时,建议按“Service → EndpointSlice → 流表 → Pod”的顺序逐层确认:
| 检查层 | 命令 | 正常表现 | 异常含义 |
|---|---|---|---|
| Service | oc get svc web-svc | ClusterIP已分配,端口正确 | 无ClusterIP说明未分配或类型错误 |
| EndpointSlice | oc get endpointslice -l kubernetes.io/service-name=web-svc | endpoints列表非空且ready | 为空说明selector不匹配或Pod未就绪 |
| 流表 | ovs-ofctl dump-flows br-int | 存在对应ClusterIP的DNAT规则 | 缺失说明OVN未同步或节点异常 |
| Pod | oc get pod -o wide | Pod Running且IP在EndpointSlice中 | IP不一致说明Endpoint未更新 |
掌握Pod IP、Service、EndpointSlice与OVN流表之间的映射关系后,后续排查DNS解析、网络策略、Ingress路由等问题时,就能快速定位故障发生在哪一层,而不是在“网络不通”这个模糊结论上反复试探。