
上次跟几个搞网络的朋友撸串,聊到一个挺有意思的事儿。他们公司业务其实做得挺大,服务器几百台,结果前段时间整个内网瘫了。查了一圈,路由没问题,交换机亮着灯,应用服务也都活着,但就是谁也连不上谁。
最后你猜怎么着?内网那台破DNS服务器挂了。
而且,他们就只有一台。
当时我就笑了,我说你们心也是真大,平时看着挺正规,这种基础设施居然敢搞单点。DNS这玩意儿,平时像空气一样,你感觉不到它的存在,一旦没了,那就跟人被掐住了脖子一样,啥都干不了。什么微服务、数据库连接串,只要你是写域名的,全得歇菜。
所以啊,别偷懒。今天咱们就不聊那些虚头巴脑的架构理论,直接上干货。我把以前在生产环境部署 BIND9 主从(Master-Slave)的那套东西翻出来,咱们一步一步搭一套高可用的DNS。
不管你是用 CentOS 还是 Rocky Linux,甚至 Ubuntu,道理都一样,命令大差不差。哪怕你现在还没碰到过DNS故障,先把这一手备着,保不齐哪天能救命。
简单说,就是搞两台服务器。
我这次演示的环境挺简单的,两台虚拟机,跑的是 Rocky Linux 9(CentOS 7也都一样,没啥区别):
行了,废话不说,开整。
两台机器(Master 和 Slave)都要操作。
别想着去源码编译安装 BIND,除非你有特殊癖好或者版本强迫症。生产环境求的是稳,直接用包管理器装官方源里的版本最省心,出了漏洞修补也快。
dnf install bind bind-utils -y装完之后,设个开机自启。很多新人最容易犯的错就是配置配得天花乱坠,服务器一重启,服务没起来,大半夜被报警电话叫起来排障,结果发现是没 enable。
systemctl enable named
systemctl start named这里提一嘴,BIND 的服务名在 Linux 里通常叫 named(Name Daemon),别敲成 bind 了,你会发现找不到服务。
还有个事儿,防火墙。
以前我碰到过一个兄弟,死活配置不通,都要重装系统了。我过去看了一眼,firewalld 开着呢,53端口没放行。DNS 默认用的是 UDP 53,有时候数据包大了(比如有 DNSSEC)或者区域传输的时候,也会用到 TCP 53。
省事儿点,把 UDP 和 TCP 的 53 都开了:
firewall-cmd --permanent --add-service=dns
firewall-cmd --reload如果你是在云服务器上,别忘了去安全组里也放行一下。
这是重头戏。配置文件一般在 /etc/named.conf。
操作之前,哪怕你是十年老手,也请你养成一个好习惯:备份。
cp /etc/named.conf /etc/named.conf.bak打开配置文件,咱们得改几个关键地方。BIND 的配置文件对格式要求极其变态,少个分号、少个花括号都能让你服务起不来,改的时候心细点。
我贴一部分核心配置,大家对着改:
options {
# 监听端口和IP。注意了,默认可能是 127.0.0.1,一定要改成你的内网IP或者 any
listen-on port 53 { 127.0.0.1; 192.168.31.100; };
# 这一行如果是IPv6,不用管它,或者注释掉
listen-on-v6 port 53 { ::1; };
# 允许哪些机器查询?内网环境一般写 any 或者指定网段
# 生产环境建议写具体的网段,比如 192.168.31.0/24,安全点
allow-query { any; };
# 这一步很关键!允许谁来同步数据?
# 必须把 Slave 的 IP 加进来,不然 Slave 也就是个摆设,拉不到数据
allow-transfer { 192.168.31.101; };
# 转发器。如果解析不了外网域名(比如 baidu.com),就丢给这些公网DNS
forwarders { 114.114.114.114; 8.8.8.8; };
recursion yes;
# 下面这些默认的路径不用动
directory "/var/named";
dump-file "/var/named/data/cache_dump.db";
statistics-file "/var/named/data/named_stats.txt";
memstatistics-file "/var/named/data/named_mem_stats.txt";
secroots-file "/var/named/data/named.secroots";
recursing-file "/var/named/data/named.recursing";
};这里要多啰嗦一句 recursion yes;。如果是对内网服务的 DNS,开启递归查询是必须的,因为你还得让员工能上百度、刷B站。但如果你的 DNS 是暴露在公网给别人解析你的域名的,千万别开递归,不然会被人利用搞 DNS 放大攻击,流量能把你打死。
接下来,在 named.conf 的最下面(或者它包含的 named.rfc1912.zones 文件里),定义咱们的区域(Zone)。
# 正向解析区域:域名 -> IP
zone "ops-coffee.local" IN {
type master; # 声明我是老大
file "ops-coffee.local.zone"; # 解析文件放在哪
allow-update { none; }; # 咱们手动改文件,不许动态更新
};
# 反向解析区域:IP -> 域名(可选,但推荐配上,有些古老应用依赖这个)
zone "31.168.192.in-addr.arpa" IN {
type master;
file "192.168.31.zone";
};刚才我们在配置里写了 file "ops-coffee.local.zone"; 既然写了,就得有这个文件。它通常在 /var/named/ 目录下。
我们可以复制一个模板过来改,保留好权限:
cd /var/named/
cp -p named.localhost ops-coffee.local.zone编辑 ops-coffee.local.zone。这地方是新手掉坑最多的地方,尤其是那个 Serial Number。
$TTL 1D
@ IN SOA ns1.ops-coffee.local. admin.ops-coffee.local. (
2023102601 ; serial
1D ; refresh
1H ; retry
1W ; expire
3H ) ; minimum
NS ns1.ops-coffee.local.
NS ns2.ops-coffee.local. ; 这里要把Slave也写上
ns1 A 192.168.31.100
ns2 A 192.168.31.101
; 下面是具体的业务记录
www A 192.168.31.200
db A 192.168.31.201
api CNAME www重点敲黑板!!
看到那个 2023102601 了吗?那个叫序列号(Serial)。
每次你修改主库的解析记录,必须把这个数字改大!必须改大!哪怕加个1也行。
Slave 它是很傻的,它只看这个号。如果它发现老大的号跟自己一样,它就觉得:“哦,没变化,那我接着睡。” 只有老大的号比它大,它才会去把新的记录拉过来。
我以前带的一个实习生,在那排查了半天说主从不同步,哭丧着脸来找我,结果一看,序列号也就是 Serial 没变。这种低级错误,真的能气死人。
还有一个细节,域名后面那个点 .。比如 ns1.ops-coffee.local.。在 BIND 的世界里,如果没有最后那个点,它会自动给你补上区域名。如果你写成 ns1.ops-coffee.local(没点),它解析出来可能就变成了 ns1.ops-coffee.local.ops-coffee.local。这画面太美我不敢看。
检查配置有没有语法错误:
named-checkconf
named-checkzone ops-coffee.local /var/named/ops-coffee.local.zone只要没报错,就可以重启 Master 的服务了:
systemctl restart namedSlave 的配置比 Master 简单多了,因为它不需要自己写具体的域名记录文件,全靠“白嫖”老大的。
登录到 192.168.31.101。
同样编辑 /etc/named.conf。options 部分跟 Master 基本一样,listen-on 改成自己的IP。
关键是区域配置:
zone "ops-coffee.local" IN {
type slave; # 声明我是小弟
masters { 192.168.31.100; }; # 声明老大是谁
file "slaves/ops-coffee.local.zone"; # 同步回来的文件放哪?
};
zone "31.168.192.in-addr.arpa" IN {
type slave;
masters { 192.168.31.100; };
file "slaves/192.168.31.zone";
};注意那个 file 的路径:slaves/ops-coffee.local.zone。
为什么是 slaves/?因为在 /var/named/ 目录下,普通用户(named用户)通常只有读取权限,没有写入权限。而 /var/named/slaves 这个目录,默认是给 named 用户写权限的。
如果不加 slaves/ 前缀,你会发现日志里报错 permission denied,导致同步失败。这也是个经典坑位。
配置改完,重启服务:
systemctl restart named这时候,你去 Slave 机器的 /var/named/slaves/ 目录下看一眼:
ls -l /var/named/slaves/如果看到 ops-coffee.local.zone 这个文件出现了,甚至是个乱码文件(因为传输过来可能是二进制格式,这很正常),那就说明同步成功了!
咱们来验证一下。
找台内网的电脑,或者就在 Master 上,用 dig 命令指定向 Slave 查询:
dig @192.168.31.101 www.ops-coffee.local如果返回了 192.168.31.200,那就是通了。
高可用测试:
现在,咱们玩个刺激的。把 Master (192.168.31.100) 的 named 服务直接停掉:
systemctl stop named然后再去那台测试机上,把 DNS 设置成 Slave 的 IP,或者继续用 dig 指定查询。你会发现,解析依然丝般顺滑。这就是主从架构的意义——老大挂了,小弟顶上。
上面的步骤,很多网上的教程也能凑合教你,但下面这两点,是咱们真正做运维的才会关注的。
1. 时间同步 (NTP)
DNS 这东西对时间虽然没那么极其敏感(不像 Kerberos),但在做主从同步、特别是涉及 DNSSEC 的时候,时间差太大绝对会有问题。
确保你的 Master 和 Slave 都配置了 Chrony 或者 NTP,时间要一致。别到时候日志里一堆 "time out" 或者 "clock skew",你都找不着北。
2. SELinux 的锅
说实话,为了省事,很多教程第一步就是 setenforce 0。但在合规要求严格的企业,关 SELinux 是要被安全团队批斗的。
如果你非要开着 SELinux,记得给文件打标。特别是 Slave 目录,如果同步不过来,很有可能是 SELinux 拦住了 named 进程的写入操作。
# 看看审计日志是不是被拒了
grep denied /var/log/audit/audit.log实在搞不定,还是先临时宽容模式排查问题,别跟自己过不去。
3. 增量传输 (IXFR) vs 全量传输 (AXFR)
BIND 默认是很聪明的。如果你的区域文件特别大(比如几万条记录),每次改一条记录就全量传一次,网卡都要爆了。它会自动尝试增量传输。
但是,这依赖于你的操作日志(journal)。如果你手欠把 /var/named/ 下面的 .jnl 文件删了,那下次同步就只能全量来了。所以,运维的时候手别太快,删文件前先过过脑子。
搭建 DNS 主从其实真不难,难的是细心。
把这套东西搭起来,你的内网解析就有了双保险。哪怕机房光纤被挖掘机铲断了一根,只要还有一台 DNS 活着,你的业务就不至于全线崩盘。
这年头,运维就是个操心的命。咱们能做的,就是把地基打牢点,别让那些低级故障毁了咱们的周末。
行了,今天就扯到这。如果你在搭建过程中碰到什么奇葩报错,或者有关于 DNS 优化的心得,欢迎在评论区留言,咱们一起探讨探讨。
我是爱折腾的老炮儿,咱们下篇文章见。
公众号:运维躬行录 个人博客:躬行笔记
觉得有用的话,点个在看或者转发给身边的兄弟们,别让大家都在单点故障的边缘疯狂试探了!