嘿,朋友。如果你正在为 Kubernetes 网络抓狂——比如 Pod 之间死活连不上,或者 Service 突然解析失败导致业务雪崩——那你找对地方了。别被那些枯燥的理论吓跑,我们今天就像剥洋葱一样,一层层把 K8s 的网络内核给拆解开。我会用最直白的话,配合真实的故障场景和代码,带你彻底搞懂从 Pod 通信到 Service 发现的每一个环节。准备好了吗?我们要开始这场网络探险了。
1. 地基:CNI 插件与 Pod IP 的世界观
首先,你得明白一个核心概念:在 Kubernetes 眼里,每个 Pod 都是一个独立的“虚拟机”,拥有独立的 IP 地址。 这个 IP 在整个集群内是全局唯一的,而且 Pod 重启后 IP 会变,但应用本身不应该感知到这一点。这就是为什么我们需要 CNI(Container Network Interface)插件。
常见的 CNI 插件有 Calico、Flannel、Weave Net 等。它们就像是网络的“路由器”和“网线铺设工”。
1.1 为什么 Pod 能跨节点通信?
想象一下,你的集群有两台节点 Node A 和 Node B。
- Node A 上的 Pod A (
10.244.1.5) 想访问 Node B 上的 Pod B (10.244.2.3)。 - 如果没有 CNI 插件,Node A 根本不知道
10.244.2.3在哪里,就像你在北京打电话给一个没有区号的号码。
CNI 插件通过以下方式解决这个问题:
- 虚拟网桥:在每个节点上创建一个
veth pair(虚拟以太网设备对)。一端连进容器的网络命名空间,另一端连到节点的虚拟网桥(如cni0或flannel.1)。 - 路由表/Overlay 隧道:CNI 插件会在所有节点的路由表中添加规则,告诉系统:“如果要访问
10.244.x.x网段的数据包,请通过特定的接口发送出去。”- Calico:使用 BGP 协议在节点间交换路由信息,性能极高,接近裸金属速度。
- Flannel:早期版本使用 UDP 封装,后来支持 VXLAN,通过隧道技术在物理网络上叠加一个虚拟网络。
1.2 实战:检查你的 CNI 状态
如果 Pod 无法 ping 通其他节点的 Pod,第一步永远是检查 CNI。
# 查看当前使用的 CNI 插件
kubectl get pods -n kube-system | grep -E 'calico|flannel|weave'
# 在节点上检查虚拟接口
ip addr show cni0 # 如果是 Calico/CNI 默认配置
ip addr show flannel.1 # 如果是 Flannel
# 检查路由表
ip route | grep 10.244
常见坑点:如果你的节点防火墙(iptables/firewalld)没有放行 CNI 所需的端口(如 Calico 的 5473 BGP 端口,Flannel 的 8285 UDP 端口),跨节点通信就会静默失败。
2. 桥梁:Service 与 kube-proxy 的秘密
Pod 的 IP 是不稳定的,重启就变。为了让外部(或其他 Pod)能稳定访问服务,Kubernetes 引入了 Service。Service 是一个抽象概念,它定义了一组 Pod 的逻辑集合和一个访问它们的策略。
2.1 Service 是如何工作的?
当你在 YAML 中定义一个 Service 时,Kubernetes 会分配一个 ClusterIP(虚拟 IP)。这个 IP 并不真正存在于任何网络接口上,它是一个“魔法 IP”。
关键角色:kube-proxy
kube-proxy 是每个节点上运行的网络代理。它负责将 Service 的 ClusterIP 映射到后端 Pod 的真实 IP。它主要通过两种模式工作:
- userspace 模式(已过时,太慢):数据包被重定向到 kube-proxy 进程,由它进行负载均衡。
- iptables 模式(默认,较老):kube-proxy 监听 API Server,更新节点的 iptables 规则。当流量到达 ClusterIP 时,iptables 将其随机转发到一个后端 Pod。
- IPVS 模式(推荐,高性能):基于 Linux 内核的 IP Virtual Server,性能远超 iptables,支持更复杂的负载均衡算法(如 RR, LC, DH 等)。
2.2 深入 iptables vs IPVS
如果你的 Service 背后有成百上千个 Pod,iptables 模式会导致规则链过长,匹配效率急剧下降,甚至引发 CPU 飙升。
切换为 IPVS 模式示例:
在 Master 节点的 kube-proxy ConfigMap 中配置:
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs
ipvs:
scheduler: rr # 轮询调度
strictARP: true # 开启严格 ARP,防止 IP 冲突
然后重启 kube-proxy:
kubectl delete pod -n kube-system -l k8s-app=kube-proxy
验证 IPVS 规则:
# 在任意节点上执行
ipvsadm -Ln
你会看到类似这样的输出,清晰地展示了 Service IP 到 Pod IP 的映射:
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.96.0.10:53 rr
-> 10.244.1.5:53 Route 1 0 0
-> 10.244.2.3:53 Route 1 0 0
3. 灵魂:CoreDNS 与 DNS 解析机制
很多“连接超时”问题,其实不是网络不通,而是 DNS 解析失败。在 K8s 中,DNS 是由 CoreDNS(或旧的 kube-dns)提供的。
3.1 DNS 解析流程
当你在一个 Pod 里执行 nslookup my-service 时,发生了什么?
- Pod 配置:每个 Pod 的
/etc/resolv.conf都被自动注入,指向集群内部的 DNS 服务器(通常是10.96.0.10,即 CoreDNS 的 ClusterIP)。 - 查询请求:Pod 向
10.96.0.10:53发送 UDP/TCP 查询。 - CoreDNS 处理:CoreDNS 收到请求,根据查询类型(A记录、SRV记录等)进行解析。
- 如果是短名称(如
my-service),它会追加默认的搜索域(如.default.svc.cluster.local)。 - 如果是完全限定域名(FQDN,如
my-service.default.svc.cluster.local),它直接查找。
- 如果是短名称(如
- 返回结果:CoreDNS 返回对应的 ClusterIP 或 Endpoint IP。
3.2 常见 DNS 问题与排查
问题 1:Pod 内无法解析 Service 名称
症状:ping: my-service: Name or service not known
原因:
- CoreDNS Pod 崩溃或 Pending。
- 网络插件问题导致 Pod 无法访问 CoreDNS 的 ClusterIP。
- 搜索域配置错误。
排查步骤:
# 1. 检查 CoreDNS 状态
kubectl get pods -n kube-system -l k8s-app=kube-dns
# 2. 进入一个测试 Pod,手动解析
kubectl run -it --rm debug-pod --image=busybox --restart=Never -- sh
# 3. 在 Pod 内测试 DNS
nslookup my-service
# 或者测试具体域名
nslookup my-service.default.svc.cluster.local
# 4. 检查 resolv.conf
cat /etc/resolv.conf
问题 2:DNS 解析超时
症状:nslookup 卡住很久才报错,或者直接超时。
原因:
- CoreDNS 配置了上游 DNS 服务器(如
8.8.8.8),而上游 DNS 响应慢或不可达。 - 网络带宽不足或丢包严重。
- CoreDNS 资源限制过低(CPU/Memory Limit)。
解决方案:
优化 CoreDNS 部署的资源限制:
apiVersion: apps/v1
kind: Deployment
metadata:
name: coredns
namespace: kube-system
spec:
template:
spec:
containers:
- name: coredns
resources:
limits:
memory: "170Mi"
cpu: "100m" # 适当增加 CPU 限制
requests:
memory: "70Mi"
cpu: "100m"
检查 CoreDNS 日志:
kubectl logs -n kube-system -l k8s-app=kube-dns
如果看到大量 timeout 或 refused 错误,可能是上游 DNS 问题。你可以修改 CoreDNS 的 Corefile 配置,减少上游查询频率或更换上游 DNS。
4. 实战:解决跨节点连接超时
假设你有两个微服务:frontend 和 backend。frontend 部署在 Node A,backend 部署在 Node B。frontend 调用 backend 的服务时出现间歇性超时。
4.1 诊断思路
确认 Service 存在且正确:
kubectl get svc backend # 确保 ClusterIP 和 Port 正确确认 Endpoints 存在:
kubectl get endpoints backend # 应该列出 backend Pod 的 IP 和端口测试网络连通性: 在
frontendPod 内部执行:# 先测试 DNS nslookup backend # 再测试 TCP 连通性 telnet <backend-cluster-ip> <port> # 或者使用 nc (netcat) nc -zv <backend-cluster-ip> <port>检查节点间网络: 在 Node A 上 ping Node B 上的 Pod IP:
ping 10.244.2.3 # Node B 上的 backend Pod IP如果 ping 不通,说明 CNI 网络有问题。检查 iptables 规则:
iptables -L -n -v | grep 10.244
4.2 常见陷阱:NetworkPolicy 拦截
如果你使用了 NetworkPolicy(网络策略),它可能会默认拒绝所有流量。
场景:你创建了一个 NetworkPolicy,只允许来自特定 Namespace 的流量访问 backend。
解决:确保 NetworkPolicy 允许 frontend 所在的 Namespace 访问 backend。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: default
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: frontend-ns # 允许 frontend-ns 命名空间的流量
ports:
- protocol: TCP
port: 8080
4.3 常见陷阱:节点防火墙
在某些云环境或自定义主机中,iptables 或 firewalld 可能阻止了跨节点的网络流量。
检查:
# 在 Node A 和 Node B 上执行
sudo iptables -L -n | grep DROP
sudo firewall-cmd --list-all
解决:确保允许 CNI 插件所需的端口和协议。对于 Calico,通常需要允许 TCP/5473 (BGP) 和 UDP/4789 (VXLAN,如果使用)。
5. 高级话题:Headless Service 与 DNS 记录
有时候,你不需要 Service 的负载均衡,而是希望直接获取每个 Pod 的 IP。这时你需要使用 Headless Service(无头服务)。
5.1 什么是 Headless Service?
在 Service 定义中,将 clusterIP 设置为 None。
apiVersion: v1
kind: Service
metadata:
name: my-headless-service
spec:
clusterIP: None # 关键配置
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
5.2 DNS 行为
对于 Headless Service,CoreDNS 不会返回一个 ClusterIP,而是直接返回所有匹配 Pod 的 A 记录。
查询:
nslookup my-headless-service.default.svc.cluster.local
响应:
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: my-headless-service.default.svc.cluster.local
Address: 10.244.1.5
Name: my-headless-service.default.svc.cluster.local
Address: 10.244.2.3
5.3 应用场景
- StatefulSet:数据库集群(如 MySQL、Kafka)需要固定的网络标识符,每个 Pod 有自己的 IP,客户端需要直接连接到特定实例。
- gRPC 服务发现:某些 gRPC 框架依赖 DNS SRV 记录或服务发现,Headless Service 提供了更细粒度的控制。
6. 总结与最佳实践
Kubernetes 网络是一个复杂的系统,涉及 CNI、kube-proxy、CoreDNS 等多个组件的协同工作。要解决跨节点连接超时和 DNS 解析失败的问题,关键在于:
- 理解网络模型:知道 Pod IP、Service ClusterIP、Endpoint IP 之间的关系。
- 检查组件状态:定期监控 CNI 插件、kube-proxy 和 CoreDNS 的健康状态。
- 善用调试工具:
kubectl exec、nslookup、telnet、nc、tcpdump是你的好朋友。 - 注意网络安全策略:NetworkPolicy 和防火墙规则可能会无意中阻断流量。
- 选择合适的 CNI 和 kube-proxy 模式:对于大规模集群,IPVS + Calico/Flannel 是性能较好的组合。
记住,网络问题往往不是单一原因造成的,需要层层剥离,从应用层到传输层再到网络层,一步步定位。希望这篇指南能帮你拨开迷雾,让 K8s 网络变得透明可控。如果还有疑问,随时回来看看,或者在社区里提问,大家都会很乐意帮忙的!
