bind篇01-Bind+Keepalived安装高可用DNS集群

本文最后更新于:March 24, 2024 am

本文主要对bind进行安装配置,并且搭配keepalived实现高可用。

1、系统环境准备

这里我们使用的是centos7的操作系统,默认使用yum安装的情况下,bind的程序named会安装到/var/named目录下,注意保证分区的大小,当然也可以使用chroot包来修改目录,这里使用默认目录

1
2
3
4
5
6
$ lsb_release -a
LSB Version: :core-4.1-amd64:core-4.1-noarch:cxx-4.1-amd64:cxx-4.1-noarch:desktop-4.1-amd64:desktop-4.1-noarch:languages-4.1-amd64:languages-4.1-noarch:printing-4.1-amd64:printing-4.1-noarch
Distributor ID: CentOS
Description: CentOS Linux release 7.9.2009 (Core)
Release: 7.9.2009
Codename: Core

2、bind安装

bind的安装非常简单,默认的centos系统的yum源中就包含了其安装包,不同的系统版本对应的bind版本略有差异但是不大。

1
2
3
4
5
6
7
8
9
$ yum list | egrep ^bind.x86_64
bind.x86_64 32:9.11.20-5.el8_3.1 appstream
$ cat /etc/redhat-release
CentOS Linux release 8.3.2011

[root@tiny-cloud ~]# yum list | egrep ^bind.x86_64
bind.x86_64 32:9.11.4-26.P2.el7_9.5 updates
[root@tiny-cloud ~]# cat /etc/redhat-release
CentOS Linux release 7.9.2009 (Core)

一般我们只需要安装bind和bind-utils这两个包,前者是bind的主要程序named和控制工具rndc等,后者则是一些常用工具如dig命令等。

1
$ yum install bind bind-utils

安装完成之后我们就会发现系统主要新增了/var/named/etc/named/etc/named*一系列文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ ll /var/named/
total 28K
drwxrwx--- 2 named named 4.0K Apr 29 22:05 data
drwxrwx--- 2 named named 4.0K Apr 29 22:05 dynamic
-rw-r----- 1 root named 2.3K Apr 5 2018 named.ca
-rw-r----- 1 root named 152 Dec 15 2009 named.empty
-rw-r----- 1 root named 152 Jun 21 2007 named.localhost
-rw-r----- 1 root named 168 Dec 15 2009 named.loopback
drwxrwx--- 2 named named 4.0K Apr 29 22:05 slaves
$ ll /etc/named*
-rw-r----- 1 root named 1.8K Apr 29 22:06 /etc/named.conf
-rw-r--r-- 1 root named 3.9K Apr 29 22:06 /etc/named.iscdlv.key
-rw-r----- 1 root named 931 Jun 21 2007 /etc/named.rfc1912.zones
-rw-r--r-- 1 root named 1.9K Apr 13 2017 /etc/named.root.key

/etc/named:
total 0

同时我们可以使用systemd来对named服务进行管理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ systemctl enable named.service
Created symlink from /etc/systemd/system/multi-user.target.wants/named.service to /usr/lib/systemd/system/named.service.
$ systemctl start named.service
$ systemctl status named.service
● named.service - Berkeley Internet Name Domain (DNS)
Loaded: loaded (/usr/lib/systemd/system/named.service; enabled; vendor preset: disabled)
Active: active (running) since Thu 2021-05-20 16:26:36 CST; 10min ago
Main PID: 28777 (named)
Tasks: 4
Memory: 58.6M
CGroup: /system.slice/named.service
└─28777 /usr/sbin/named -u named -c /etc/named.conf

May 20 16:31:49 tiny-cloud named[28777]: validating net/SOA: got insecure response; parent indicates it should be secure
May 20 16:31:49 tiny-cloud named[28777]: no valid RRSIG resolving 'edgekey.net/DS/IN': 192.12.94.30#53
May 20 16:31:49 tiny-cloud named[28777]: validating net/SOA: got insecure response; parent indicates it should be secure
May 20 16:31:49 tiny-cloud named[28777]: no valid RRSIG resolving 'edgekey.net/DS/IN': 192.31.80.30#53
May 20 16:31:49 tiny-cloud named[28777]: validating net/DNSKEY: got insecure response; parent indicates it should be secure
May 20 16:31:49 tiny-cloud named[28777]: insecurity proof failed resolving 'net/DNSKEY/IN': 192.12.94.30#53
May 20 16:31:50 tiny-cloud named[28777]: validating net/DNSKEY: got insecure response; parent indicates it should be secure
May 20 16:31:50 tiny-cloud named[28777]: insecurity proof failed resolving 'net/DNSKEY/IN': 192.31.80.30#53
May 20 16:31:51 tiny-cloud named[28777]: validating net/SOA: got insecure response; parent indicates it should be secure
May 20 16:31:51 tiny-cloud named[28777]: no valid RRSIG resolving 'akamaiedge.net/DS/IN': 192.31.80.30#53

3、bind配置

3.1 IPv6相关配置

无论是centos7还是centos8系统使用yum进行安装的bind都已经默认开启了IPv6的支持,如果我们的系统暂时还不支持IPv6网络,则最好把配置文件中的IPv6相关的配置去除

1
sed -i 's#listen-on-v6 port 53 { ::1; };#//listen-on-v6 port 53 { ::1; };#g' /etc/named.conf

同时如果是把bind当作递归查询服务器使用,默认情况下的bind是会自动启用了hint类型的解析

1
2
3
4
zone "." IN {
type hint;
file "named.ca";
};

该配置会把所有匹配到这个zone的DNS查询请求转发到/var/named/named.ca文件中的13个根DNS服务器节点,为了减少不必要的干扰,我们可以把文件中的的AAAA记录注释掉。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
;; ADDITIONAL SECTION:
a.root-servers.net. 518400 IN A 198.41.0.4
b.root-servers.net. 518400 IN A 199.9.14.201
c.root-servers.net. 518400 IN A 192.33.4.12
d.root-servers.net. 518400 IN A 199.7.91.13
e.root-servers.net. 518400 IN A 192.203.230.10
f.root-servers.net. 518400 IN A 192.5.5.241
g.root-servers.net. 518400 IN A 192.112.36.4
h.root-servers.net. 518400 IN A 198.97.190.53
i.root-servers.net. 518400 IN A 192.36.148.17
j.root-servers.net. 518400 IN A 192.58.128.30
k.root-servers.net. 518400 IN A 193.0.14.129
l.root-servers.net. 518400 IN A 199.7.83.42
m.root-servers.net. 518400 IN A 202.12.27.33
a.root-servers.net. 518400 IN AAAA 2001:503:ba3e::2:30
b.root-servers.net. 518400 IN AAAA 2001:500:200::b
c.root-servers.net. 518400 IN AAAA 2001:500:2::c
d.root-servers.net. 518400 IN AAAA 2001:500:2d::d
e.root-servers.net. 518400 IN AAAA 2001:500:a8::e
f.root-servers.net. 518400 IN AAAA 2001:500:2f::f
g.root-servers.net. 518400 IN AAAA 2001:500:12::d0d
h.root-servers.net. 518400 IN AAAA 2001:500:1::53
i.root-servers.net. 518400 IN AAAA 2001:7fe::53
j.root-servers.net. 518400 IN AAAA 2001:503:c27::2:30
k.root-servers.net. 518400 IN AAAA 2001:7fd::1
l.root-servers.net. 518400 IN AAAA 2001:500:9f::42
m.root-servers.net. 518400 IN AAAA 2001:dc3::35

3.2 named.conf配置rndc

rndc可以简单视为是一个用来控制或者查看named系统的命令行工具。它不仅可以在服务器本地使用,还可以远程控制其他的bind服务器上面的named服务。但是在默认情况下的配置文件中并没有对其进行显示配置,所以named程序默认情况下只会监听本机127.0.0.1953端口

1
2
3
4
$ netstat -ntulp | grep named
tcp 0 0 127.0.0.1:953 0.0.0.0:* LISTEN 12737/named
tcp 0 0 127.0.0.1:53 0.0.0.0:* LISTEN 12737/named
udp 0 0 127.0.0.1:53 0.0.0.0:* 12737/named

named.conf文件中对rndc进行配置,主要涉及到三个选项:监听网卡(inet)、允许IP(allow)和认证使用的keys

  • 这样子就是设为监听机器上的所有网卡并允许所有的来源IP进行访问,不过限制了需要使用keys

    1
    2
    3
    4
    # 这样子就是设为监听机器上的所有网卡并允许所有的来源IP进行访问,不过限制了需要使用keys
    controls {
    inet * allow { any; } keys { "rndc-key"; };
    };
  • 这种限制了只能在本机上使用rndc

    1
    2
    3
    4
    # 这种限制了只能在本机上使用rndc    
    controls {
    inet 127.0.0.1 allow { localhost; } keys { "rndc-key"; };
    };
  • 这种限制了在局域网和本机上使用rndc,如果有多个inet需要指定监听则需要分开多条配置,并且可以添加port参数来指定端口

    1
    2
    3
    4
    5
    # 这种限制了在局域网和本机上使用rndc,如果有多个inet需要指定监听则需要分开多条配置  
    controls {
    inet 127.0.0.1 allow { localhost; } keys { rndckey; };
    inet 192.168.1.1 port 1953 allow { 192.168.1.1; 192.168.1.2; 192.168.1.0/24;} keys { rndckey; };
    };

3.3 rndc-key配置

keys在这里的作用主要是鉴权,效果相当于ssh程序中的ssh-key,因此如果需要远程操作,需要保证客户端和服务端的keys一致。

rndc-key只是keys这个参数的一个值,相当于一个key-value,这里只是用来指代,实际上换成tinycehn-key之类的其他名字也是没问题的,本质上它们都是一个HMAC-MD5的key,因此首先我们需要生成一个rndc-key。在bind9里面,一般情况下我们可以使用dnssec-keygen命令生成或者是rndc-confgen -a命令直接生成。这里个人推荐直接使用后者。

1
2
3
4
5
6
7
$ rndc-confgen -a
wrote key file "/etc/rndc.key"
$ cat /etc/rndc.key
key "rndc-key" {
algorithm hmac-md5;
secret "0JqEwIF4kihHEcAbgC4t1w==";
};

使用dnssec-keygen命令的时候会生成一个key和一个private文件,private文件里面记录着详细信息,同时这样我们需要手动将格式修改为rndc支持的格式并放置在/etc/rndc.key文件中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ dnssec-keygen -a hmac-md5 -b 256 -n HOST tinychen-key
Ktinychen-key.+157+42293
$ ll
total 8
-rw------- 1 root root 76 May 20 15:37 Ktinychen-key.+157+42293.key
-rw------- 1 root root 185 May 20 15:37 Ktinychen-key.+157+42293.private
$ cat Ktinychen-key.+157+42293.key
tinychen-key. IN KEY 512 3 157 uEICksjZ53OlSXPpHrAmS1s/FhRy5g26+KUCtGqmflM=
$ cat Ktinychen-key.+157+42293.private
Private-key-format: v1.3
Algorithm: 157 (HMAC_MD5)
Key: uEICksjZ53OlSXPpHrAmS1s/FhRy5g26+KUCtGqmflM=
Bits: AAA=
Created: 20210520073748
Publish: 20210520073748
Activate: 20210520073748

In this case, the is a HMAC-MD5 key. You can generate your own HMAC-MD5 keys with the following command:

dnssec-keygen -a hmac-md5 -b -n HOST
A key with at least a 256-bit length is good idea. The actual key that should be placed in the area can found in the .

The name of the key used in /etc/named.conf should be something other than key.

3.4 rndc.conf配置

默认情况下并不会生成rndc.conf文件,因此我们需要自己手动生成一个。使用rndc-confgen命令可以快速地生成一个配置模板并且打印到终端窗口上(注意执行命令之后并不会生成rndc.conf文件,需要我们手动将生成的配置写入文件/etc/rndc.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ rndc-confgen
# Start of rndc.conf
key "rndc-key" {
algorithm hmac-md5;
secret "h0Pmn9ueo1Uk9Cv6cpPE2w==";
};

options {
default-key "rndc-key";
default-server 127.0.0.1;
default-port 953;
};
# End of rndc.conf

# Use with the following in named.conf, adjusting the allow list as needed:
# key "rndc-key" {
# algorithm hmac-md5;
# secret "h0Pmn9ueo1Uk9Cv6cpPE2w==";
# };
#
# controls {
# inet 127.0.0.1 port 953
# allow { 127.0.0.1; } keys { "rndc-key"; };
# };
# End of named.conf


需要注意的是,当同时存在rndc.conf文件和rndc.key文件的时候,默认是优先读取rndc.conf,如果我们需要指定不同的key来访问不同的server,可以在命令中指定参数,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ cat /etc/rndc.conf
key "rndc-key" {
algorithm hmac-md5;
secret "h0Pmn9ueo1Uk9Cv6cpPE2w==";
};

key "rndc-conf-key" {
algorithm hmac-md5;
secret "uEICksjZ53OlSXPpHrAmS1s/FhRy5g26+KUCtGqmflM=";
};

options {
default-key "rndc-key";
default-server 127.0.0.1;
default-port 953;
};

# -s参数用来指定不同的服务器,这里可以是域名也可以是IP
# -k参数用来指定key,但是后面跟着的是一个类似rndc.key的文件
# -y参数也是用来指定key,但是后面跟着的参数需要是在rndc.conf文件中已经写明的key的key-value
$ rndc -s localhost -k /etc/rndc.key status
$ rndc -s 192.168.1.1 -y rndc-conf-key status

4、keepalived安装

由于这里只需要支持IPv4网络的keepalived程序,因此我们可以直接使用yum源来安装keepalived,如果有较高的版本要求或者特殊需要,可以考虑自行下载源码编译安装。

1
$ yum install keepalived

同时为了方便我们debug,这里再将keepalived的日志额外重定向到单独的目录文件中

首先我们需要修改keepalived的默认启动参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ sed -i 's#KEEPALIVED_OPTIONS="-D"#KEEPALIVED_OPTIONS="-D -d -S 0"#g' /etc/sysconfig/keepalived
$ cat /etc/sysconfig/keepalived
# Options for keepalived. See `keepalived --help' output and keepalived(8) and
# keepalived.conf(5) man pages for a list of all options. Here are the most
# common ones :
#
# --vrrp -P Only run with VRRP subsystem.
# --check -C Only run with Health-checker subsystem.
# --dont-release-vrrp -V Dont remove VRRP VIPs & VROUTEs on daemon stop.
# --dont-release-ipvs -I Dont remove IPVS topology on daemon stop.
# --dump-conf -d Dump the configuration data.
# --log-detail -D Detailed log messages.
# --log-facility -S 0-7 Set local syslog facility (default=LOG_DAEMON)
#

KEEPALIVED_OPTIONS="-D -d -S 0"

修改syslog的配置,将日志输出到指定的目录

1
2
# 对于系统使用rsyslog服务来管理日志的,可以修改 /etc/rsyslog.conf 加入下列的配置
local0.* /path/to/keepalived.log

最后重启rsyslog服务和keepalived服务即可

1
2
$ systemctl enable rsyslog.service
$ systemctl restart rsyslog.service

5、bind主从安装

主从两个节点的安装理论上应该完全一致。需要注意的是:

  • 两个节点之间的rndc配置必须要保证能够互相远程访问
  • 确保两者之间的配置文件能够保持同步(可以使用git或者rsync等方式)
  • 确保两个节点的named.conf配置文件中的监听网卡和端口覆盖了本机IP和VIP

6、高可用过程分析

这里为了保证DNS节点的高可用,我们使用keepalived将两台机器分别作为主从节点,做一个简单的主从节点方式的高可用。

正常情况下,主节点的priority为100,从节点的priority为90,此时VIP在主节点上,请求和流量从VIP进入,由主节点提供服务,从节点作为备用。

当主节点出现异常时,VIP偏移到从节点,从节点进入MASTER状态,直到主节点本身的服务恢复正常再切换过去。

而为了防止VIP偏移到对应的机器上的时候,named服务没有监听到对应的端口,我们在脚本中设置当keepalived进入notify_master时重启一下named服务,确保能够VIP的服务端口能够被正常监听。

注意在主节点脚本中设置的检测方式是检测MASTER本身的IP上的rndc状态是否正常而不是VIP上面的rndc状态,而备节点也是检测本机的IP,确保本机的服务是正常的。

我们以下面的配置为例进行分析,master节点的初始权重是100,backup节点的初始权重是90,两者的脚本都是检测本机的DNS服务是否正常,当不正常的时候weight -20。当master节点的DNS出现故障,weight从100降到80,此时VIP就会切换到backup节点,当master节点恢复正常的时候,weight上升回100,此时VIP就会重新回到master节点上面。

三个节点的配置也是同理,只需要保证出问题的节点的weight,在出问题之后,减去的weight要低于所有节点中最低的weight即可。

例如三个节点分别是100、90、80,则建议vrrp_script中的weight最少要-30,确保100的节点出了故障之后,要比正常的没出故障的80的节点weight更低。

这里主要是为了避免当主节点本身DNS服务就有问题,而它的检测脚本又是检测VIP的rndc状态时,VIP切到从节点后可以正常提供服务,然后主节点脚本检测正常,将VIP抢了回来,但是这时候主节点自己是无法正常提供服务的,随后主节点检测到服务不正常,weight下降,备用节点又将VIP抢了过去,然后继续循环导致VIP不断偏移。

7、keepalived配置

keepalived的配置比较简单,注意这里的intervalinterfacerouter_idvirtual_router_id等参数可以根据实际情况进行调整。

7.1 keepalived.conf(master)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
! Configuration File for keepalived

global_defs {
router_id HA_DNS
}

vrrp_script chk_dns {
# 定义检测的脚本和执行参数
script "/etc/keepalived/dns_status.sh check master机器的IP"
# 定义脚本的执行时间间隔为2秒
interval 2
# 执行失败的时候weight-20
weight -20
# 检测到脚本执行两次失败才算失败
fall 2
# 检测到脚本执行成功一次就算成功
rise 1
}

vrrp_instance VIRT_DNS {
state MASTER
interface eth0
virtual_router_id 201
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 7777@tinychen
}
track_script {
chk_dns
}

virtual_ipaddress {
需要配置的VIP(e.g. 1.1.1.1) dev VIP所在的网卡(e.g. eth0)
}

notify_master "/etc/keepalived/dns_status.sh notify master"
notify_backup "/etc/keepalived/dns_status.sh notify backup"
notify_fault "/etc/keepalived/dns_status.sh notify fault"
}

7.2 keepalived.conf(backup)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
! Configuration File for keepalived

global_defs {
router_id HA_DNS
}

vrrp_script chk_dns {
script "/etc/keepalived/dns_status.sh check backup主机的IP"
# 定义脚本的执行时间间隔为2秒
interval 2
# 执行失败的时候weight-20
weight -20
# 检测到脚本执行两次失败才算失败
fall 2
# 检测到脚本执行成功一次就算成功
rise 1
}

vrrp_instance VIRT_DNS {
state BACKUP
interface eth0
virtual_router_id 201
priority 90
advert_int 1
authentication {
auth_type PASS
auth_pass 7777@tinychen
}
track_script {
chk_dns
}

virtual_ipaddress {
需要配置的VIP(e.g. 1.1.1.1) dev VIP所在的网卡(e.g. eth0)
}

notify_master "/etc/keepalived/dns_status.sh notify master"
notify_backup "/etc/keepalived/dns_status.sh notify backup"
notify_fault "/etc/keepalived/dns_status.sh notify fault"
}

7.3 dns_status.sh

这里脚本的放置目录要和上面的keepalived配置文件中的目录保持一致

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# vim /etc/keepalived/dns_status.sh

#!/bin/bash
LOGFILE="/home/named/keepalived/keepalived.log"
case "$1" in
check)
ALIVE=$(/usr/sbin/rndc -s $2 status | grep "server is up and running")
if [ $? == 0 ]; then
exit 0
else
echo "---------------------------------------" >>$LOGFILE
date "+%Y-%m-%d %H:%M:%S" >>$LOGFILE
echo "Using rndc status check failed" >>$LOGFILE
echo "---------------------------------------" >>$LOGFILE
exit 1
fi
;;
notify)
echo "---------------------------------------" >>$LOGFILE
date "+%Y-%m-%d %H:%M:%S" >>$LOGFILE
echo "Enter status: $2" >>$LOGFILE
if [ $2 == "master" ]; then
echo "Begin running systemctl restart cmd " >>$LOGFILE
systemctl restart named.service >>$LOGFILE 2>&1
echo "Running reload cmd done ! " >>$LOGFILE
date "+%Y-%m-%d %H:%M:%S" >>$LOGFILE
fi
echo "---------------------------------------" >>$LOGFILE
;;
*)
echo "Usage: sh $0 check ipaddr | notify status"
;;
esac

8、效果检测

最后我们关闭主节点上面的named服务,然后查看日志和从节点的状态确定VIP能否顺利切换,之后再重启主节点上面的named服务,保证服务能够正常运行即可。