Kubernetes集群Consul Pod重启IP变更后DNS恢复方案咨询
这个问题我之前也碰到过,核心原因很明确:kube-dns的stubDomains配置是静态写在ConfigMap里的,当Consul Pod重启获取新IP后,旧的IP还留在配置里,kube-dns不会自动感知并更新。下面给你几个可行的恢复方案,从临时应急到长期根治都有:
1. 手动应急修复(最快解决当前问题)
这是最直接的临时办法,适合紧急恢复服务:
- 第一步,编辑kube-dns的ConfigMap,替换成Consul Pod的新IP:
在打开的编辑器里找到kubectl edit configmap kube-dns -n kube-systemstubDomains字段,把里面的旧IP换成Consul Pod的新IP(可以用kubectl get pods -n <consul-namespace> -o wide查看新IP)。注意格式是JSON数组,别写错括号。 - 第二步,重启kube-dns Pod让新配置生效:
kube-dns的Deployment会自动重建Pod,加载更新后的ConfigMap。kubectl delete pod -l k8s-app=kube-dns -n kube-system
优点:操作简单,几分钟就能恢复;缺点:下次Consul Pod重启还会重复出问题,只能救急。
2. 改用Consul Service的ClusterIP(更稳定的方案)
既然你是用Helm部署的Consul,集群里肯定有对应的Service(比如consul或者consul-dns)——Service的ClusterIP是稳定的,不会随Pod重启变化。把stubDomains里的Pod IP换成Service的ClusterIP就能一劳永逸解决Pod重启的问题:
- 先查Consul Service的ClusterIP:
比如如果Service叫kubectl get svc <consul-service-name> -n <consul-namespace>consul,命名空间是default,就是kubectl get svc consul -n default,看CLUSTER-IP列的值。 - 然后按照方法1的步骤,把kube-dns ConfigMap里的stubDomains IP换成这个ClusterIP,再重启kube-dns。
优点:Service IP稳定,除非Service本身被删除重建,否则不会变;缺点:如果后续Helm升级Consul导致Service重建,ClusterIP可能会变,不过这种情况比Pod重启少得多。
3. 升级到CoreDNS(长期根治方案)
Kubernetes 1.8.x还在用kube-dns,而后续版本替换的CoreDNS支持更灵活的DNS配置,能直接通过Service名称指向上游DNS,自动解析Service的IP变化。如果你有集群升级的计划,建议直接替换成CoreDNS:
- 部署CoreDNS到集群里(适配1.8版本的官方替换指南可以直接参考集群文档)。
- 在CoreDNS的ConfigMap里配置Consul的上游为Service名称,比如:
这里.:53 { errors health kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure upstream fallthrough in-addr.arpa ip6.arpa } consul { forward . consul.default.svc.cluster.local } cache 30 loop reload loadbalance }consul.default.svc.cluster.local是Consul Service的FQDN,CoreDNS会自动解析这个域名对应的ClusterIP,不用手动维护IP。
优点:彻底解决静态IP的问题,后续Consul Pod或Service的IP变化都能自动适配;缺点:需要替换kube-dns,有一定操作成本,适合有长期维护计划的集群。
4. 自动化更新ConfigMap(自定义解决方案)
如果暂时不想升级CoreDNS,也可以写个简单的脚本或者自定义控制器,自动检测Consul Pod的IP变化并更新kube-dns的ConfigMap:
- 举个Shell脚本的例子(可以做成CronJob定期执行):
这个脚本会定期对比Consul Pod的IP和ConfigMap里的IP,不一样就自动更新并重启kube-dns。# 获取当前Consul Pod的IP(假设只有一个Consul Pod,多个的话需要调整) CONSUL_POD_IP=$(kubectl get pods -n default -l app=consul -o jsonpath='{.items[0].status.podIP}') # 获取当前kube-dns ConfigMap里的Consul IP CURRENT_STUB_IP=$(kubectl get configmap kube-dns -n kube-system -o jsonpath='{.data.stubDomains}' | jq -r '.consul[0]') if [ "$CONSUL_POD_IP" != "$CURRENT_STUB_IP" ]; then # 更新ConfigMap kubectl patch configmap kube-dns -n kube-system --type merge -p "{\"data\":{\"stubDomains\":\"{\\\"consul\\\":[\\\"$CONSUL_POD_IP\\\"]}\"}}" # 重启kube-dns kubectl delete pod -l k8s-app=kube-dns -n kube-system fi
优点:完全自动化,不用手动干预;缺点:需要维护额外的脚本或控制器,还要处理多Consul Pod的情况(比如取所有Pod IP组成数组)。
内容的提问来源于stack exchange,提问作者matkam

