CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
DNS 与域名解析/课时/K8s CoreDNS
RawBlame
课时目录12 节

DNS 与域名解析

  1. 01DNS 是什么
  2. 02记录类型
  3. 03解析过程
  4. 04域名层次
  5. 05诊断工具
  6. 06本站域名配置
  7. 07DNS 与 HTTPS
  8. 08邮件相关记录
  9. 09K8s CoreDNS
  10. 10常见故障
  11. 11DNS 与 CDN
  12. 12综合练习

K8s CoreDNS

集群内服务发现 svc.cluster.local。

25 分钟

K8s CoreDNS

这一课你将能做到

  1. 写出集群内服务域名的完整形态与四种简写规则,并用 Pod 内 nslookup 验证
  2. 读懂 CoreDNS 的 Corefile(CoreDNS ConfigMap),解释每个插件(kubernetes、forward、cache、logs)的作用
  3. 排查集群内典型解析问题:ndots 拖慢、外部域名超时、CoreDNS 负载不均、5 秒延迟

为什么要学

把应用搬上 Kubernetes 后,DNS 的角色比在虚拟机时代更重:Pod IP 随时漂移,服务之间不靠 IP 互相找,而靠 Service 名字——http://backend:8080 这样的调用能成立,全靠集群里的 CoreDNS。它为每个 Service 自动生成 名字.命名空间.svc.cluster.local 的记录,还负责把集群外域名转发给上游递归器。

初学者在 K8s 遇到的「服务偶发超时」「外部接口时快时慢」,相当部分是 CoreDNS 配置(ndots、缓存)问题。本课讲透集群解析机制与调优。

先建立图像

Pod (dnsPolicy: ClusterFirst)
  │ /etc/resolv.conf 指向 CoreDNS Service:10.96.0.10
  ▼
CoreDNS(Deployment + Service kube-system/coredns)
  │ Corefile 决定怎么回答
  ├─ 集群内名字(*.cluster.local)
  │    └─ kubernetes 插件直接读 API Server 的 Service/Pod 数据回答
  └─ 集群外名字(www.coderoadmap.cn 等)
       └─ forward 插件转发给节点上游 DNS(如 223.5.5.5 / 云内网DNS),cache 插件缓存

服务域名规则(以 default 命名空间的 backend 服务为例):

完整形态:backend.default.svc.cluster.local
同命名空间:backend              ← 最常用
跨命名空间:backend.default
Pod 也有名字:10-244-1-5.default.pod.cluster.local(默认不开,需配置)
名词人话解释
CoreDNSK8s 默认集群 DNS(1.11 起,替代 kube-dns),Go 编写、插件化
ClusterIPService 的虚拟 IP,DNS 返回的就是它(如 backend → 10.96.x.x)
Headless Service无 ClusterIP,DNS 直接返回各 Pod IP(StatefulSet 场景)
ndots名字里点的数量低于此值就先按 search 后缀逐个补全尝试
dnsPolicyPod 的 DNS 策略:ClusterFirst / Default / None

跟着做

步骤 1:查看集群 DNS 与 Pod 的 resolv.conf

kubectl get svc -n kube-system kube-dns
kubectl run dns-test --image=busybox:1.36 -it --rm -- sh

Pod 内执行:

cat /etc/resolv.conf

示例输出:

nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

三行含义:查询全部发给 CoreDNS;先按本命名空间、svc、cluster.local 的顺序补后缀;ndots:5 是后面要讲的「慢」的根源。

步骤 2:解析 Service 的四种写法

# 在 default 命名空间的测试 Pod 里
nslookup backend
nslookup backend.default
nslookup backend.default.svc
nslookup backend.default.svc.cluster.local

示例输出:

Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name:      backend.default.svc.cluster.local
Address 1: 10.96.7.21 backend.default.svc.cluster.local

跨命名空间调用必须写全到命名空间级,如 nslookup kubernetes.default。

步骤 3:看 CoreDNS 实际配置

kubectl -n kube-system get cm coredns -o yaml

默认 Corefile 示例:

.:53 {
    errors
    health {
       lameduck 5s
    }
    ready
    kubernetes cluster.local in-addr.arpa ip6.arpa {
       pods insecure
       fallthrough in-addr.arpa ip6.arpa
    }
    prometheus :9153
    forward . /etc/resolv.conf {
       max_concurrent 1000
    }
    cache 30
    loop
    reload
    loadbalance
}

插件逐个解释:

插件作用
kubernetes监听 API Server,Service/Pod 数据直接成答(非区域文件)
forward非集群域名转发给上游(节点 /etc/resolv.conf 或指定公共 DNS)
cache缓存 30 秒(集群内记录 TTL 通常很短,外部记录按其 TTL)
loadbalance对多条 A 轮询排序
pods insecure允许 Pod IP 反查
ready/health就绪与存活探针

步骤 4:观察 Headless Service 的差异

kubectl create service clusterip mysvc --clusterip=None
kubectl get svc mysvc

对普通 Service,DNS 返回单个 ClusterIP;对 Headless Service,CoreDNS 直接返回所有就绪 Pod IP:

# 普通 Service
mysvc.default.svc.cluster.local → 10.96.7.21

# Headless(StatefulSet:还带每副本稳定名字 web-0.mysvc、web-1.mysvc)
web-0.mysvc.default.svc.cluster.local → 10.244.1.5
web-1.mysvc.default.svc.cluster.local → 10.244.2.8

步骤 5:理解 ndots:5 与搜索后缀,量化额外查询

# 在 Pod 中解析一个只有一个点的外部名(如 api.partner.com)
nslookup api.partner.com

由于 api.partner.com 只有 1 个点 < ndots:5,解析器不会直接查它,而是依次尝试:

api.partner.com.default.svc.cluster.local   → NXDOMAIN
api.partner.com.svc.cluster.local           → NXDOMAIN
api.partner.com.cluster.local               → NXDOMAIN
api.partner.com                             → 成功

3 次无效查询,丢包时还要等超时——这是外部调用偶发慢的常见原因。两种解法:

# 解法 1:应用直接写 FQDN 末尾加点,强制按绝对名查(最省事)
url: https://api.partner.com./v1

# 解法 2:给工作负载单独调低 ndots
apiVersion: v1
kind: Pod
spec:
  dnsConfig:
    options:
      - name: ndots
        value: "2"
  containers: [ ... ]

步骤 6:CoreDNS 扩容与排障三板斧

# 1) 看 CoreDNS 是否有压力/错误日志(先开日志插件)
kubectl -n kube-system logs -l k8s-app=kube-dns --tail=50

# 2) 大规模集群默认副本不足,调大(或配合 autoscaler)
kubectl -n kube-system scale deploy coredns --replicas=3

# 3) Pod 内直接对比「CoreDNS」与「公共DNS」,区分转发问题
nslookup www.coderoadmap.cn 10.96.0.10
# 在能直连公网 DNS 的节点上
nslookup www.coderoadmap.cn 223.5.5.5

补充:节点 /etc/resolv.conf 指向的 DNS 不稳时 CoreDNS 也会抖;生产建议 forward 直接写云厂商内网 DNS 或多个公共 DNS 做 failover。

讲清楚要点

  1. 集群内 DNS 答案来自 API Server 实时数据,不是预生成文件:Service 创建后几乎立即可解析,不存在 TTL 传播问题。
  2. Pod 拿到的是 CoreDNS ClusterIP:靠 iptables/IPVS 规则负载均衡到 CoreDNS 副本;Pod 多、查询密集时要保证副本数与节点分布(Pod 反亲和打散)。
  3. ndots:5 + search 列表是 K8s 解析慢的头号配置:理解「短名先补后缀、绝对名直接查」,能解释大量偶发超时。
  4. 外部解析问题要分层:Pod→CoreDNS(UDP 是否被 NetworkPolicy 拦)、CoreDNS→上游(forward 目标是否可达、conntrack 丢包)、上游本身。
  5. conntrack/UDP race 会造成约 5 秒延迟:高并发下 SNAT 端口竞争丢 UDP 包,解析器重传正好 5 秒;修复靠调优 conntrack、部署 NodeLocal DNSCache 与扩 CoreDNS。
  6. NodeLocal DNSCache 是大集群标配:节点本地 DaemonSet 缓存,减少到 CoreDNS 的 UDP 跳转,显著降低 5 秒延迟。
  7. dnsPolicy 要会选:默认 ClusterFirst;宿主机网络 Pod 常用 Default;需要完全自定义时用 None + dnsConfig。

你可能会懵的地方

  • Service 刚删掉,为什么 DNS 有时还返回旧 ClusterIP? CoreDNS 的 cache 插件默认缓存 30 秒(成功与否定都缓存)。等缓存过期;在缩发布、频繁重建同名服务时尤为明显。

  • 为什么 Pod 里 ping 不通 cluster.local? cluster.local 是域后缀不是主机;要 ping 具体名字,如 ping backend.default.svc.cluster.local。而且 CoreDNS 本身只应答查询,不响应 ICMP。

  • nslookup 正常、Java 应用却解析失败? JVM 默认缓存 DNS 结果(旧版默认永久缓存,可用 networkaddress.cache.ttl);且 Java 不走 glibc search 的某些行为、老版本对 ndots 处理不同。容器里设 -Dnetworkaddress.cache.ttl=30 并确认 dnsPolicy。

  • CoreDNS Pod 挂了集群内调用全断? DNS 是集群基础设施,必须冗余并配 PodDisruptionBudget;Service 后没有就绪端点时解析立即全失败。

  • forward . /etc/resolv.conf 里的点代表什么? CoreDNS 语法中 forward 的第一个参数是匹配的域,. 匹配所有(即默认转发所有非集群域);后面是上游地址,写文件表示从该文件读上游。

错法对照

错法后果正确做法
应用写死 Service ClusterIP重建集群/Service 后全线崩用服务名,让 DNS 解析
跨命名空间只写服务名补后缀只在本命名空间找,NXDOMAIN写 服务.命名空间 或 FQDN
忽略 ndots,短外部名多每域名 3~4 次无效查询,偶发超时FQDN 加点或调低 ndots
CoreDNS 副本长期默认 2 不扩查询排队、UDP 丢包、5 秒延迟按规模扩副本 + NodeLocal DNSCache
NetworkPolicy 只放 80/443Pod 到 CoreDNS 的 UDP 53 被拦放行到 kube-dns:53 TCP/UDP

卡点急救

  1. 集群内服务全部偶发解析超时:先看 CoreDNS Pod 是否全部就绪、是否被调度在同一节点;再看日志有无大量 SERVFAIL;立即扩容并检查节点 conntrack 表是否满(dmesg | grep conntrack)。
  2. 只有外部域名解析慢/失败:在 CoreDNS Pod 内直接 nslookup 外部名 上游IP 判断上游健康;检查 forward 配置与节点 DNS;必要时把 forward 改为显式多个公共/内网 DNS。
  3. 固定出现约 5 秒卡顿后成功:典型 UDP 丢包重传。部署 NodeLocal DNSCache、调大 conntrack 表、确认 CoreDNS 副本与节点反亲和,而不是去改业务代码。

面试常问

  • Kubernetes 集群里 Service 的域名是怎么解析的? Pod 的 resolv.conf 指向 CoreDNS Service(默认 10.96.0.10),并配置 search 后缀与 ndots。查 服务.命名空间.svc.cluster.local 时,CoreDNS 的 kubernetes 插件直接从 API Server 的 Service 对象取 ClusterIP 返回;Headless Service 则返回各 Pod IP。非集群域由 forward 插件转发上游,cache 插件做缓存。

  • ndots 是什么?为什么会导致解析变慢? resolv.conf 里的 ndots 设定阈值:域名中点的数量达到阈值才当作绝对域名直接查询,否则先依次拼上 search 列表(命名空间.svc、svc、cluster.local)尝试,全失败后才查原始名。默认 ndots:5 让大多数只有一两个点的外部域名多出 3 次 NXDOMAIN 查询,链路差或丢包时延迟明显。用 FQDN 末尾加点、调低 ndots 或上 NodeLocal DNSCache 解决。

  • 什么是 K8s 中著名的「5 秒 DNS 延迟」? 高并发场景下 Pod 经 SNAT 访问 CoreDNS 的 UDP 包因 conntrack 竞态被丢弃,glibc/musl 解析器重传间隔恰为 5 秒,表现为请求稳定卡 5 秒后成功。社区标准对策是 NodeLocal DNSCache(节点本地缓存避免跨网络 UDP/SNAT)、调 conntrack、扩 CoreDNS;TCP 模式也可规避但非默认。

自测三问

  1. 写出 default 命名空间中 redis 服务的四种域名形态;跨命名空间最少要写全到哪一级?
  2. CoreDNS 收到 www.coderoadmap.cn 和 backend.default.svc.cluster.local 分别走哪条插件路径?
  3. 应用日志中大量「调用合作方接口固定慢 5 秒」,你按哪三步定位到 DNS 层?

小结一句话

CoreDNS 用 kubernetes 插件把 Service 对象实时变成集群内域名答案,用 forward+cache 接外部世界;ndots、conntrack 和副本数是集群解析性能的三个命门。

延伸

  • Kubernetes 官方:Pod 与 Service 的 DNS
  • Kubernetes 官方:使用 NodeLocal DNSCache
  • CoreDNS 官方文档与插件手册
  • CoreDNS kubernetes 插件说明
  • 下一课预告:常见故障——NXDOMAIN、传播延迟、解析超时、5 秒延迟的系统排障法。
加载本节练习…
← 上一课邮件相关记录下一课 →常见故障