嘿,朋友。我是 Agnes。今天咱们不聊那些干巴巴的教科书定义,而是把 Kubernetes 网络这个“黑盒”彻底拆开,看看里面到底是怎么工作的。
很多新手(甚至老手)在面对 K8s 集群时,最头疼的就是网络问题。DNS 解析失败和Pod 之间 ping 不通,这两件事看似简单,背后却牵扯到整个集群的网络架构设计。
如果你正被这些报错折磨,或者想彻底搞懂原理以便提前规避风险,那这篇文章就是为你准备的。我们会从最直观的故障现象出发,一路深挖到底层原理,最后给你一套可以落地的排错工具箱。
一、 为什么 DNS 解析会失败?先理解 K8s 的“电话簿”
想象一下,你在一个巨大的办公室里工作。同事之间互不相识,只知道工号(IP 地址)。有一天,你想找“数据库服务”谈谈,但你不记得它的工号,只记得它叫 my-db-service。
在 Kubernetes 里,这个“查电话簿”的工作,是由 CoreDNS(或旧的 kube-dns)这个组件完成的。这就是为什么 DNS 是 K8s 网络的命脉。
1.1 故障现象:NXDOMAIN 或 Connection timed out
当你 kubectl exec 进一个 Pod 执行 nslookup 或 curl 时,如果看到这样的报错:
$ kubectl exec -it nginx-pod -- nslookup my-svc
nslookup: can't resolve '(null)': Name does not resolve
或者:
$ kubectl exec -it app-pod -- curl -v http://my-svc:80
curl: (6) Could not resolve host: my-svc
这时候,90% 的情况不是网络断了,而是 DNS 服务本身或者配置出了问题。
1.2 深入排查:三步定位 DNS 故障
第一步:检查 Pod 的 DNS 配置
每个 Pod 启动时,Kubelet 会把集群的 DNS 服务 IP 和域名写入 Pod 的 /etc/resolv.conf 文件中。
# 查看当前 Pod 使用的 DNS 配置
$ kubectl exec -it my-pod -- cat /etc/resolv.conf
nameserver 10.96.0.10 # 这是 Service kube-dns 的 Cluster IP
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
关键点:ndots:5。这个配置意味着,如果你查询的域名点数少于 5 个(比如 my-svc),kubelet 会先尝试在本地域名后缀下查找,再尝试完全限定域名。这解释了为什么跨命名空间访问必须用 my-svc.namespace.svc.cluster.local 这种完整形式。
第二步:检查 CoreDNS Pod 是否运行
$ kubectl get pods -n kube-system -l k8s-app=kube-dns
NAME READY STATUS RESTARTS AGE
coredns-6d46d68f47-8xz99 1/1 Running 0 2d
coredns-6d46d68f47-mn456 1/1 Running 0 2d
如果状态是 CrashLoopBackOff 或 Error,那 DNS 肯定挂了。去查看日志:
$ kubectl logs -n kube-system coredns-6d46d68f47-8xz99
常见错误:
no matches for kind "Service":可能是 CRD 未正确部署。upstream connect error:CoreDNS 无法连接到上游 DNS(比如外网 DNS 被墙)。
第三步:检查 Service 是否存在且有效
$ kubectl get svc my-svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-svc ClusterIP 10.96.0.10 <none> 80/TCP 1h
如果 Service 不存在,或者它的 Selector 没有匹配到任何 Pod,CoreDNS 依然会返回一个 IP(因为 Service 已经创建了),但当用户访问该 IP 时,没有后端 Pod 接收流量,这会表现为“连接拒绝”或“超时”,而不是 DNS 解析失败。
二、 Pod 间连通性测试:不仅仅是 ping
很多开发者第一反应是 ping 另一个 Pod 的 IP。但在 Kubernetes 里,ICMP 协议经常被忽略或阻断。
2.1 为什么 ping 往往不通?
Kubernetes 网络模型规定:Pod 可以通过 IP 互相通信,但 CNI(容器网络接口)插件不保证 ICMP 协议的支持。
- Calico:默认支持 ICMP。
- Flannel:默认支持 ICMP。
- Weave Net:默认支持 ICMP。
- 但! 很多云厂商的 CNI(如 AWS VPC CNI、阿里云 Terway)出于安全或性能考虑,默认丢弃 ICMP 包。
所以,不要依赖 ping 来判断连通性。
2.2 正确的连通性测试方法
方法一:使用 TCP 连接测试(推荐)
创建一个临时的测试 Pod,用它去连接目标 Pod 的 IP 和端口。
# test-tcp-connection.yaml
apiVersion: v1
kind: Pod
metadata:
name: net-test
spec:
containers:
- name: netshoot
image: nicolaka/netshoot
command: ["sleep", "3600"]
# 部署测试 Pod
$ kubectl apply -f test-tcp-connection.yaml
# 进入测试 Pod
$ kubectl exec -it net-test -- bash
# 使用 nc (netcat) 测试 TCP 连通性
# 假设目标 Pod IP 是 10.244.1.5,端口 80
$ nc -zv 10.244.1.5 80
Connection to 10.244.1.5 80 port [tcp/http] succeeded!
如果 nc 失败,说明网络层或应用层有问题。
方法二:使用 HTTP 请求测试
如果目标是一个 Web 服务:
$ curl -v http://<target-pod-ip>:<port>/healthz
2.3 Pod 间通信的基本原理
Kubernetes 的网络模型核心是 “每个 Pod 都拥有独立的 IP 地址”。
graph LR
A[Node 1] --> B[Pod A: 10.244.1.2]
A --> C[Pod B: 10.244.1.3]
D[Node 2] --> E[Pod C: 10.244.2.2]
B <-->|通过 Overlay/路由| E
- 同一节点上的 Pod:通过 veth pair 连接到同一个 Linux Bridge(如
cni0)直接通信。 - 不同节点上的 Pod:通过 CNI 插件构建的 Overlay 网络(如 VXLAN)或路由表转发。
三、 常见排错方案:系统化诊断流程
当你遇到网络问题时,不要慌。按照以下流程图一步步排查。
3.1 诊断流程图
1. 确认问题现象
├── DNS 解析失败? → 进入 DNS 诊断流程
└── 连接超时/拒绝? → 进入连通性诊断流程
2. DNS 诊断
├── Pod 内 resolv.conf 是否正确?
├── CoreDNS Pod 是否 Running?
├── CoreDNS 日志是否有错误?
└── Service 是否存在且 Endpoint 正确?
3. 连通性诊断
├── 同一 Namespace 内 Pod IP 直连?
├── 不同 Namespace 内 Pod IP 直连?
├── Service ClusterIP 是否可达?
├── Endpoint 是否绑定到后端 Pod?
└── NetworkPolicy 是否阻断了流量?
3.2 实战案例 1:Endpoint 缺失
现象:DNS 解析正常,但连接超时。
$ kubectl get svc my-svc
NAME TYPE CLUSTER-IP PORT(S) AGE
my-svc ClusterIP 10.96.0.10 80/TCP 1h
$ kubectl get endpoints my-svc
NAME ENDPOINTS AGE
my-svc <none> 1h
原因:Service 的 Selector 没有匹配到任何 Label 正确的 Pod。
解决:
$ kubectl describe svc my-svc
# 查看 Selector
# 确保后端 Pod 有对应的 Label
$ kubectl get pods -l app=my-app --show-labels
3.3 实战案例 2:NetworkPolicy 阻断
现象:Pod A 可以 ping 通 Pod B,但无法访问 Pod B 的端口。
原因:集群中启用了 NetworkPolicy,默认拒绝所有入站流量。
检查:
$ kubectl get networkpolicy
NAME POD-SELECTOR AGE
deny-all <none> 1h
$ kubectl describe networkpolicy deny-all
解决:创建允许流量的 NetworkPolicy。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-http
spec:
podSelector:
matchLabels:
app: my-app
policyTypes:
- Ingress
ingress:
- from:
- podSelector: {}
ports:
- protocol: TCP
port: 80
3.4 实战案例 3:CNI 插件故障
现象:新创建的 Pod 无法获得 IP,或者 Pod 之间无法通信。
检查:
$ kubectl get pods -n kube-system | grep calico
$ kubectl logs -n kube-system calico-node-xxxxx
如果看到 IPv4 address could not be assigned,可能是 IPAM(IP 地址管理)池用尽了。
解决:
# 检查 IP 池使用情况
$ ipam block list
# 清理未使用的 IP 或扩展 IP 池
四、 给小朋友的比喻:Kubernetes 网络就像一座城市
为了让这个复杂的概念更清晰,我们来打个比方。
- Pod 是城市里的 房子。每个房子有自己的门牌号(IP 地址)。
- Service 是 黄页。你想找“张伟”(某个应用),不需要知道他的具体住址,只需要查黄页(DNS)就能找到。
- CoreDNS 是 邮政局。它负责把名字翻译成地址。
- CNI 插件 是 道路系统。它负责让房子之间的路连通。
- NetworkPolicy 是 门禁系统。它规定哪些人可以进入哪栋房子。
DNS 故障 就像邮政局罢工了,你不知道怎么找到人。 连通性故障 就像道路被封了,或者门禁太严格,人进不去房子。
五、 总结与最佳实践
- 不要依赖 ping:使用
nc或curl测试 TCP 连通性。 - 检查 Endpoint:Service 存在不等于有后端 Pod,
kubectl get endpoints是必须的步骤。 - 理解 DNS 后缀:跨 Namespace 访问使用完整域名
svc.namespace.svc.cluster.local。 - 审查 NetworkPolicy:任何新的网络策略都可能阻断流量,务必测试。
- 查看日志:CoreDNS 和 CNI 插件的日志是排错的金矿。
Kubernetes 的网络模型虽然复杂,但只要理解其核心组件(Pod、Service、DNS、CNI)的相互作用,就能快速定位和解决问题。希望这篇文章能帮你解开困惑,祝你在 K8s 的网络世界里畅通无阻!
如果你有具体的排错案例,欢迎在评论区分享,我们一起分析。
