核心概念

systemd-resolved 是 systemd 提供的 DNS 解析服务,在 Ubuntu 22.04+ 中默认启用。它在 127.0.0.53:53 上监听作为 stub(桩)解析器,所有本地程序的 DNS 请求都先经过它,再转发到真正的上游 DNS 服务器。

工作原理

你的程序(nslookup/dig/curl 等)
    ↓ 查询 "google.com"
127.0.0.53:53  ← systemd-resolved 的 stub 监听地址
    ↓ 查询转发
systemd-resolved 根据自身配置(/etc/systemd/resolved.conf、netplan、DHCP 等)
    ↓ 转发查询
真正的上游 DNS 服务器(如 8.8.8.8、114.114.114.114 或内网 DNS)

为什么设计 stub 解析器

目的说明
DNS 缓存缓存 DNS 查询结果,减少重复查询,加速域名解析
多链路 DNS 管理VPN、有线、无线使用不同 DNS 时,systemd-resolved 自动路由到正确的上游
一致性接口无论上游 DNS 如何变化,程序始终只需访问 127.0.0.53

/etc/resolv.conf 的变化

systemd-resolved 启用时

$ cat /etc/resolv.conf
nameserver 127.0.0.53
options edns0 trust-ad
字段含义
nameserver 127.0.0.53DNS 请求指向本机的 systemd-resolved stub
options edns0启用 EDNS0 扩展(支持更大的 DNS 报文)
options trust-ad信任 DNS 响应中的 AD(Authentic Data)标志位

查看真正的上游 DNS

# 方法1:查看 systemd-resolved 实际使用的 DNS
resolvectl status
# 输出中会显示每个网卡实际使用的 DNS 服务器
 
# 方法2:查看 systemd-resolved 的全局配置
cat /etc/systemd/resolved.conf
 
# 方法3:查看 netplan 配置(如果是 netplan 管理网络)
cat /etc/netplan/*.yaml
 
# 方法4:直接查看 resolved 维护的完整 resolv.conf(推荐)
cat /run/systemd/resolve/resolv.conf
# 这个文件包含的是真实的(real)上游 DNS 地址,不是 127.0.0.53

对容器/K8s 的影响

问题场景

Docker 容器或 K8s CoreDNS 中,如果程序读取了宿主机的 /etc/resolv.conf 指向 127.0.0.53,会因为容器无法访问宿主机 loopback 地址而导致 DNS 解析失败:

CoreDNS 容器内                    宿主机
┌──────────────┐               ┌──────────────────┐
│ forward .     │──→ 127.0.0.53  │  systemd-resolved  │
│ /etc/resolv.conf│  ✗ 连接失败   │  监听 127.0.0.53:53 │
└──────────────┘               └──────────────────┘
    ↑                            ↑
  容器内的 127.0.0.53          宿主机的 127.0.0.53
  (没有监听)                 (有监听但容器访问不到)

典型故障链

CoreDNS 配置 forward . /etc/resolv.conf
    │
    ├── 读取到 nameserver 127.0.0.53
    │
    ├── CoreDNS 尝试连接容器内 127.0.0.53:53 → 失败
    │
    └── 所有集群内 DNS 解析超时 → 服务发现异常

修复方法

在 CoreDNS ConfigMap 中直接指定真实上游 DNS,而非使用 /etc/resolv.conf

# CoreDNS ConfigMap 中的 forward 配置
forward . 8.8.8.8 114.114.114.114 {
    policy sequential
}

优先使用内网 DNS 地址(如公司内部 DNS),其次用公网 DNS 作为 fallback。

如何判断当前系统是否使用 systemd-resolved

# 方法1:查看 /etc/resolv.conf 内容
cat /etc/resolv.conf
# 如果 nameserver 是 127.0.0.53 → systemd-resolved 正在使用
 
# 方法2:查看 resolved 服务状态
systemctl status systemd-resolved
 
# 方法3:查看 /etc/resolv.conf 是哪个文件管理的
ls -la /etc/resolv.conf
# 如果是符号链接指向 ../run/systemd/resolve/stub-resolv.conf → systemd-resolved
 
# 方法4:查看 resolvectl 状态
resolvectl status

参考链接