嘿,我懂那种感觉。明明在 Kubernetes 集群里部署了两个服务,从 Pod A 去访问 Pod B,结果就是连不上,timeout 或者 connection refused。这种时候,真的会让人怀疑人生。别急,咱们今天就把这事儿掰开揉碎了讲清楚。我是 Agnes,虽然年轻,但在这上面踩过的坑比你吃过的米还多。咱们今天就聊聊 Kubernetes 里最让人头疼的两个角色:CoreDNS 和 iptables 规则,看看它们怎么让你的 Pod 网络“不通”,又该怎么解决。
首先,咱们得有个前提:你的集群网络插件(CNI)是正常工作着的。也就是说,每个 Pod 都能拿到一个 IP,而且不同节点上的 Pod 能互相 ping 通。如果这一步就挂了,那咱们得先解决 CNI 的问题。假设这一步是 OK 的,那问题就出在“服务发现”和“流量转发”这两个环节上。
核心概念:Pod、Service 和 DNS 的关系
在深入代码之前,咱们先理清几个基本概念。Kubernetes 里,Pod 是最小的部署单元,每个 Pod 都有自己的 IP 地址。但是,Pod 的 IP 是不稳定的,它可能会因为重启、迁移而改变。所以,Kubernetes 引入了 Service 这个概念。Service 定义了一组 Pod 的逻辑集合,以及访问它们的方式。Service 本身也有一个 IP 地址,叫做 ClusterIP,这个 IP 是稳定的。
那么,怎么从 Pod A 访问 Service 呢?这里就用到了 DNS。Kubernetes 内置了一个 DNS 服务,默认就是 CoreDNS。当一个 Service 创建时,CoreDNS 会为该 Service 生成一个 DNS 记录。比如,你创建了一个名为 my-service 的 Service,在 default 命名空间下,那么它对应的 DNS 名称就是 my-service.default.svc.cluster.local。任何 Pod 都可以用这个 DNS 名称来访问该 Service。
问题就出在这里:DNS 解析和流量转发,是两个独立但又紧密相关的过程。如果其中任何一个环节出问题,你的 Pod 就访问不了 Service。
第一步:排查 DNS 解析问题
很多情况下,Pod 访问不通,首先怀疑的是 DNS 解析。比如,你在 Pod A 里执行 nslookup my-service.default.svc.cluster.local,结果超时或者返回空。这时候,问题大概率出在 CoreDNS 上。
CoreDNS 是一个插件式的 DNS 服务器,它在 Kubernetes 集群中以 Deployment 的形式运行。我们可以通过查看 CoreDNS 的 Pod 状态和日志来排查问题。
# 查看 CoreDNS Pod 的状态
kubectl get pods -n kube-system -l k8s-app=kube-dns
# 查看 CoreDNS 的日志
kubectl logs -n kube-system <coredns-pod-name>
如果 CoreDNS 的 Pod 处于 CrashLoopBackOff 状态,或者日志里有报错,那问题就很明显了。常见的错误包括:
- ConfigMap 配置错误:CoreDNS 的配置文件存储在 ConfigMap 中,名为
coredns,位于kube-system命名空间。如果配置文件写错了,CoreDNS 就会启动失败。你可以用以下命令查看和编辑配置:
kubectl get configmap coredns -n kube-system -o yaml
kubectl edit configmap coredns -n kube-system
上游 DNS 问题:CoreDNS 需要能够解析外部的域名(比如
kubernetes.default.svc.cluster.local)。如果集群节点的 upstream DNS 配置有问题,CoreDNS 可能无法正常启动。你可以检查/etc/resolv.conf文件,确保它指向了集群内的 DNS 服务。资源不足:CoreDNS 的 Pod 可能被驱逐,或者因为内存/CPU 限制而重启。检查 CoreDNS 的 Deployment 资源限制,以及节点的资源状况。
# 查看 CoreDNS Deployment 的资源配置
kubectl describe deployment coredns -n kube-system
# 查看 CoreDNS Pod 的事件
kubectl describe pod <coredns-pod-name> -n kube-system
如果 DNS 解析没问题,那咱们就得往下看了。
第二步:排查 Service 和 Endpoint 问题
DNS 解析成功,并不意味着流量就能到达正确的 Pod。接下来,我们需要检查 Service 的 Endpoint。Endpoint 是 Service 背后实际提供服务的 Pod 的 IP 地址列表。如果 Endpoint 为空,或者指向了错误的 Pod,那流量自然就过不去。
# 查看 Service 的 Endpoint
kubectl get endpoints my-service -n default
# 查看 Service 的详细描述
kubectl describe service my-service -n default
如果 Endpoint 为空,可能的原因有:
- Label Selector 不匹配:Service 通过 Label Selector 来关联 Pod。如果 Pod 的标签和 Service 的 Selector 不一致,就不会有 Endpoint。检查一下 Service 的 Selector 和 Pod 的标签是否匹配。
# 查看 Service 的 Selector
kubectl get service my-service -n default -o yaml
# 查看 Pod 的标签
kubectl get pods -l app=my-app -n default --show-labels
- Pod 处于非就绪状态:只有处于
Ready状态的 Pod 才会被加入到 Endpoint 中。如果 Pod 的健康检查失败,或者容器还没启动完成,它就不会被选中。检查 Pod 的状态:
kubectl get pods -l app=my-app -n default
kubectl describe pod <pod-name> -n default
- NetworkPolicy 限制:如果你的集群启用了 NetworkPolicy,可能会阻止某些 Pod 被选中为 Endpoint。检查一下是否有相关的 NetworkPolicy 规则。
第三步:深入 iptables 规则——流量是如何转发的
好了,DNS 解析没问题,Endpoint 也正常,但流量还是过不去。这时候,咱们就得深入到 Kubernetes 网络的核心——iptables 规则了。
在传统的 Kubernetes 集群中(没有使用 eBPF 或 IPVS 模式),Service 的流量转发是通过 iptables 规则实现的。当一个 Pod 访问一个 Service 的 ClusterIP 时,iptables 规则会将流量重定向到后端 Pod 的 IP 地址上。
我们可以通过以下命令查看集群中的 iptables 规则:
# 在任意节点上执行,查看 kube-proxy 生成的 iptables 规则
iptables-save | grep -E "KUBE-SERVICE|KUBE-SEP"
这些规则是由 kube-proxy 组件动态生成的。kube-proxy 会监听 Kubernetes API,当 Service 或 Endpoint 发生变化时,它会更新 iptables 规则。
如果 iptables 规则缺失或者错误,就会导致流量无法正确转发。常见的排查方法包括:
- 检查 kube-proxy 的状态:确保 kube-proxy 的 Pod 正在运行,并且没有报错。
kubectl get pods -n kube-system -l k8s-app=kube-proxy
kubectl logs -n kube-system <kube-proxy-pod-name>
- 对比 iptables 规则:在源 Pod 所在的节点和目标 Pod 所在的节点上,分别查看 iptables 规则,确认流量路径是否正确。
# 在源 Pod 所在节点上查看
iptables-save | grep -E "KUBE-SERVICE|KUBE-SEP"
# 在目标 Pod 所在节点上查看
iptables-save | grep -E "KUBE-SERVICE|KUBE-SEP"
- 使用 tc 工具进行抓包:如果 iptables 规则看起来正常,但流量还是过不去,可以使用
tc工具或者tcpdump在节点上进行抓包,看看流量到底发生了什么。
# 在源 Pod 所在节点上,抓取出站流量
tcpdump -i any -nn host <service-cluster-ip> and port <service-port>
# 在目标 Pod 所在节点上,抓取出站流量
tcpdump -i any -nn host <pod-ip> and port <container-port>
- 检查 CNI 插件的 iptables 规则:有些 CNI 插件(比如 Calico、Flannel)也会生成 iptables 规则。这些规则可能会和 kube-proxy 的规则产生冲突。检查一下 CNI 插件的文档,看看是否有相关的配置需要调整。
第四步:其他可能的问题
除了 DNS 和 iptables,还有一些其他因素可能导致 Pod 之间网络不通:
- MTU 问题:如果集群中不同网络的 MTU 值不一致,可能会导致大包丢失。检查一下节点的网络接口 MTU 值,确保它们一致。
# 查看节点的网络接口 MTU 值
ip link show
安全组/防火墙规则:如果集群部署在云上,检查云平台的安全组或防火墙规则,确保端口是开放的。
NodePort/LoadBalancer 类型 Service 的问题:如果你使用的是 NodePort 或 LoadBalancer 类型的 Service,还需要检查 NodePort 是否在节点上正确监听,以及负载均衡器的配置是否正确。
总结
Pod 网络不通,真的是一个很综合的问题。从 DNS 解析,到 Endpoint 匹配,再到 iptables 规则转发,每一步都可能出问题。咱们今天讲了 CoreDNS 和 iptables 规则这两个核心环节,但记住,排查问题的时候要循序渐进,从简到繁。
首先,确认 DNS 解析是否正常;然后,检查 Service 的 Endpoint 是否存在;接着,查看 iptables 规则是否正确生成;最后,考虑其他可能的因素,比如 MTU、安全组等。
希望这篇文章能帮到你。记住,Kubernetes 的网络问题虽然复杂,但只要思路清晰,一步步排查,总能找到问题的根源。加油!
