【架构实战】Kubernetes网络模型深度解析:从Pod通信到Ingress网关实战

📅 2026/8/20 21:12:55
【架构实战】Kubernetes网络模型深度解析:从Pod通信到Ingress网关实战
Kubernetes网络模型深度解析从Pod通信到Ingress网关实战一、为什么K8s网络让无数人头疼上午聊完 Istio 服务网格很多同学会问Istio 的 Sidecar 拦截的是服务间流量那流量在进入服务网格之前是怎么在 Kubernetes 集群里流动的Pod 之间到底怎么通信为什么 Service 的 IP 有时 ping 不通却能用Ingress 和 Service 又是什么关系这一篇我们把 Kubernetes 网络这条主线彻底捋清楚从 Pod 的 IP 是怎么来的到跨节点流量怎么走再到外部流量怎么进来最后附上实战排查手册。1.1 传统网络与K8s网络的本质差异在传统虚拟机/物理机架构里网络模型非常简单一台机器一个 IP防火墙规则写在主机上端口冲突自己管理。运维对网络有绝对的掌控感。但 K8s 把这一切打碎了维度传统主机网络Kubernetes 网络IP 分配固定、手工规划Pod IP 动态分配、随时漂移通信主体主机 ↔ 主机Pod ↔ Pod、Pod ↔ Service网络边界物理网卡/交换机虚拟网络命名空间 veth服务发现固定 IP 端口Service DNS动态解析安全控制防火墙规则NetworkPolicy一层层策略核心矛盾业务代码还在用IP:端口的思维写调用但 Pod 的 IP 是临时的——扩容、故障迁移、滚动更新都会让 IP 变。K8s 网络要解决的第一件事就是在 IP 随时变化的前提下让通信依然可靠。1.2 K8s网络要解决的四个问题Pod 之间的通信同节点 Pod、跨节点 Pod 怎么互通Pod 与 Service 的通信IP 会变的 Pod怎么稳定地被访问Service 与外部的通信集群外部比如数据库、第三方 API怎么访问集群内服务南北向流量入口用户的浏览器请求怎么到达集群里的应用这四个问题就是 K8s 网络的四个层次。下面一层一层拆。二、K8s网络模型一条必须遵守的宪法K8s 对网络有一条硬性要求称为CNIContainer Network Interface规范核心就三条每个 Pod 拥有独立的 IP集群内唯一Pod 之间可以直接通信不需要 NAT无论是否同节点Pod 访问节点、节点访问 Pod也不需要 NAT为什么这三条如此重要因为只有IP 全网可达、不搞地址转换才能让 Service、Ingress、Istio 这些上层组件基于一个统一、简单的地址空间做文章。任何 CNI 插件Flannel、Calico、Cilium……都必须满足这个模型。2.1 网络命名空间与veth pair先看最小单元一个 Pod 的网络长什么样。┌─────────────────────────── Pod ───────────────────────────┐ │ ┌──────────────┐ ┌──────────────┐ │ │ │ 容器 A │ │ 容器 B │ │ │ │ (业务进程) │ │ (Sidecar) │ │ │ └──────┬───────┘ └──────┬───────┘ │ │ │ eth0 │ │ │ └────────┬─────────┘ │ │ ┌────┴─────┐ │ │ │ pause │ ← Pod 的网络根容器 │ │ │ 容器 │ 持有 eth0 IP │ │ └────┬─────┘ │ └──────────────────┼─────────────────────────────────────────┘ │ veth0veth pair 的一端 ▼ ┌─────────────────────┐ │ cni0 网桥/隧道 │ ← 由 CNI 插件创建 └─────────────────────┘关键点Pod 里的所有容器共享一个网络命名空间——这个命名空间由 pause沙箱容器持有业务容器包括 Sidecar都把自己的 eth0 挂进去。所以 Pod 内容器通过 localhost 就能互相访问这也是 Istio Sidecar 能拦截流量的基础。而 Pod 的 eth0 另一端是通过veth pair虚拟网线连到 CNI 插件创建的虚拟网络设备上。数据从容器 eth0 出来就到了 CNI 插件的管辖范围。2.2 三大主流CNI实现怎么选CNI 插件数据面技术性能网络策略适用场景FlannelVXLAN / Host-GW中❌ 不支持小集群、快速上手、学习环境CalicoBGP / IPIP高✅ 完整生产主流策略要求高CiliumeBPF最高✅ 极强大规模、高吞吐、可观测性选型建议学习/试验Flannel一条命令装完原理简单。生产通用Calico网络策略成熟社区大坑少。性能极致/大规模CiliumeBPF 内核态转发延迟低一个量级还自带可观测性Hubble但内核版本要求较高5.8 更佳。注意网络策略NetworkPolicy不是 CNI 自带的Flannel 就不支持。如果你需要默认拒绝 白名单的安全隔离直接选 Calico 或 Cilium。三、Pod间通信原理从同节点到跨节点3.1 同节点通信网桥转发两个 Pod 在同一个节点上时通信路径非常短Pod A(10.244.1.2) ──veth── cni0 网桥 ──veth── Pod B(10.244.1.3)数据包从 Pod A 的 eth0 出来经 veth 到达节点的 cni0 网桥网桥查 MAC 地址表直接转发给 Pod B 的 veth。全程不离开节点性能损耗几乎为零。3.2 跨节点通信隧道封装Pod 在节点 110.244.1.0/24要访问节点 2 的 Pod10.244.2.0/24两个网段不同数据包怎么过去以 Flannel VXLAN 模式为例节点1 节点2 ┌──────────────────────────┐ UDP 8484 ┌──────────────────────────┐ │ Pod A 10.244.1.2 │ │ Pod B 10.244.2.3 │ │ │ │ │ ▲ │ │ ▼ │ │ │ │ │ cni0 网桥 │ │ cni0 网桥 │ │ │ │ │ │ │ │ ▼ │ │ │ │ │ flannel.1 (VTEP) │ │ flannel.1 (VTEP) │ │ │ │ │ │ │ │ ▼ 原始包 VXLAN头 │ │ │ 解封装还原原始包 │ │ eth0 10.0.0.11 ──────────►│──────────────────│◄─ eth0 10.0.0.12 │ └──────────────────────────┘ 物理网络 └──────────────────────────┘VXLAN 的做法是把 Pod 的原始数据包整个装进一个 UDP 包里外层目的地址是目标节点的物理 IP通过物理网络传输到达后再解封装还原。对底层网络完全无感——哪怕物理交换机不支持任何特殊协议也能跑。Calico 的 BGP 模式则不同它把节点当作 BGP 路由器直接广播这些 Pod 网段在这个节点数据包不封装、直接路由性能更好但要求物理网络允许云厂商 VPC 通常需要配置路由表或 IPIP 模式。四、Service与kube-proxy稳定访问的基石Pod IP 会漂移那业务怎么稳定访问答案是Service。Service 是一个虚拟的稳定入口它有一个固定的虚拟 IPClusterIP通过 Label Selector 动态关联一组 Pod。Pod 挂了、扩了、变了Service 的 IP 不变。4.1 Service三种类型类型作用访问方式适用场景ClusterIP集群内部虚拟 IP集群内访问服务间调用默认NodePort每个节点开放一个端口节点IP:端口 外部访问测试、非云环境暴露LoadBalancer云厂商 LB NodePort负载均衡器 IP云上对外暴露4.2 kube-proxy三种转发模式kube-proxy 负责把访问 ClusterIP 的流量转发到后端 Pod有三种实现模式原理性能特点userspace用户态代理转发差老古董已弃用iptables内核 Netfilter 规则链中默认模式规则多时延迟升高IPVS内核 LVS 负载均衡高规则少、支持多种调度算法生产建议直接开 IPVS。iptables 模式下Service 数量一多上千条规则每条新连接都要遍历规则链延迟明显IPVS 基于哈希表O(1) 查找性能稳定。4.3 ClusterIP转发链路拆解访问my-service:8080ClusterIP 10.96.0.10时发生了什么客户端 Pod │ 访问 10.96.0.10:8080 ▼ PREROUTING ── KUBE-SERVICES 链 │ 匹配 ClusterIP 10.96.0.10 ▼ KUBE-SVC-XXXX 链负载均衡 │ 按权重跳转到后端 ▼ KUBE-SEP-YYYYEndpointPod A / Pod B / Pod C │ DNAT 改写目的地址为 Pod IP ▼ 真实 Pod10.244.1.2:8080这就是为什么 ClusterIP “ping 不通却能用”——ClusterIP 是 iptables/IPVS 里的一条虚拟规则不是真实网卡地址ICMP 没人应答但 TCP 流量会被规则 DNAT 到真实 Pod所以业务访问完全正常。五、DNS与服务发现让调用方不再硬编码IPService 解决了稳定 IP但代码里写死 ClusterIP 依然不优雅——换个环境 IP 就变了。K8s 的答案是DNS 服务发现通常由 CoreDNS 提供。5.1 自动生成的DNS记录K8s 会自动为每个 Service 生成 DNS 记录service-name.namespace.svc.cluster.local比如 namespaceprod下的order-service集群内任何 Pod 都可以直接curl http://order-service.prod.svc.cluster.local:8080/api/orders同一 namespace 内还能简写curl http://order-service:8080/api/orders5.2 服务发现实战示例apiVersion:v1kind:Servicemetadata:name:order-servicenamespace:prodspec:selector:app:order-serviceports:-port:8080# Service 端口targetPort:8080# Pod 容器端口配合 Deployment 的app: order-service标签这套配置就完成了DNS 解析 → Service → 后端 Pod的完整链路。代码里只需要写服务名IP 的事全交给 K8s。六、南北向流量Ingress实战Service 解决了集群内部和节点级的暴露但生产环境的需求是一个域名 80/443 端口路由到多个服务。用 NodePort 一个个暴露端口显然不行端口冲突、无法按域名分流。这就轮到Ingress登场。6.1 Ingress vs LoadBalancer维度LoadBalancerIngress层级L4TCP/UDPL7HTTP/HTTPS按域名/路径路由❌✅TLS 终结部分✅成本每个服务一个 LB贵一个 LB 入口多个服务共用典型场景数据库、gRPC、非 HTTPWeb 应用、API 网关6.2 部署Nginx Ingress ControllerIngress 本身只是一个 API 对象真正干活的是Ingress Controller社区主流是 ingress-nginx底层是 Nginx Lua# 以 Helm 方式部署 ingress-nginxhelm repoaddingress-nginx https://kubernetes.github.io/ingress-nginx helm repo update helminstallingress-nginx ingress-nginx/ingress-nginx\--namespaceingress-nginx\--create-namespace\--setcontroller.service.typeLoadBalancer部署后所有 Ingress 规则由这个控制器监听并动态生成 Nginx 配置。6.3 Ingress规则配置实战假设有两个服务blog-service博客和api-serviceAPI要求www.example.com→ blog-serviceapi.example.com→ api-service带 TLSapiVersion:networking.k8s.io/v1kind:Ingressmetadata:name:example-ingressannotations:nginx.ingress.kubernetes.io/rewrite-target:/$2spec:rules:-host:www.example.comhttp:paths:-path:/pathType:Prefixbackend:service:name:blog-serviceport:number:80-host:api.example.comhttp:paths:-path:/v1(/|$)(.*)pathType:ImplementationSpecificbackend:service:name:api-serviceport:number:8080tls:-hosts:-api.example.comsecretName:api-tls-secret请求链路全貌用户浏览器 │ https://api.example.com/v1/orders ▼ 云LBLoadBalancer ▼ Ingress ControllerNginx443/80 │ 按 Hostapi.example.com 路径 /v1/ 匹配规则 │ TLS 终结rewrite 为 /orders ▼ api-service:8080ClusterIP ▼ kube-proxy → 真实 Pod一句话总结 Ingress 的价值把域名、路径、TLS、灰度、限流这些七层能力集中在一个入口统一管理业务团队只管写 Ingress 规则不用碰 LB。七、网络安全NetworkPolicy实战K8s 网络默认全通——所有 Pod 之间都能互访。生产环境这显然不行支付服务凭什么能被任意 Pod 调用此时需要NetworkPolicy做精细化隔离。7.1 默认拒绝一切入站apiVersion:networking.k8s.io/v1kind:NetworkPolicymetadata:name:default-deny-ingressnamespace:prodspec:podSelector:{}# 匹配命名空间所有 PodpolicyTypes:-Ingress# 只管控入站这条策略一落地prod命名空间所有 Pod 的入站流量全部被拒——任何新服务上线默认零暴露必须显式加白名单。7.2 只允许网关访问订单服务apiVersion:networking.k8s.io/v1kind:NetworkPolicymetadata:name:allow-gateway-to-ordernamespace:prodspec:podSelector:matchLabels:app:order-servicepolicyTypes:-Ingressingress:-from:-podSelector:matchLabels:app:api-gatewayports:-protocol:TCPport:8080效果只有带app: api-gateway标签的 Pod 能访问 order-service 的 8080 端口其他全部隔离。默认拒绝 显式放行是生产集群的标准姿势。注意NetworkPolicy 依赖 CNI 支持Calico/Cilium 均可Flannel 不生效且策略要按命名空间维度规划好否则排查起来非常痛苦。八、网络排查实战手册网络问题占了 K8s 排障的一半。按下面的顺序排查能少走很多弯路。8.1 Pod之间不通# 1. 确认 Pod 状态和 IPkubectl get pod-owide-nprod# 2. 进入源 Pod 测试连通性kubectlexec-itsrc-pod-nprod --pingdst-pod-ip# 3. 不通则查 CNI 状态kubectl get pods-nkube-system|grep-Eflannel|calico|ciliumkubectl logs-nkube-systemcni-pod# 4. 检查 NetworkPolicy 是否误拦kubectl get networkpolicy-A常见原因CNI 组件异常、NetworkPolicy 拦截、节点路由表缺失Calico BGP 未建立。8.2 DNS解析失败# 在 Pod 内测试 DNSkubectlexec-itpod--nslookuporder-service.prod.svc.cluster.local# 检查 CoreDNSkubectl get pods-nkube-system|grepcoredns kubectl logs-nkube-systemcoredns-pod--tail50常见原因CoreDNS 副本数不足建议≥2、resolv.conf里的search域被覆盖重点查dnsPolicy、上游 DNS 不通。8.3 Service访问不通# 1. 检查 Endpoints 是否有后端kubectl get endpointsservice-nprod# 如果 ENDPOINTS 为空 → selector 没匹配上 Pod最经典的坑# 2. 检查 kube-proxy 模式与状态kubectl get pods-nkube-system|grepkube-proxy# 3. 检查 iptables/IPVS 规则# IPVS 模式ipvsadm-ln|grepcluster-ip最常见的坑Service 的selector标签和 Pod 标签不一致导致 Endpoints 为空Service 看起来存在但永远连不通。九、总结把 K8s 网络这条主线串起来CNI 插件解决Pod 怎么拿到 IP、怎么互通——Flannel/Calico/Cilium 按需选型Service kube-proxy解决Pod IP 漂移怎么稳定访问——ClusterIP 是虚拟规则生产开 IPVSCoreDNS解决代码不写死 IP——服务名就是地址Ingress解决外部流量怎么按域名/路径进来——七层统一入口NetworkPolicy解决谁能访问谁——默认拒绝 白名单。回到开头的问题Istio 建立在 K8s 网络之上——K8s 网络保证包能到Istio 保证流量怎么治理。理解了这一层网络地基再看服务网格、再看云原生架构都会有豁然开朗的感觉。下一篇可以聊聊Kubernetes 调度与资源管理把 Pod 是怎么被安放到节点上的原理讲透敬请期待。