kube-dns异常:特定节点Pod DNS解析偶发'reply from unexpected source'错误求助
这个reply from unexpected source错误的根源很明确——当你的Pod在node01上访问kube-dns Service时,有一半概率请求被转发到本地的kube-dns Pod(100.96.8.239),但这个kube-dns Pod回复时直接用了自己的Pod IP,而你的Pod期望回复来自Service IP(100.64.0.10),导致DNS客户端验证失败。
核心原因分析
在Kubernetes的iptables模式kube-proxy下,当本地Pod访问同一节点上的Service后端Pod时,需要通过**SNAT(源地址转换)**将请求的源IP替换为节点IP,或者通过hairpin模式让回复流量经过kube-proxy,确保回复的源IP是Service IP。如果node01上的kube-proxy规则缺失了这部分配置,就会出现这种“回复来源不符”的问题。
排查与解决步骤
1. 检查节点的桥接iptables参数
首先确认node01上的内核参数是否正确开启,这是kube-proxy生成规则的前提:
# 在node01节点上执行 sysctl net.bridge.bridge-nf-call-iptables sysctl net.bridge.bridge-nf-call-ip6tables
如果输出是0,需要立即开启并永久生效:
# 临时生效 sysctl -w net.bridge.bridge-nf-call-iptables=1 sysctl -w net.bridge.bridge-nf-call-ip6tables=1 # 永久生效,写入sysctl配置文件 echo "net.bridge.bridge-nf-call-iptables=1" >> /etc/sysctl.conf echo "net.bridge.bridge-nf-call-ip6tables=1" >> /etc/sysctl.conf
2. 检查kube-proxy的hairpin模式配置
Kubernetes 1.8版本中,默认可能没有开启hairpin模式,这会导致本地Pod访问本地Service后端时出现SNAT问题。检查kube-proxy的ConfigMap:
kubectl -n kube-system get configmap kube-proxy -o yaml
找到config.conf中的hairpinMode字段,如果值为none,修改为promiscuous-bridge(适合用网桥的网络插件,比如flannel):
apiVersion: v1 data: config.conf: |- apiVersion: kubeproxy.config.k8s.io/v1alpha1 kind: KubeProxyConfiguration mode: "iptables" hairpinMode: "promiscuous-bridge" # 其他配置...
保存后,重建所有kube-proxy Pod让配置生效:
kubectl -n kube-system delete pod -l k8s-app=kube-proxy
3. 验证kube-dns的iptables规则
在node01上检查kube-dns Service对应的iptables SNAT规则是否存在:
# 替换为你的kube-dns Service的hash,可通过kubectl get svc kube-dns -o yaml找到对应的规则前缀 iptables-save | grep -A 15 "KUBE-SVC-TCOU7JCQXEZGVUNU"
正常情况下,应该能看到针对本地Pod流量的SNAT规则,类似:
-A KUBE-SVC-TCOU7JCQXEZGVUNU -s 100.96.0.0/16 -d 100.64.0.10/32 -p udp -m udp --dport 53 -j KUBE-SEP-XXXXXXX -A KUBE-SEP-XXXXXXX -s 100.96.8.239/32 -j MASQUERADE # 这个就是SNAT规则
如果没有这条MASQUERADE规则,说明kube-proxy没有正确生成规则,重启kube-proxy后应该会自动生成。
4. 检查kube-proxy日志
如果以上步骤都没解决问题,查看node01上kube-proxy的日志,看是否有规则生成失败的报错:
kubectl -n kube-system logs -l k8s-app=kube-proxy --field-selector spec.nodeName=node01
日志中如果有类似Failed to ensure chain或者Error updating iptables的信息,说明节点的iptables环境有问题,可能需要清理旧的规则后重启kube-proxy:
# 在node01上清理kube-proxy相关的iptables规则 iptables-save | grep -v KUBE- | iptables-restore systemctl restart kube-proxy
预防措施
- 确保所有节点的
net.bridge.bridge-nf-call-iptables参数默认开启,可以在kops的集群配置中添加这个内核参数,避免新节点出现同样问题。 - 若条件允许,升级Kubernetes集群到较新版本(1.8.x已停止维护),新版本的kube-proxy对本地流量的处理逻辑更完善。
内容的提问来源于stack exchange,提问作者whites11

