在Ubuntu系统运维中,DNS解析故障是最常见的网络问题之一,而通过resolv.conf配置DNS故障转移(DNS Failover)是解决这一问题最直接、最有效的手段。核心思路就是在resolv.conf中配置多个DNS服务器地址,当主DNS服务器不可用时,系统自动切换到备用DNS服务器,保证域名解析不中断。Ubuntu默认使用systemd-resolved或者NetworkManager来管理DNS,直接修改resolv.conf可能会被覆盖,所以需要掌握正确的配置方法,包括传统方式和systemd-resolved方式两种路径。
一、Ubuntu DNS解析机制的基本认识
Ubuntu系统的DNS解析配置文件位于/etc/resolv.conf,这个文件通常是一个符号链接,指向systemd-resolved生成的stub文件(/run/systemd/resolve/stub-resolv.conf)或者NetworkManager管理的文件。文件内容一般包含nameserver指令,每行一个DNS服务器IP地址。系统按照从上到下的顺序依次尝试DNS服务器,第一个能响应的就被使用,这就是天然的故障转移机制。但问题在于,如果你直接编辑/etc/resolv.conf,重启后配置可能丢失,所以必须从源头去配置。
二、传统方式:直接修改resolv.conf并锁定配置
如果你的Ubuntu版本较老(18.04之前),或者你不使用systemd-resolved,可以直接编辑resolv.conf。打开文件:
sudo nano /etc/resolv.conf
写入多个DNS服务器地址,例如:
nameserver 114.114.114.114 nameserver 8.8.8.8 nameserver 223.5.5.5
这里114.114.114.114是主DNS,8.8.8.8和223.5.5.5是备用。系统会优先使用第一个,如果第一个超时(默认5秒),就尝试第二个。为了防止配置被覆盖,需要安装resolvconf包并锁定文件:
sudo apt install resolvconf sudo chattr +i /etc/resolv.conf
chattr +i命令给文件加了不可修改属性,即使systemd-resolved尝试重写也会失败。但这种方式在新版Ubuntu上并不推荐,因为它和systemd体系存在冲突。
三、systemd-resolved方式:正确的现代配置方法
Ubuntu 18.04及之后的版本默认启用systemd-resolved作为DNS解析服务。正确的做法是修改systemd-resolved的配置文件,而不是直接动resolv.conf。
编辑/etc/systemd/resolved.conf文件:
sudo nano /etc/systemd/resolved.conf
找到或添加以下配置项:
[Resolve] DNS=114.114.114.114 8.8.8.8 223.5.5.5 FallbackDNS=1.1.1.1 9.9.9.9 DNSStubListener=yes DNS=127.0.0.53
这里需要特别说明:DNS指令中多个IP用空格分隔,系统会按顺序尝试。FallbackDNS是当所有配置的DNS都不可用时的兜底方案。DNSStubListener=yes表示systemd-resolved在本地127.0.0.53提供DNS服务。配置完成后重启服务:
sudo systemctl restart systemd-resolved
然后验证配置是否生效:
resolvectl status
输出中会显示当前使用的DNS服务器列表,确认多个DNS都已生效。此时/etc/resolv.conf会自动更新为指向127.0.0.53,这是正常的,不需要手动修改它。
四、NetworkManager方式:适用于桌面版和无线网络环境
如果你的Ubuntu是桌面版,网络由NetworkManager管理,那么需要通过nmcli或者nmtui来配置DNS。使用nmcli命令:
nmcli con mod "你的连接名称" ipv4.dns "114.114.114.114 8.8.8.8 223.5.5.5" nmcli con mod "你的连接名称" ipv4.dns-search "yourdomain.com" nmcli con mod "你的连接名称" ipv4.ignore-auto-dns yes nmcli con up "你的连接名称"
关键参数ipv4.ignore-auto-dns yes的作用是告诉NetworkManager忽略DHCP分配的DNS,使用我们手动指定的。如果不加这一行,DHCP可能会覆盖你的配置。对于无线网络,同样适用这套命令。可以用nmcli con show查看所有连接名称。
五、DNS故障转移的超时和重试策略
默认情况下,系统对每个DNS服务器的超时时间是5秒。如果主DNS挂了,等5秒后才会尝试备用DNS,这在某些场景下可能太慢。可以通过修改systemd-resolved的超时参数来优化。编辑/etc/systemd/resolved.conf:
[Resolve] DNS=114.114.114.114 8.8.8.8 223.5.5.5 Timeout=2 Attempts=3
Timeout=2表示每个DNS服务器等待2秒,Attempts=3表示每个DNS尝试3次。这样总的故障检测时间可以控制在6秒以内,比默认的5秒单次超时更灵活。但要注意,Timeout值不能设得太小(比如低于1秒),否则正常网络波动也会触发不必要的切换。
六、使用resolv.conf的options参数优化解析行为
在resolv.conf中可以添加options指令来控制解析行为,虽然在systemd-resolved体系下这些参数通常放在resolved.conf中,但了解它们很有必要:
options timeout:2 attempts:3 rotate
rotate参数表示轮询使用多个DNS服务器,而不是总是从第一个开始。这在负载均衡场景下很有用,避免所有请求都打到同一个DNS上。但对于故障转移场景,一般不建议加rotate,因为你希望主DNS优先,只有它挂了才用备用。如果你确实需要在resolved.conf中设置,写法是:
[Resolve] DNS=114.114.114.114 8.8.8.8 223.5.5.5 Options=timeout:2 attempts:3
七、验证DNS故障转移是否真正生效
配置完成后必须验证。最直接的方法是模拟DNS故障:
# 先测试主DNS是否正常 dig @114.114.114.114 example.com # 然后用iptables模拟主DNS不可达(测试环境中) sudo iptables -A OUTPUT -d 114.114.114.114 -p udp --dport 53 -j DROP # 再次测试解析 dig example.com # 恢复规则 sudo iptables -D OUTPUT -d 114.114.114.114 -p udp --dport 53 -j DROP
如果dig命令在主DNS被阻断后仍然能返回结果,说明故障转移生效了。另外可以用resolvectl query example.com查看当前使用的是哪个DNS服务器,确认切换逻辑正确。
八、生产环境中的注意事项和最佳实践
第一,不要把所有DNS都配置成同一个运营商的,比如全用电信的DNS,万一该运营商出口故障,所有DNS都不可用。建议主备DNS选择不同运营商或不同服务商,比如114(国内)、阿里DNS(223.5.5.5)、腾讯DNS(119.29.29.29)搭配使用。
第二,DNS服务器数量建议2到3个,不要超过4个。太多DNS会增加解析延迟,因为系统要逐个尝试。三个足够覆盖大多数故障场景。
第三,定期检查DNS配置是否被意外覆盖。可以写一个简单的监控脚本:
#!/bin/bash
EXPECTED_DNS="114.114.114.114 8.8.8.8 223.5.5.5"
ACTUAL_DNS=$(resolvectl status | grep "DNS Server" | awk '{print $3}' | tr '\n' ' ')
if [ "$ACTUAL_DNS" != "$EXPECTED_DNS" ]; then
echo "DNS配置异常,当前: $ACTUAL_DNS" | mail -s "DNS Alert" admin@example.com
fi
第四,如果是服务器环境,建议关闭systemd-resolved的DNS缓存过期策略,避免缓存了错误的解析结果。在resolved.conf中可以设置Cache=no,但这会增加DNS查询量,需要权衡。
第五,对于容器化部署的Ubuntu环境(如Docker),容器内的resolv.conf通常继承宿主机配置,但如果使用了自定义网络,需要在docker run时指定--dns参数或者在daemon.json中全局配置:
{
"dns": ["114.114.114.114", "8.8.8.8", "223.5.5.5"]
}
九、常见问题排查
如果配置后DNS仍然不生效,按以下步骤排查:首先确认systemd-resolved是否在运行(systemctl status systemd-resolved);其次检查/etc/resolv.conf是否是符号链接且指向正确;再次确认resolved.conf中没有语法错误(可以用resolved.conf的man手册检查格式);最后查看journalctl -u systemd-resolved日志,看是否有报错信息。
另一个常见问题是DHCP覆盖DNS配置。如果你的网络通过DHCP获取IP,DHCP服务器可能会下发自己的DNS地址。解决办法就是前面提到的在NetworkManager中设置ipv4.ignore-auto-dns yes,或者在netplan配置中明确指定DNS并覆盖DHCP:
network:
version: 2
ethernets:
eth0:
dhcp4: true
nameservers:
addresses: [114.114.114.114, 8.8.8.8, 223.5.5.5]
netplan是Ubuntu 18.04之后推荐的网络配置工具,通过/etc/netplan/*.yaml文件管理,配置后执行sudo netplan apply生效。这种方式配置的DNS不会被DHCP轻易覆盖,是生产环境中最稳妥的方案之一。
十、总结
Ubuntu运维中配置DNS故障转移并不复杂,关键是选对方法。新版系统优先使用systemd-resolved或netplan来管理DNS,避免直接修改resolv.conf。配置多个不同来源的DNS服务器,设置合理的超时和重试参数,定期监控验证,就能确保在任何单个DNS故障时业务不受影响。记住核心原则:多源DNS、正确配置入口、定期验证,这三点做到了,DNS故障转移就稳了。
