从NetworkManager到systemd-resolved:一文搞懂Ubuntu 20.04网络服务如何“打架”并吃掉你的DNS设置
Ubuntu 20.04网络服务DNS配置冲突全解析与实战解决方案
当你发现每次重启Ubuntu服务器后,精心配置的DNS设置总是神秘消失,这背后其实是systemd-resolved和NetworkManager两大服务在暗中较劲。本文将带你深入理解现代Linux发行版中复杂的网络服务交互机制,并提供一套可落地的解决方案。
1. 现代Linux网络服务架构解析
Ubuntu 20.04作为采用systemd的现代发行版,其网络管理架构与传统Linux有显著不同。系统中可能同时运行着多个网络管理服务:
- NetworkManager:图形界面友好的网络配置工具
- systemd-networkd:轻量级的网络配置守护进程
- systemd-resolved:DNS和域名解析管理服务
这些服务各自为政时相安无事,但当它们同时尝试管理DNS配置时,就会产生令人头疼的冲突。典型的症状包括:
- 手动修改
/etc/resolv.conf后重启失效 - VPN连接后DNS被意外覆盖
- 多网卡环境下DNS配置混乱
# 查看当前活跃的网络管理服务 systemctl status NetworkManager systemd-resolved systemd-networkd2. DNS配置的底层机制
理解DNS配置如何被覆盖,需要先了解现代Linux的域名解析流程:
传统解析流程:
- 应用查询 -> glibc解析器 -> 读取
/etc/resolv.conf-> 向指定DNS服务器查询
- 应用查询 -> glibc解析器 -> 读取
systemd-resolved介入后的流程:
- 应用查询 -> glibc解析器 -> 访问
/etc/resolv.conf(指向127.0.0.53) -> systemd-resolved接收请求 -> 根据自身配置转发到上游DNS
- 应用查询 -> glibc解析器 -> 访问
关键文件关系图:
| 文件路径 | 作用 | 管理方 |
|---|---|---|
| /etc/resolv.conf | 符号链接,默认指向stub-resolv.conf | systemd-resolved |
| /run/systemd/resolve/stub-resolv.conf | 存根解析器配置 | systemd-resolved |
| /run/systemd/resolve/resolv.conf | 实际使用的DNS服务器列表 | systemd-resolved |
| /etc/systemd/resolved.conf | systemd-resolved的主配置文件 | 管理员 |
3. 诊断DNS配置问题的专业工具包
当出现DNS问题时,系统管理员需要一套系统的诊断方法:
3.1 使用resolvectl检查当前状态
# 查看完整的DNS解析状态 resolvectl status # 查询特定域名的解析过程 resolvectl query example.com # 清空DNS缓存 resolvectl flush-caches # 查看统计信息 resolvectl statistics3.2 网络管理器交互检查
# NetworkManager管理的连接信息 nmcli connection show --active # 查看NetworkManager的DNS配置 nmcli dev show | grep DNS3.3 文件系统检查点
# 检查resolv.conf的真实指向 ls -l /etc/resolv.conf # 比较三个关键DNS配置文件 diff -u /run/systemd/resolve/stub-resolv.conf /run/systemd/resolve/resolv.conf4. 永久性DNS配置方案
根据不同的使用场景,我们提供三种可靠的配置方案:
方案一:纯systemd-resolved配置(推荐)
- 编辑主配置文件:
sudo nano /etc/systemd/resolved.conf- 取消注释并修改以下行:
[Resolve] DNS=8.8.8.8 1.1.1.1 Domains=example.com FallbackDNS=9.9.9.9- 重启服务:
sudo systemctl restart systemd-resolved方案二:NetworkManager优先配置
对于使用NetworkManager为主的管理环境:
- 修改NetworkManager配置:
sudo nano /etc/NetworkManager/conf.d/dns.conf- 添加内容:
[main] dns=systemd-resolved- 为特定连接设置DNS:
nmcli connection modify "有线连接1" ipv4.dns "8.8.8.8 8.8.4.4" nmcli connection up "有线连接1"方案三:传统resolv.conf模式(兼容性方案)
如果需要完全禁用systemd-resolved:
- 取消resolv.conf的符号链接:
sudo rm /etc/resolv.conf sudo nano /etc/resolv.conf- 添加传统DNS配置:
nameserver 8.8.8.8 nameserver 1.1.1.1- 锁定文件防止被修改:
sudo chattr +i /etc/resolv.conf5. 高级场景处理技巧
5.1 多网卡环境DNS配置
当系统有多个网络接口时,可以为不同接口指定不同DNS:
# 使用NetworkManager按连接配置 nmcli connection modify eth0 ipv4.dns-priority 100 nmcli connection modify eth1 ipv4.dns-priority 505.2 VPN连接时的DNS处理
VPN客户端通常会尝试修改DNS设置,可以通过以下方式保持稳定性:
# 在NetworkManager中禁用VPN的DNS修改 nmcli connection modify vpn-name ipv4.never-default yes nmcli connection modify vpn-name ipv4.ignore-auto-dns yes5.3 企业内网DNS的特殊处理
对于需要同时解析内外网域名的环境:
# /etc/systemd/resolved.conf [Resolve] DNS=10.0.0.1 8.8.8.8 Domains=~internal.company ~.company6. 服务交互的深度解析
理解各服务如何交互是解决冲突的关键:
优先级机制:
- NetworkManager配置 > systemd-resolved配置 > 传统resolv.conf
- 最后修改的服务通常会覆盖之前的配置
配置传播路径:
graph LR A[NetworkManager] -->|推送配置| B(systemd-resolved) B -->|生成| C[/run/systemd/resolve/resolv.conf] C -->|符号链接| D[/etc/resolv.conf]调试技巧:
# 实时监控DNS配置变化 sudo inotifywait -m /etc/resolv.conf /run/systemd/resolve/ # 查看systemd-resolved日志 journalctl -u systemd-resolved -f
在实际运维中,我遇到过最棘手的情况是在Kubernetes节点上,Calico网络插件、NetworkManager和systemd-resolved三方争夺DNS控制权。最终通过锁定NetworkManager作为唯一配置源,并禁用其他服务的DNS管理功能解决了问题。
