Appearance
第 3 讲|域名和 DNS
IP 地址(尤其是 IPv4 的 203.0.113.10、IPv6 的 2001:db8::8a2e:370:7334)不便于人类记忆。域名是为了让用户可以用易记的名称(如 www.example.com)访问服务而设计的中间层。但机器之间通信仍然使用 IP——浏览器拿到域名后,需要查询该名称对应的 IP,这一过程称为 DNS(Domain Name System)解析。
DNS 不只用于公网网站。公司内部平台、云 VPC 内的服务、Kubernetes 里的 Service,背后都是同一套域名解析机制。本讲先讲清楚域名的结构、DNS 的查询过程、记录类型、TTL 的作用,然后展开内网 DNS 的应用场景和常见解析异常的判定。
一、域名的层级结构
域名按层级组织,从右往左层级越来越细。以 www.example.com 为例:

| 段 | 层级 | 管理者 |
|---|---|---|
com | 顶级域(TLD) | ICANN 等国际机构 |
example.com | 主域名(Second-level Domain) | 域名注册者(公司/个人) |
www | 子域名(Sub-domain) | 主域名所有者自行控制 |
顶级域分两类:
- 通用顶级域(gTLD):
.com、.org、.net、.io、.app - 国家代码顶级域(ccTLD):
.cn、.jp、.uk、.de
主域名所有者可以在自己的主域名下创建任意子域名,按业务用途拆分。常见的拆分方式:
| 子域名 | 用途 |
|---|---|
www | 官网 |
api | 后端 API |
static / cdn | 静态资源/CDN |
m | 移动版网站 |
admin | 管理后台(应限制内网或 VPN 访问) |
mail | 邮件服务 |
grafana / prometheus | 监控平台 |
harbor / nexus | 镜像/制品仓库 |
看到一个陌生的域名时,从子域名前缀通常能大致判断指向的服务类型,这对快速理解故障范围有帮助。
二、递归 DNS 与权威 DNS
DNS 系统有两类核心角色:
权威 DNS
最终保存域名解析记录、对外回答"该域名对应什么"的服务器。每个主域名都有自己的权威 DNS。在云厂商控制台或域名注册商管理后台配置的解析记录,就是写入权威 DNS。
- 阿里云解析、腾讯云 DNS、AWS Route53、Cloudflare 都属于权威 DNS 服务商
- 改解析记录,本质是改权威 DNS 上的配置
递归 DNS
替客户端完成完整查询过程的中间服务器。客户端不会自己从根 DNS 开始一路查到底——递归 DNS 帮你完成这件事并返回最终结果。
- 系统配置中
/etc/resolv.conf里的nameserver,通常就是递归 DNS 8.8.8.8(Google)、1.1.1.1(Cloudflare)、114.114.114.114(国内通用)、运营商 DNS、公司内网 DNS,都属于递归 DNS
完整查询过程

权威 DNS 与递归 DNS 的分工对运维的影响
- 修改解析记录 — 在权威 DNS(控制台)操作,通常立即生效
- 生效全网范围 — 不取决于权威 DNS,而取决于各级递归 DNS 的缓存何时过期——这正是 TTL 的作用,下一节展开
三、DNS 记录类型
DNS 不只能返回 IP,还有多种记录类型对应不同的解析需求:
| 类型 | 含义 | 典型用途 |
|---|---|---|
A | IPv4 地址 | 大多数业务域名 |
AAAA | IPv6 地址 | IPv6 网络 |
CNAME | 别名,指向另一个域名 | 接入 CDN、域名跳转 |
MX | 邮件服务器域名 | 邮件投递 |
TXT | 任意文本 | 域名所有权验证、SPF/DKIM 反垃圾邮件、ACME 证书申请 |
NS | 该域名的权威 DNS 服务器 | 子域委派 |
SOA | 域起始授权 | 域的元数据,自动生成 |
SRV | 服务记录 | 指定服务的主机名+端口,LDAP/SIP 等场景 |
业务方日常接触最多的是 A、AAAA、CNAME 三种。
CDN 接入场景下的 CNAME 链
接入 CDN 的业务域名几乎都使用 CNAME 而非 A 记录。原因:
- CDN 厂商的边缘节点 IP 动态分配,根据用户位置就近返回
- 业务方无法预测 IP、不可能写死
典型解析链:
查询: www.example.com
权威 DNS: CNAME → example.com.cdn-provider.net
查询: example.com.cdn-provider.net
CDN 权威 DNS: A → 北京用户得到 203.0.113.42,上海用户得到 198.51.100.13dig 工具可以完整看到这条链路:
bash
$ dig www.example.com
;; ANSWER SECTION:
www.example.com. 300 IN CNAME example.com.cdn-provider.net.
example.com.cdn-provider.net. 60 IN A 203.0.113.42CNAME 的限制
主域名(zone apex)不能配 CNAME——example.com 本身只能配 A,不能 CNAME 到其他域名。这是 RFC 规定,部分场景下需要主域名也走 CDN,但又不允许 CNAME,云厂商提供了 ALIAS 或 ANAME 记录作为变通方案(在 DNS 层做隐式 CNAME 解析)。
四、TTL 与缓存
DNS 查询结果会在多个层级被缓存:浏览器、操作系统、路由器、运营商 DNS、上游 DNS。TTL(Time To Live)就是告诉这些缓存"这条记录可以保留多久"——单位是秒。

例如 TTL = 300,意味着查询到这条记录后,300 秒内的重复查询使用缓存,300 秒后必须重新查询。
TTL 长短的取舍
| TTL 范围 | 优点 | 缺点 |
|---|---|---|
| 长(3600s ~ 86400s) | 查询少,权威 DNS 负载低 | 切换 IP 时缓存等待时间长 |
| 短(60s ~ 300s) | 切换快,几分钟全网生效 | 查询量大,权威 DNS 压力大 |
业务正常运行期间,TTL 可以配置稍长(3600s 即 1 小时)以减少查询压力。
IP 切换前的标准操作:提前调低 TTL
域名迁移或主备切换前的标准操作:
- 提前 1-2 天把 TTL 调低(例如从 3600 改为 60-300 秒)
- 等待原 TTL 完全过期(各级缓存都已使用新 TTL)
- 执行 A 记录的 IP 切换
- 观察 1-2 天确认稳定后,把 TTL 恢复正常值
这个流程的关键价值:新 IP 出问题时,回滚的等待时间从数小时缩短到几分钟。
缓存清理
修改解析记录后,某些位置仍解析到旧 IP,通常是缓存未过期。手动清理本地缓存:
bash
# Linux (systemd-resolved)
systemd-resolve --flush-caches
resolvectl flush-caches
# Linux (nscd)
service nscd restart
# macOS
sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder
# Windows
ipconfig /flushdns
# 浏览器:大多数浏览器需要重启或访问 chrome://net-internals/#dns上游递归 DNS 的缓存无法用客户端命令清理,只能等待 TTL 自然过期——这正是 TTL 决定全网生效时间的体现。
五、内网 DNS
DNS 在内网场景中的应用范围远超公网。公司内部、云 VPC、Kubernetes 集群内都广泛使用 DNS。

内网 DNS 的典型场景
| 场景 | 域名示例 |
|---|---|
| 公司内部 GitLab | gitlab.company.local |
| 云 VPC 内的 MySQL | mysql.internal.example.com |
| K8s Service | api.default.svc.cluster.local |
| K8s Pod | pod-name.namespace.pod.cluster.local |
内网 DNS 的核心价值:解耦 IP 与服务
服务的 IP 在生产环境中频繁变化:
- 数据库主备切换 → IP 切换
- Kubernetes Pod 重建 → IP 变化
- 应用扩缩容 → 新增/减少 IP
通过 DNS 解耦后,业务代码使用稳定的域名访问,IP 变化对应用透明。Kubernetes 是这种解耦最彻底的实现——一个 Service 名背后的 Pod IP 可能一天变几次,应用始终用同一个域名,完全无感知。
Kubernetes 内的 DNS 解析机制
K8s 集群内的 DNS 由 CoreDNS 提供,服务名按固定格式构成:
<service-name>.<namespace>.svc.cluster.local例如 default namespace 下的 api Service,完整域名是 api.default.svc.cluster.local。同 namespace 内的 Pod 可以省略部分,直接用 api(由 search domain 自动补全)。
内网 DNS 故障的判定
应用日志中出现:
lookup api.default.svc.cluster.local: no such host判定路径:
bash
# 1. Service 是否存在
kubectl get svc -n default api
# 2. Service 的 Endpoints 是否有 Pod
kubectl get endpoints -n default api
# 3. CoreDNS 是否正常
kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=50
# 4. 从有问题的 Pod 内部直接 DNS 查询
kubectl exec -it <pod> -- nslookup api.default.svc.cluster.local具体的网络 DNS 故障类型与处理方式,在 第 14 讲 网络诊断与排错 的 DNS 章节展开。
六、DNS 解析异常的判定信号
DNS 出问题时通常表现为以下几种结果:
| 结果 | 含义 | 大概率原因 |
|---|---|---|
NXDOMAIN | 域名不存在 | 域名拼写错误、记录未配置、域名已过期 |
SERVFAIL | DNS 服务器内部错误 | 上游权威 DNS 故障、网络断、DNSSEC 校验失败 |
REFUSED | DNS 服务器拒绝回答 | 防火墙拦截、DNS 服务器配置限制查询来源 |
| 解析到旧 IP | 缓存未过期 | TTL 还有效或本机 hosts 写死 |
| 不同地区解析到不同 IP | 智能调度 | CDN、GeoDNS、运营商缓存差异 |
NXDOMAIN 不一定是故障
某些应用启动时会探测多个候选域名(例如 DNS search 自动补全后的多个 FQDN),部分候选返回 NXDOMAIN 是正常的。日志中出现少量 NXDOMAIN 不必紧张,真正需要警觉的是:
- 业务核心域名出现 NXDOMAIN
- 多个域名同时 SERVFAIL
- 解析耗时从毫秒级突然升到秒级
后两种情况通常意味着 DNS 链路本身出了问题,排查方向是上游 DNS 服务器、网络连通性、CoreDNS 健康状态。
DNS 解析慢的判定
应用偶尔出现"启动后第一次请求慢几秒,后续正常",大概率是 DNS 解析慢:
bash
time dig @<本机配置的 DNS> example.com正常本地 DNS 响应应当在 100ms 以内。如果接近 1 秒甚至几秒,说明本地或上游 DNS 性能有问题。处理方式:
- 在本机部署 dnsmasq / systemd-resolved / unbound 做本地缓存,避免每次都查上游
- 应用层启用 DNS 缓存(JVM 的
networkaddress.cache.ttl、Python 的 socket 缓存) - 检查
/etc/resolv.conf中的options参数:timeout默认 5 秒过长,可调到 1-2 秒;attempts默认 2 次过多,可调到 1
bash
# /etc/resolv.conf
options timeout:2 attempts:1 rotaterotate 让多个 nameserver 轮询使用,避免第一个 DNS 慢时所有查询都先等它超时。
七、查 DNS 的常用工具
| 工具 | 用途 |
|---|---|
dig | 直接查权威 DNS,显示完整结果(推荐) |
nslookup | 简化的查询工具,输出较简略 |
host | 进一步简化的工具 |
getent hosts | 走系统 NSS,模拟应用的真实解析路径 |
bash
# 标准查询
dig www.example.com
# 指定 DNS 服务器查询
dig @8.8.8.8 www.example.com
dig @1.1.1.1 www.example.com
# 查特定记录类型
dig www.example.com A
dig example.com MX
dig example.com NS
dig example.com TXT
# 从根域名开始递归追踪
dig +trace example.com
# 反向解析(IP → 域名)
dig -x 8.8.8.8
# 只输出最终 IP(脚本化)
dig +short www.example.com
# 走系统 NSS(包括 /etc/hosts),模拟应用看到的解析
getent hosts www.example.comdig 与 getent hosts 必须对比看
应用看到的解析结果走的是系统 NSS(nsswitch.conf 中通常是 files dns,先查 /etc/hosts 再查 DNS),dig 直接绕过 hosts 查 DNS。两者结果不一致时,几乎都是 /etc/hosts 写死了旧记录:
bash
# 修改的是 DNS,但应用一直访问旧 IP——常见根因是 /etc/hosts
grep example.com /etc/hosts
cat /etc/nsswitch.conf | grep ^hosts判定流程:dig 出来对、getent hosts 出来不对 → 几乎一定是 hosts 或 NSS 顺序问题。这是 DNS 排查中最常见的认知陷阱。