首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >还在用单点DNS?生产环境炸一次你就老实了,手把手教你搭建高可用主从架构!

还在用单点DNS?生产环境炸一次你就老实了,手把手教你搭建高可用主从架构!

作者头像
悠悠12138
发布2026-03-02 21:36:33
发布2026-03-02 21:36:33
1060
举报

上次跟几个搞网络的朋友撸串,聊到一个挺有意思的事儿。他们公司业务其实做得挺大,服务器几百台,结果前段时间整个内网瘫了。查了一圈,路由没问题,交换机亮着灯,应用服务也都活着,但就是谁也连不上谁。

最后你猜怎么着?内网那台破DNS服务器挂了。

而且,他们就只有一台。

当时我就笑了,我说你们心也是真大,平时看着挺正规,这种基础设施居然敢搞单点。DNS这玩意儿,平时像空气一样,你感觉不到它的存在,一旦没了,那就跟人被掐住了脖子一样,啥都干不了。什么微服务、数据库连接串,只要你是写域名的,全得歇菜。

所以啊,别偷懒。今天咱们就不聊那些虚头巴脑的架构理论,直接上干货。我把以前在生产环境部署 BIND9 主从(Master-Slave)的那套东西翻出来,咱们一步一步搭一套高可用的DNS。

不管你是用 CentOS 还是 Rocky Linux,甚至 Ubuntu,道理都一样,命令大差不差。哪怕你现在还没碰到过DNS故障,先把这一手备着,保不齐哪天能救命。

咱们要干个啥事儿?

简单说,就是搞两台服务器。

  • Master(主库):这是老大,负责维护域名的解析记录。所有的修改、添加域名都在这上面操作。
  • Slave(从库):这是小弟,平时从老大那里同步数据。当客户端查询域名的时候,可以找老大,也可以找小弟。最重要的是,如果老大挂了,小弟还在,业务就不会停。

我这次演示的环境挺简单的,两台虚拟机,跑的是 Rocky Linux 9(CentOS 7也都一样,没啥区别):

  • ns1 (Master): 192.168.31.100
  • ns2 (Slave): 192.168.31.101
  • 域名域:ops-coffee.local (咱们自己瞎编的一个内网域名)

行了,废话不说,开整。

第一步:装软件,别整那些花里胡哨的

两台机器(Master 和 Slave)都要操作。

别想着去源码编译安装 BIND,除非你有特殊癖好或者版本强迫症。生产环境求的是稳,直接用包管理器装官方源里的版本最省心,出了漏洞修补也快。

代码语言:javascript
复制
dnf install bind bind-utils -y

装完之后,设个开机自启。很多新人最容易犯的错就是配置配得天花乱坠,服务器一重启,服务没起来,大半夜被报警电话叫起来排障,结果发现是没 enable。

代码语言:javascript
复制
systemctl enable named
systemctl start named

这里提一嘴,BIND 的服务名在 Linux 里通常叫 named(Name Daemon),别敲成 bind 了,你会发现找不到服务。

还有个事儿,防火墙

以前我碰到过一个兄弟,死活配置不通,都要重装系统了。我过去看了一眼,firewalld 开着呢,53端口没放行。DNS 默认用的是 UDP 53,有时候数据包大了(比如有 DNSSEC)或者区域传输的时候,也会用到 TCP 53。

省事儿点,把 UDP 和 TCP 的 53 都开了:

代码语言:javascript
复制
firewall-cmd --permanent --add-service=dns
firewall-cmd --reload

如果你是在云服务器上,别忘了去安全组里也放行一下。

第二步:配置 Master(主节点)

这是重头戏。配置文件一般在 /etc/named.conf

操作之前,哪怕你是十年老手,也请你养成一个好习惯:备份

代码语言:javascript
复制
cp /etc/named.conf /etc/named.conf.bak

打开配置文件,咱们得改几个关键地方。BIND 的配置文件对格式要求极其变态,少个分号、少个花括号都能让你服务起不来,改的时候心细点。

我贴一部分核心配置,大家对着改:

代码语言:javascript
复制
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)。

代码语言:javascript
复制
# 正向解析区域:域名 -> 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/ 目录下。

我们可以复制一个模板过来改,保留好权限:

代码语言:javascript
复制
cd /var/named/
cp -p named.localhost ops-coffee.local.zone

编辑 ops-coffee.local.zone。这地方是新手掉坑最多的地方,尤其是那个 Serial Number。

代码语言:javascript
复制
$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。这画面太美我不敢看。

检查配置有没有语法错误:

代码语言:javascript
复制
named-checkconf
named-checkzone ops-coffee.local /var/named/ops-coffee.local.zone

只要没报错,就可以重启 Master 的服务了:

代码语言:javascript
复制
systemctl restart named

第四步:配置 Slave(从节点)

Slave 的配置比 Master 简单多了,因为它不需要自己写具体的域名记录文件,全靠“白嫖”老大的。

登录到 192.168.31.101。

同样编辑 /etc/named.confoptions 部分跟 Master 基本一样,listen-on 改成自己的IP。

关键是区域配置:

代码语言:javascript
复制
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,导致同步失败。这也是个经典坑位。

配置改完,重启服务:

代码语言:javascript
复制
systemctl restart named

第五步:见证奇迹的时刻

这时候,你去 Slave 机器的 /var/named/slaves/ 目录下看一眼:

代码语言:javascript
复制
ls -l /var/named/slaves/

如果看到 ops-coffee.local.zone 这个文件出现了,甚至是个乱码文件(因为传输过来可能是二进制格式,这很正常),那就说明同步成功了!

咱们来验证一下。

找台内网的电脑,或者就在 Master 上,用 dig 命令指定向 Slave 查询:

代码语言:javascript
复制
dig @192.168.31.101 www.ops-coffee.local

如果返回了 192.168.31.200,那就是通了。

高可用测试:

现在,咱们玩个刺激的。把 Master (192.168.31.100) 的 named 服务直接停掉:

代码语言:javascript
复制
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 进程的写入操作。

代码语言:javascript
复制
# 看看审计日志是不是被拒了
grep denied /var/log/audit/audit.log

实在搞不定,还是先临时宽容模式排查问题,别跟自己过不去。

3. 增量传输 (IXFR) vs 全量传输 (AXFR)

BIND 默认是很聪明的。如果你的区域文件特别大(比如几万条记录),每次改一条记录就全量传一次,网卡都要爆了。它会自动尝试增量传输。

但是,这依赖于你的操作日志(journal)。如果你手欠把 /var/named/ 下面的 .jnl 文件删了,那下次同步就只能全量来了。所以,运维的时候手别太快,删文件前先过过脑子。

总结一下

搭建 DNS 主从其实真不难,难的是细心。

  1. 1. Master 配置文件要注意权限和 IP 限制。
  2. 2. Zone 文件里的 Serial Number 记得每次都要加。
  3. 3. Slave 的文件路径要放在有写权限的目录下。
  4. 4. 防火墙端口要开对(TCP/UDP 53)。

把这套东西搭起来,你的内网解析就有了双保险。哪怕机房光纤被挖掘机铲断了一根,只要还有一台 DNS 活着,你的业务就不至于全线崩盘。

这年头,运维就是个操心的命。咱们能做的,就是把地基打牢点,别让那些低级故障毁了咱们的周末。

行了,今天就扯到这。如果你在搭建过程中碰到什么奇葩报错,或者有关于 DNS 优化的心得,欢迎在评论区留言,咱们一起探讨探讨。

我是爱折腾的老炮儿,咱们下篇文章见。


公众号:运维躬行录 个人博客:躬行笔记

觉得有用的话,点个在看或者转发给身边的兄弟们,别让大家都在单点故障的边缘疯狂试探了!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-02-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 运维躬行录 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 咱们要干个啥事儿?
  • 第一步:装软件,别整那些花里胡哨的
  • 第二步:配置 Master(主节点)
  • 第三步:造解析文件
  • 第四步:配置 Slave(从节点)
  • 第五步:见证奇迹的时刻
  • 进阶:几个不得不说的生产痛点
  • 总结一下
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档