2026/10/16 8:54:05

K8s中Pod无法解析域名?从CoreDNS到DNS策略的完整排障指南

K8s中Pod无法解析域名?从CoreDNS到DNS策略的完整排障指南 1. 先把现象拆清楚“不能ping通域名”到底卡在哪一层线上K8s集群最容易碰到的一类怪问题就是Pod里ping某台外部服务器或某个内部服务的域名不通但是直接ping对应的IP却是通的。很多同学第一反应是“CoreDNS挂了吧”然后开始重启CoreDNS Pod。说实话我刚开始也这么干后来发现这样既解决不了问题还容易把现场搞丢。正确做法是先冷静下来把“ping域名不通”这个现象拆开弄清楚它到底是DNS解析失败还是ICMP网络路径不通又或者是目标服务本身就不允许ping。先说一个基本链路当你在一个Pod里执行ping www.example.com时命令首先会把域名交给C库的解析器也就是读取Pod里的/etc/resolv.conf向里面配置的nameserver发起DNS查询拿到A记录以后再发起ICMP请求。所以“ping域名不通”其实包含了两个环节域名到IP的解析以及IP到目标的网络连通性。如果域名能解析出IP、但ping不通IP那是路由或安全组的问题跟CoreDNS关系不大如果连解析都失败比如报unknown host或Temporary failure in name resolution那才需要把矛头指向集群内的DNS链路。正因为这个原因我建议进入Pod后先做两个最基础的动作第一步直接ping一个已知的内网IP确认从Pod出发的网络数据面是通的第二步用nslookup或dig查询域名确认解析是否正常。光靠肉眼判断“ping不通域名”就认定是CoreDNS故障很容易被表面现象带偏。实际情况中有相当比例的“ping域名不通”其实是目标域名原本就没有公网解析记录或者集群里的NetworkPolicy把访问外网的流量拦了CoreDNS本身并没有问题。把现象拆细后面排查才会少走弯路。1.1 “解析失败”和“网络不通”是完全不同的两回事这里要特别强调“解析失败”和“网络不通”的差异。在K8s集群里这个差异直接决定了你要去看CoreDNS还是去看CNI插件的路由。我们可以用一个小实验来帮助理解进入一个运行中的Pod执行ping 10.96.0.10这里的10.96.0.10是CoreDNS Service的ClusterIP。如果这个IP能通说明Pod到集群Service网络的转发是正常的至少数据面的承载没问题。再执行nslookup kubernetes.default.svc.cluster.local如果能解析出ClusterIP那起码说明Kubernetes集群内部的DNS链路是通的。但如果反过来ping ClusterIP也不通问题可能出现在CNI插件、kube-proxy或者Pod网络命名空间上这时候再去查CoreDNS就是南辕北辙。还有一个常见现象在Pod里ping域名时命令长时间卡住不动最后报ping: sendmsg: Network is unreachable。这个错误更像Pod没有默认路由或者CNI网关不可达和DNS解析失败的表现完全不同。DNS解析失败通常报的是unknown host或者在应用日志里看到Could not resolve host: xxx。所以我的经验是遇到这类问题时不要急着去翻CoreDNS日志先手动分成两条线一条叫“数据面连通性”负责确认Pod到各网段的IP通信是否正常另一条叫“控制面解析”负责确认DNS查询是否被正确处理。两条线各自定位再汇合到一起判断。如果数据面没问题但控制面解析异常再把注意力放到CoreDNS和上游DNS的转发关系上。1.2 常见的“假性DNS故障”有哪些还有一种容易误导人的情况它被我叫作“假性DNS故障”Pod里解析域名偶尔变慢、或者只在特定时间段失败你以为CoreDNS出问题了实际上问题出在/etc/resolv.conf里的search域和ndots选项上。举个例子集群默认的resolv.conf一般长这样nameserver 10.96.0.10 search default.svc.cluster.local svc.cluster.local cluster.local options ndots:5这段配置的意思是当你在Pod里访问一个不带点的短域名比如mydb解析器会尝试依次组合mydb.default.svc.cluster.local、mydb.svc.cluster.local、mydb.cluster.local等域名最后才尝试直接查询mydb。其中ndots:5代表只要域名里的点号数量小于5就会先把域名作为集群内部搜索域的一部分去尝试解析。这会导致一个很典型的表象查询外部短域名时CoreDNS收到大量带着search后缀的DNS请求如果CoreDNS的上游转发处理超时应用侧就会感觉“卡了好几次才成功”看起来像是解析失败。真实原因是配置里的ndots太高并不是CoreDNS不可用。另一个“假性故障”是Pod镜像里的工具链太精简。比如某些基于distroless或精简busybox的镜像连nslookup、dig、ping都可能没有或者ping命令的行为和普通机器不一样。你进入Pod以后执行ping它报bad address www.example.com以为解析失败其实只是这个精简版ping命令不依赖系统解析器。所以排查前先确认Pod里有哪些排查工具没有的话就用kubectl run临时起一个带完整工具集的调试Pod或者用kubectl debug复制共享进程命名空间。这些准备工作看着笨却能省下大量时间。2. 理解CoreDNS的工作方式才能快速定位问题不少运维同学把CoreDNS看作一个黑盒Pod/etc/resolv.conf里写了它的ClusterIP解析不了就觉得是它挂了。但黑盒心态会让你在排查时无从下手。CoreDNS本质上是一个插件化的DNS服务器它本身并不存储域名信息也不具备递归解析能力而是通过一系列插件来组合成一条完整的处理链。K8s集群内所有Pod的域名解析请求都会先落到CoreDNS它再根据配置决定是直接回答集群内Service域名还是转发给上游DNS服务器。理解了这条链排查时就能按环节逐个验证。CoreDNS在集群里的典型数据流是这样的Pod里的应用发起DNS查询请求通过ClusterIP转发到某一个CoreDNS PodCoreDNS先看查询域名是否匹配kubernetes插件的管辖范围比如*.cluster.local匹配的话就直接从K8s API里查Service或Endpoints信息返回如果不匹配就由forward插件转发给上游DNS服务器等上游返回结果后再回给Pod。这条链上任何一环出问题表现为Pod里的解析不通但真正的病灶可能相差很远。2.1 CoreDNS在集群中到底扮演什么角色CoreDNS在K8s里最核心的职责是把集群内部域名解析出来。你通过my-service.namespace.svc.cluster.local访问另一个服务这个域名并没有在任何公网DNS服务器上存在只有CoreDNS能通过Kubernetes API实时获取Service和Pod列表并返回对应的ClusterIP或PodIP。这也是为什么它必须能稳定访问K8s API Server并且依赖定期同步的对象数据。如果CoreDNS所在节点和API Server之间有网络抖动或者RBAC权限被改坏节点上的CoreDNS Pod可能出现“能起但查不了集群域名”的诡异现象。除了集群内部域名CoreDNS还要负责把外部域名转发给上游。默认配置里的forward . /etc/resolv.conf意思是非集群域名的所有请求都转发给某个上游DNS。如果上游DNS是部署在宿主机上的systemd-resolved它监听的可能是一个像127.0.0.53这样的本地地址。这里就埋了一个经典坑CoreDNS Pod运行在容器网络里127.0.0.53指向的是CoreDNS容器自身的loopback而不是宿主机所以转发出去必然失败。很多刚接触K8s的同学会遇到Pod里解析任何外部域名都失败、但集群内域名正常的现象根源往往就在这个上游地址配置上。所以CoreDNS的角色更像“代理”对内部域名它直接回答对外部域名它要找到一条能走的转发通道。这两类职责对网络环境的要求完全不同。内部域名要求CoreDNS能访问API Server外部域名要求CoreDNS能访问上游DNS服务器而且上游DNS服务器必须在CoreDNS的容器网络内可达。排查询题时我们要先确认出问题的域名究竟是内部域名还是外部域名然后分别检查对应的链路。内部域名挂了优先怀疑CoreDNS和API Server的通信外部域名挂了优先怀疑forward目标地址和网络策略。2.2 Corefile插件链的关键配置项CoreDNS一切行为都体现在Corefile里默认安装在kube-system命名空间下名为coredns的ConfigMap中。一个典型的Corefile大概长这样.:53 { errors health ready kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure fallthrough in-addr.arpa ip6.arpa } forward . 10.10.10.53 { max_concurrent 1000 } cache 30 loop reload loadbalance }这里每个插件都有讲究。errors负责把错误日志输出到标准输出排查时必备health会在http://:8080/health提供健康检查端点这是Pod存活探针的基础ready用于就绪检查当CoreDNS完成插件初始化后才返回就绪kubernetes插件负责监听集群Service和Pod变化处理cluster.local相关域名并处理反向解析的in-addr.arpa和ip6.arpa区域forward负责把非集群域名转发给指定的上游DNScache给解析结果加一个TTL缓存loop用来检查配置里是否存在解析环路reload允许ConfigMap变更后自动加载新配置但触发时会有短暂抖动。forward插件里有个容易被忽略的参数max_concurrent。在大规模集群中如果同时有大量Pod发起外部域名解析转发请求并发过高CoreDNS会排队表现为解析延迟突然飙升。默认情况下max_concurrent没有限制这意味着突发流量可能把CoreDNS的goroutine打满甚至导致OOM。建议在Corefile里显式设置一个合理的并发上限比如1000或500并且给CoreDNS配置limits避免它把节点内存吃光。设置上限后超出部分的请求会立刻返回失败虽然从应用角度看还是解析失败但至少可以把故障范围控制在CoreDNS自身而不是拖垮整个节点。cache参数也很关键。默认是cache 30表示对缓存结果保留30秒。如果你频繁变更某个外部域名的解析记录CoreDNS可能在缓存周期内一直返回旧IP。某些运维同事排查时发现“明明上游已经改了Pod里却一直解析到旧IP”第一反应是CoreDNS配置错了查了半天才发现是缓存策略。对于集群内部域名kubernetes插件自身有一套缓存机制可以通过参数调整。实战中如果要验证配置变更可以在测试Pod里用dig ttlid观察TTL也可以临时把Cache关掉再查。总之不要把影响面都归结到CoreDNS“宕机”很多解析异常其实是插件参数造成的“软故障”。2.3 Pod侧DNS参数dnsPolicy、dnsConfig和ndots除了CoreDNS自身配置K8s还给了每个Pod几个控制DNS行为的参数它们同样能制造“解析不正常”的假象。dnsPolicy决定Pod的resolv.conf怎么生成默认值是ClusterFirst意思是集群内域名走CoreDNS外部域名也通过CoreDNS代理出去。与之相对的还有Default让Pod直接继承所在节点的resolv.confNone完全忽略集群默认配置以及ClusterFirstWithHostNet用于hostNetwork类型的Pod。如果Pod的dnsPolicy被设置成Default那么Pod内部看到的nameserver就是宿主机上的DNS配置比如127.0.0.53或者云厂商内网DNS。这种情况下解析集群内部域名kubernetes.default.svc.cluster.local多半是失败的因为宿主机DNS并不认识cluster.local这个私有域。还有不少同学会在Pod上通过dnsConfig手动指定nameserver一旦填错例如漏了/etc/resolv.conf里的search域解析同样会失败。K8s允许dnsConfig和dnsPolicy组合使用Pod的resolv.conf会默认带上集群的search域和ndots。修改时要格外小心不要在YAML里随便覆盖整个resolv.conf。ndots这个参数我在前文已经提过它是排查“外部域名偶尔解析超时”的高频元凶。默认ndots:5对K8s内部服务是友好的因为Service名通常带很多点比如my-service.namespace.svc.cluster.local。但对于访问外部域名尤其是不带点的短域名解析器会先尝试把域名拼接上集群search域例如www.baidu.com.default.svc.cluster.local。CoreDNS对这类查询会先查找本地集群域名找不到再转发给上游上游也会因为不存在返回NXDOMAIN。虽然ndots不会直接让最终解析失败但每次外部域名解析都要多产生几次无效查询在高并发场景下会放大CoreDNS的负载也容易让人误判为网络问题。如果你的业务Pods大量访问短域名可以考虑调整ndots为2或者把search域精简到最小集合但必须评估对集群内Service访问的影响。3. 完整排查与修复实操从Pod内到CoreDNS一层层往下挖下面这套排查流程是我在线上真实排障时沉淀下来的几乎每次都能定位到根因。整体思路是从现象侧开始先确认问题范围再逐层向内检查。整个过程不需要重启任何组件纯粹靠命令和日志就能把病灶缩小到某个具体环节这也是排障的基础素养先别破坏现场能只读就只读能临时验证就临时验证。3.1 第一步进入Pod内抓取第一手配置和解析结果排查第一步找一个正在报障的业务Pod执行kubectl exec进入容器先看/etc/resolv.conf内容。这个文件决定Pod内所有进程把DNS请求发给谁。我通常用下面几个命令kubectl exec -it pod-name -n namespace -- cat /etc/resolv.conf kubectl exec -it pod-name -n namespace -- nslookup kubernetes.default.svc.cluster.local kubectl exec -it pod-name -n namespace -- nslookup 故障域名如果Pod里没有nslookup可以临时创建一个调试Pod挂到同一个命名空间并指定使用相同的网络命名空间。K8s提供了kubectl debug对于临时排查很实用。比如kubectl -n namespace debug -it pod-name --imagebusybox --targetcontainer-name这样得到的调试Pod与目标容器共享网络命名空间直接就能看到目标Pod的resolv.conf还能使用完整工具集。拿到resolv.conf后第一件事就是看nameserver是不是CoreDNS的ClusterIP。默认的ClusterIP一般是10.96.0.10或10.32.0.2具体取决于安装K8s时的--cluster-dns参数。如果你看到的nameserver不是预期地址说明这个Pod的dnsPolicy或dnsConfig被改过要返回去看工作负载的YAML配置。如果nameserver正确再用nslookup分别做两组测试一组解析集群内部域名一组解析故障域名。通过对比可以快速判断问题出在集群域名解析链路还是外部域名转发链路。3.2 第二步检查CoreDNS服务和Endpoints是否正常从Pod里看到的nameserver只是一个ClusterIP真正处理请求的是后端的CoreDNS Pod。如果Service没有关联到任何Pod请求就会被丢弃表现就是Pod里解析超时。所以第二步要检查Service和Endpointskubectl get svc -n kube-system kube-dns kubectl get endpoints -n kube-system kube-dns kubectl get pod -n kube-system -o wide | grep -E coredns|kube-dns注意虽然实际部署的是CoreDNS但Service在历史版本里一直叫kube-dns这个历史包袱导致不少新同学找错名字。只要看到Service存在并且Endpoints列表里有CoreDNS Pod的IP就说明Service层面的代理关系是完整的。接着检查CoreDNS Pod的运行状态。如果Pod处于CrashLoopBackOff或Pending状态问题就清楚了一大半朝着对应方向排查即可。如果Pod运行正常再看Pod的资源使用情况。我用下面命令观察kubectl top pod -n kube-system | grep coredns如果CPU使用率长期接近上限或者内存使用率超过limits一半以上说明CoreDNS本身已经到了高负载状态。此时出现的解析失败很可能是资源瓶颈导致而不是配置错误。有同学在CoreDNS高负载时选择重启Pod重启之后可能短暂恢复但很快又复现同款问题。正确做法是针对负载做扩容或者优化Corefile里的cache和forward并发参数。3.3 第三步绕过ClusterIP直接打到CoreDNS Pod上验证这一步是为了区分“Service转发问题”和“CoreDNS自身问题”。Service转发涉及kube-proxy和conntrack偶尔会因为DNAT表项问题导致解析失败但直接访问Pod IP却正常。验证方式很简单先拿到一个CoreDNS Pod的IP然后进入业务Pod用这个IP再发起一次解析请求。kubectl get pod -n kube-system -o wide | grep coredns kubectl exec -it pod-name -n namespace -- nslookup 故障域名 coredns-pod-ip如果直接指定Pod IP解析成功但使用ClusterIP解析失败说明CoreDNS和上游DNS都没问题问题出在ClusterIP的转发链路或kube-proxy规则上。这种情况可以检查对应节点上的kube-proxy规则、conntrack表项甚至重启该节点上的kube-proxy来重建规则。如果直接指定Pod IP也解析失败那么CoreDNS自身或它的上游转发链路有问题继续走进下一步。在整个排查过程中还有一个被我反复验证过的办法进入CoreDNS Pod用它的工具去解析同样的域名。CoreDNS镜像里通常带有nslookup或dig。你也可以在CoreDNS Pod里直接查看它自己的resolv.conf确认上游DNS地址是什么。这样能区分“业务Pod到CoreDNS链路正常但CoreDNS上游异常”和“CoreDNS本身异常”两个场景。3.4 第四步看CoreDNS日志和开启debug输出日志永远是最直接的证据。CoreDNS的日志默认比较简洁如果Corefile里没配置log插件你甚至看不到每个查询的详细记录。排查阶段可以临时修改ConfigMap加上log和errors插件然后等待配置自动加载或者手动滚动重启CoreDNS Pod让新配置生效。kubectl edit configmap coredns -n kube-system在Corefile的.:53块中加入log errors保存后CoreDNS会根据reload插件自动加载配置但自动加载时可能会有短暂DNS中断低峰期操作风险更小。改完以后重新在业务Pod里发起一次解析请求然后查看CoreDNS日志kubectl logs -n kube-system -l k8s-appkube-dns --tail50日志里会显示查询的域名、类型、响应码。比如SERVFAIL代表上游响应失败NXDOMAIN代表域名不存在NOERROR代表解析成功但可能返回了空答案。通过这些状态码能直接判断问题发生的位置。如果日志里出现大量SERVFAIL大概率是forward的上游DNS连不上或拒绝响应如果日志里根本看不到这条查询说明请求可能没到达CoreDNS那就要回头检查Service网络和节点网络策略了。3.5 第五步根据根因做修复和验证定位到根因后修复手段各有不同。这里整理几个我在实践中用得最多的方案。如果问题是上游DNS不可达比如宿主机/etc/resolv.conf里的DNS对CoreDNS容器网络不可达那么修改Corefile把forward目标改成集群内可达的DNS地址即可。如果集群在云环境可以优先使用VPC内网DNS地址而不是公网DNS因为公网DNS请求可能被云平台安全组或外部防火墙拦截。改完后注意观察CoreDNS日志确认不再有超时或SERVFAIL。如果问题是CoreDNS Pod资源不足可以水平扩容。扩容CoreDNS不是简单kubectl scale就完事还需要确认deployment的replicas、PodDisruptionBudget、PodAntiAffinity和topologySpreadConstraints是否合理。扩容前先看当前每个CoreDNS Pod的负载如果有一个Pod的流量明显比其它Pod高可能是kube-proxy的随机转发不够均匀可以配合loadbalance插件或调整kube-proxy模式来改善。如果是ndots或search域导致的雪崩式无效查询可以从应用侧调整dnsConfig。比如给特定工作负载配置ndots:2并保留必要的search域减少外部域名解析时一次DNS请求被拆分成多次查询的情况。这个改动需要充分测试因为ndots:2会让集群内短域名解析时先直接查询原始域名而不是拼接search域如果业务对集群内部短域名依赖较高要谨慎评估。如果是conntrack表项冲突导致偶发解析失败可以在节点上执行sysctl -w net.netfilter.nf_conntrack_max1048576 sysctl -w net.nf_conntrack_max1048576但这属于临时缓解根治还是要降低DNAT连接数比如增加CoreDNS副本数、或者部署NodeLocal DNS缓存让每个节点上的解析请求尽可能在本地完成减少经过ClusterIP的DNAT连接。无论是哪种修复最终都要回到业务Pod里重新验证一次。不要只看一条成功的解析记录就宣布修复完成建议连续解析10次以上同时用curl或实际业务请求做一次完整验证。因为某些偶发问题只在高并发下才暴露单次解析成功说明不了什么。4. 常见问题速查与避坑经验这一节我把自己在实际工作中积累的故障模式整理成表格再展开讲几个特别值得注意的坑。如果你时间紧张可以直接用这个表对照现象来定位方向。现象可能原因排查方向Pod解析集群内Service域名失败外部域名正常CoreDNS到API Server链路异常 / RBAC权限问题查看CoreDNS日志确认kubernetes插件同步状态Pod解析外部域名失败集群内正常forward上游地址不可达 / 上游DNS被防火墙拦截检查Corefile forward目标从CoreDNS Pod内测试上游连通性解析偶尔失败时好时坏CoreDNS高负载 / conntrack冲突 / UDP丢包观察CoreDNS CPU和内存调整副本数和并发参数必要时部署本地缓存域名解析非常慢超过5秒search域和ndots过大 / cache未命中 / forward上游延迟高检查resolv.conf的search列表测试上游DNS响应耗时CoreDNS Pod频繁重启资源limit过低 / 健康检查失败 / 节点绑核问题kubectl describe pod 查看最后状态调整requests和limits改了Corefile却不生效reload插件未启用 / ConfigMap挂载延迟手动滚动重启CoreDNS Pod并用dig验证Pod里直接ping域名报unknown host镜像工具问题 / 解析器配置异常检查resolv.conf用nslookup替代测试使用hostNetwork的Pod解析异常dnsPolicy不匹配 / 继承了宿主机异常DNS检查dnsPolicy必要时改用ClusterFirstWithHostNet4.1 状态码不会骗人SERVFAIL、NXDOMAIN、REFUSED的区别很多同学在CoreDNS日志里看到状态码时不知道该往哪个方向查。我说一下最常见的三种。SERVFAIL表示上游DNS在处理时出现了错误可能是上游超时、拒绝服务也可能是上游本身依赖的权威DNS无法访问。看到SERVFAIL优先检查forward配置的上游DNS是否可达、是否有响应。有一个很容易踩的坑上游DNS配置成了127.0.0.53或127.0.0.1这类loopback地址CoreDNS容器里访问的是自己的回环接口根本连不到宿主机的DNS服务结果就是所有外部域名都SERVFAIL。解决方法是改成节点内网IP上的DNS监听地址或者使用云厂商VPC内网DNS。NXDOMAIN表示域名本身不存在。看到这个状态码时要判断查询的域名是不是被错误地拼接了集群search域。比如访问www.baidu.com但实际查询可能变成了www.baidu.com.default.svc.cluster.local上游返回NXDOMAIN。这类现象一般不会导致最终失败CMD会继续尝试原始域名查询但会增加一次无效往返。如果业务对延迟极其敏感就会表现为偶尔超时。这时候优化ndots和search域比折腾CoreDNS更有效。REFUSED表示上游DNS拒绝响应。这个状态通常说明上游DNS的策略或者ACL限制只允许特定网段或特定来源查询。我曾经遇到过一个集群CoreDNS部署在节点A上游DNS部署在节点B两个节点网络互通但上游DNS在网关上只放行了业务网段忘了放行集群Pod网段结果就是CoreDNS能ping通上游DNS但解析请求全部被拒绝。排查这类问题要在CoreDNS Pod里手动向上游DNS发起查询观察状态码变化。如果上游DNS支持TCP和UDP要同时测两种协议因为有些防火墙只拦截UDPTCP查询则能成功。4.2 为什么重启CoreDNS有时候有效但过几天又复发有些同学遇到解析问题习惯先滚动重启一轮CoreDNS Pod。重启之后指标恢复但过两天问题又回来了。这里面的原理要搞清楚重启CoreDNS Pod会丢弃它的缓存重建conntrack表项甚至可能让Pod调度到另一台节点上暂时绕开资源紧张或网络不稳定的节点。所以“重启有效”不代表根因消失只是把症状暂时掩盖了。有一次我在某环境里排查发现CoreDNS Pod重启后稳定运行了几个小时随后解析延迟又开始缓慢上升。最终定位到是某个节点上的UDP netfilter参数太小大量DNS查询UDP包被丢弃CoreDNS被迫等待超时后重试。这种行为在低峰期不明显一旦遇到业务流量波动就表现为解析超时。重启Pod把容器移到了别的节点所以短时间内恢复了但由于集群里大量使用ClusterIP访问CoreDNSconntrack表项不断堆积问题再次出现。这种场景下单纯重启永远治标不治本。更稳妥的办法是给CoreDNS设置合理的资源请求和限制增加副本或者引入节点级DNS缓存来降低ClusterIP的DNAT压力。除了缓存和conntrack重启CoreDNS还会重新建立与API Server的watch连接。有些时候CoreDNS内存泄漏或goroutine卡死导致它不再更新Service信息表现为新增的Service域名解析不了但老Service域名正常。这种问题重启确实能解决但应该进一步查清为什么会卡死比如是否因为集群规模太大CoreDNS的kubernetes插件默认频率无法及时同步全部对象。必要时要调大kubernetes插件里的resyncperiod参数或者调整CoreDNS的内存limit。4.3 外部DNS、云厂商内网DNS和集群自建DNS怎么选CoreDNS的forward目标选择看似简单实则涉及集群部署形态。如果集群在云环境里我通常建议把VPC内网DNS作为第一上游因为云厂商的内网DNS在VPC内部延迟低还能解析一些云内部服务域名。如果选择公网DNS作为上游必须确认CoreDNS所在安全组的出方向允许UDP和TCP的53端口访问。很多同学遇到“Pod解析外部域名失败但nslookup指定8.8.8.8却成功”的诡异现象就是CoreDNS所在节点根本没放行到公网DNS的网络策略。如果你在自建机房部署K8s一般会有一到两台内网DNS服务器负责解析公司内部系统和部分公网域名。此时Corefile里的forward目标最好写成多条地址比如forward . 10.10.10.53 10.10.10.54 { max_concurrent 1000 }多写一个备用DNS能增强容错性但要注意CoreDNS的forward插件对多个上游默认是随机选择的不配置health_check时不会主动剔除故障上游。如果你希望故障上游自动降级可以加上health_check 5s参数。这段配置会让CoreDNS定期向上游发送健康检查请求连续失败后会暂时把该上游标记为不可用从而避免每次查询都打到坏节点上。还有一种情况是集群内已经有自建DNS负责统一解析所有内部域名和公网域名。此时CoreDNS会遇到一个关键问题自建DNS可能不认识集群内部的cluster.local。不过没关系只要CoreDNS的kubernetes插件在它处理集群域名时并不会把请求转发给上游。关键要确保Corefile里kubernetes插件的fallthrough配置正确。fallthrough的意思是如果一个域名没有被kubernetes插件匹配到是否继续交给后面的插件处理。如果你把fallthrough删掉所有非集群域名都可能被当作集群域名处理最终返回NXDOMAIN。默认配置里只对in-addr.arpa和ip6.arpa设置了fallthrough这个默认值一般够用改的时候要格外谨慎。4.4 实战心得优先建立DNS拨测别等问题变成故障才去查经历了太多次从凌晨三点被电话叫醒去查CoreDNS后我把“提前拨测”这个习惯刻在了团队流程里。DNS解析故障是可以提前暴露的并不需要等到业务大面积报障才被动响应。我通常会在固定节点部署一个小工具定期发起三类DNS查询集群内域名解析、外部域名解析、上游DNS直连解析。只要任一类查询连续失败超过阈值就自动告警并把失败状态码输出出来。这样故障刚有苗头我们就能在业务感知之前介入。拨测工具的选择不强求。你可以用一个简单的CronJob跑nslookup也可以自己写一个小脚本用dig定时探测。关键是拨测的目标要贴近真实业务不要只测一个固定域名最好把业务方最常见的几个外部域名和内部服务域名都纳入进来。因为CoreDNS对不同域名的解析路径不同只测一个域名很容易漏掉另一个域名上游DNS的单独故障。拨测结果记录成结构化数据方便后续对比变更前后是否有劣化。最后再分享一个小技巧在修改Corefile后不要只是直接保存等它reload我习惯先复制一份原配置备份然后手动触发kubectl rollout restart deployment/coredns -n kube-system再立即用拨测工具验证。手动重启虽然会带来秒级抖动但能保证新配置一定生效线上经验里ConfigMap挂载偶尔有延迟依赖自动reload可能让人误判“改了半天怎么没反应”。排障的核心就是严谨、可重复、可验证每一步都留下证据你才不会在半夜三更被一个问题反复折磨。