CentOS 7上搭建高可用BIND9集群指南

在 CentOS 7 上搭建一个高可用的 BIND9 集群通常涉及以下几种关键技术和策略的组合:主从复制 (Master-Slave Replication)、负载均衡 (Load Balancing) 以及可能的浮动 IP (Floating IP) 或 Anycast。

我们将主要关注主从复制负载均衡的实现,这是构成高可用 DNS 集群的核心。

场景假设:

  • 域名: mycluster.local
  • 主 DNS 服务器 (Master):
    • IP: 192.168.1.10
    • Hostname: dns-master.mycluster.local
  • 从 DNS 服务器 1 (Slave 1):
    • IP: 192.168.1.11
    • Hostname: dns-slave1.mycluster.local
  • 从 DNS 服务器 2 (Slave 2):
    • IP: 192.168.1.12
    • Hostname: dns-slave2.mycluster.local
  • 负载均衡器/虚拟 IP (VIP):
    • IP: 192.168.1.100 (客户端将使用此 IP 作为 DNS 服务器)

核心组件:

  1. BIND9 主从复制:
    • 主服务器 (Master) 维护权威的区域数据文件。
    • 从服务器 (Slaves) 定期从主服务器同步区域数据。
    • 当主服务器上的区域数据更新时,它会通知从服务器进行更新。
  2. 负载均衡器:
    • 将客户端的 DNS 请求分发到后端的多个 BIND 从服务器(或包括主服务器)。
    • 可以使用硬件负载均衡器 (如 F5, Citrix ADC) 或软件负载均衡器 (如 HAProxy, Nginx, LVS)。
    • 对于简单的 DNS 负载均衡,也可以使用 DNS 轮询 (Round Robin DNS),但这不提供故障检测和自动切换。
  3. (可选) Keepalived 实现 VIP 和健康检查:
    • Keepalived 可以管理一个虚拟 IP (VIP),并在主负载均衡器节点故障时将其漂移到备用节点。
    • 它可以对后端 BIND 服务器进行健康检查,如果某个 BIND 服务器故障,则将其从负载均衡池中移除。

步骤一:在所有节点上安装 BIND9

dns-master, dns-slave1, dns-slave2 上执行:

bash 复制代码
sudo yum update -y
sudo yum install -y bind bind-utils

步骤二:配置主 DNS 服务器 (dns-master)

  1. 编辑 /etc/named.conf (options 部分):

    bash 复制代码
    sudo vi /etc/named.conf
    conf 复制代码
    options {
        listen-on port 53 { 127.0.0.1; 192.168.1.10; }; // 监听自己的IP
        listen-on-v6 port 53 { ::1; };
        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";
    
        allow-query     { localhost; 192.168.1.0/24; }; // 允许内网查询
        recursion no;                                   // 作为权威服务器
        allow-recursion { none; };
    
        // 允许从服务器进行区域传送
        allow-transfer { 192.168.1.11; 192.168.1.12; };
    
        dnssec-enable yes;
        dnssec-validation yes; // 或 no,如果纯权威且不解析外部
    
        pid-file "/run/named/named.pid";
        // ... 其他默认选项 ...
    };
    
    logging {
        channel default_debug {
                file "data/named.run";
                severity dynamic;
        };
    };
    
    include "/etc/named.rfc1912.zones";
    include "/etc/named.root.key";
  2. 编辑 /etc/named.rfc1912.zones (定义区域):

    bash 复制代码
    sudo vi /etc/named.rfc1912.zones

    在文件末尾添加:

    conf 复制代码
    zone "mycluster.local" IN {
        type master;
        file "db.mycluster.local"; // 区域数据文件名
        allow-update { none; };
        // 主动通知从服务器有更新
        also-notify { 192.168.1.11; 192.168.1.12; };
    };
    
    // 示例反向区域
    zone "1.168.192.in-addr.arpa" IN {
        type master;
        file "db.192.168.1";
        allow-update { none; };
        also-notify { 192.168.1.11; 192.168.1.12; };
    };
  3. 创建区域文件 (例如 /var/named/db.mycluster.local):

    bash 复制代码
    sudo vi /var/named/db.mycluster.local
    zone 复制代码
    $TTL 86400
    @       IN      SOA     dns-master.mycluster.local. admin.mycluster.local. (
                            2023072101      ; Serial (YYYYMMDDNN)
                            3600            ; Refresh
                            1800            ; Retry
                            604800          ; Expire
                            86400 )         ; Minimum TTL
    ; Name Servers for the zone (these will be the VIP or individual server IPs clients might use)
    ; For HA, clients should point to the VIP. These NS records are for delegation.
    @       IN      NS      dns-vip.mycluster.local. ; 或者直接写 VIP IP 的 PTR 记录对应的主机名
    ; @       IN      NS      dns-master.mycluster.local. ; 也可以列出所有服务器
    ; @       IN      NS      dns-slave1.mycluster.local.
    ; @       IN      NS      dns-slave2.mycluster.local.
    
    ; A Records for Name Servers (actual IPs)
    dns-master      IN      A       192.168.1.10
    dns-slave1      IN      A       192.168.1.11
    dns-slave2      IN      A       192.168.1.12
    dns-vip         IN      A       192.168.1.100 ; VIP
    
    ; Other records
    server1         IN      A       192.168.1.50
    web             IN      CNAME   server1.mycluster.local.

    重要:

    • SOA 记录中的主NS应为 dns-master.mycluster.local.
    • NS 记录应指向客户端实际用于查询的DNS服务器名称。如果使用VIP,则指向VIP对应的主机名。如果客户端可能直接查询各个节点,则列出所有节点。
    • 每次修改区域文件后,务必增加 Serial 号码
  4. 创建反向区域文件 (例如 /var/named/db.192.168.1):

    (内容类似,包含 PTR 记录,SOA 和 NS 记录与正向区域类似)

  5. 设置区域文件权限:

    bash 复制代码
    sudo chown root:named /var/named/db.mycluster.local
    sudo chown root:named /var/named/db.192.168.1
    sudo chmod 640 /var/named/db.mycluster.local
    sudo chmod 640 /var/named/db.192.168.1
  6. 检查配置并启动服务:

    bash 复制代码
    sudo named-checkconf /etc/named.conf
    sudo named-checkzone mycluster.local /var/named/db.mycluster.local
    sudo named-checkzone 1.168.192.in-addr.arpa /var/named/db.192.168.1
    sudo systemctl start named
    sudo systemctl enable named
    sudo firewall-cmd --permanent --add-service=dns
    sudo firewall-cmd --reload

步骤三:配置从 DNS 服务器 (dns-slave1dns-slave2)

dns-slave1dns-slave2 上执行以下操作 (配置相似,只需注意 IP 地址)。

  1. 编辑 /etc/named.conf (options 部分):

    bash 复制代码
    sudo vi /etc/named.conf
    conf 复制代码
    options {
        listen-on port 53 { 127.0.0.1; <slave_server_ip>; }; // 例如 192.168.1.11 for dns-slave1
        listen-on-v6 port 53 { ::1; };
        directory       "/var/named"; // BIND 会将从主服务器同步的区域文件存放在这里 (通常在 slaves/ 子目录)
        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";
    
        allow-query     { localhost; 192.168.1.0/24; };
        recursion no;
        allow-recursion { none; };
    
        // 从服务器不需要 allow-transfer,除非它也是其他从服务器的主
        // allow-transfer { none; };
    
        dnssec-enable yes;
        dnssec-validation yes; // 或 no
    
        pid-file "/run/named/named.pid";
        // ... 其他默认选项 ...
    };
    
    logging {
        channel default_debug {
                file "data/named.run";
                severity dynamic;
        };
        // 建议为从服务器添加 xfer (transfer) 日志
        channel xfer_log {
            file "data/xfer.log" versions 3 size 5m;
            print-time yes;
            severity info;
        };
        category xfer-in { xfer_log; };
        category xfer-out { xfer_log; };
        category notify { xfer_log; };
    };
    
    include "/etc/named.rfc1912.zones";
    include "/etc/named.root.key";
  2. 编辑 /etc/named.rfc1912.zones (定义区域为 slave):

    bash 复制代码
    sudo vi /etc/named.rfc1912.zones

    在文件末尾添加:

    conf 复制代码
    zone "mycluster.local" IN {
        type slave;
        file "slaves/db.mycluster.local"; // BIND 会自动创建此文件
        masters { 192.168.1.10; };      // 指定主服务器的 IP 地址
        // 可选:如果主服务器的 also-notify 可能被防火墙阻止,可以配置 allow-notify
        // allow-notify { 192.168.1.10; };
    };
    
    zone "1.168.192.in-addr.arpa" IN {
        type slave;
        file "slaves/db.192.168.1";
        masters { 192.168.1.10; };
    };

    注意: file 指令指定了从主服务器同步下来的区域数据副本的存储位置。BIND 会自动在 directory (即 /var/named/) 下创建 slaves 子目录(如果不存在)并存储这些文件。

  3. 检查配置并启动服务:

    bash 复制代码
    sudo named-checkconf /etc/named.conf
    sudo systemctl start named
    sudo systemctl enable named
    sudo firewall-cmd --permanent --add-service=dns
    sudo firewall-cmd --reload
  4. 验证区域传送:

    • 在从服务器启动 named 后,稍等片刻。
    • 查看从服务器的日志 (sudo journalctl -u named -f 或配置的 xfer.log),应该能看到区域传送成功的消息,类似:
      zone mycluster.local/IN: transferred serial 2023072101
      transfer of 'mycluster.local/IN' from 192.168.1.10#53: Transfer completed
    • 检查 /var/named/slaves/ 目录下是否生成了对应的区域文件。

步骤四:配置负载均衡 (以 HAProxy 为例)

这里我们使用 HAProxy 作为软件负载均衡器。可以在一台独立的服务器上安装 HAProxy,或者在其中一台 DNS 服务器上安装(但不推荐用于生产环境的关键服务)。

假设 HAProxy 安装在 IP 为 192.168.1.20 的服务器上。

  1. 安装 HAProxy:

    bash 复制代码
    sudo yum install -y haproxy
  2. 配置 HAProxy (/etc/haproxy/haproxy.cfg):

    bash 复制代码
    sudo vi /etc/haproxy/haproxy.cfg

    添加或修改以下内容:

    cfg 复制代码
    global
        log         /dev/log local0
        chroot      /var/lib/haproxy
        pidfile     /var/run/haproxy.pid
        maxconn     4000
        user        haproxy
        group       haproxy
        daemon
        stats socket /var/lib/haproxy/stats
    
    defaults
        mode                    http # 对于DNS,通常用tcp模式,但http模式的健康检查更灵活
        log                     global
        option                  httplog # 如果是tcp模式,用tcplog
        option                  dontlognull
        option                  http-server-close # 如果是tcp模式,用clitcpka 和 srvtcpka
        # option                forwardfor except 127.0.0.0/8 # 如果需要传递客户端IP
        option                  redispatch
        retries                 3
        timeout http-request    10s
        timeout queue           1m
        timeout connect         10s
        timeout client          1m
        timeout server          1m
        timeout http-keep-alive 10s
        timeout check           10s
        maxconn                 3000
    
    # DNS UDP Frontend and Backend
    frontend dns_udp_frontend
        bind 192.168.1.100:53 proto udp # VIP 和 UDP 端口
        mode udp
        default_backend dns_udp_backend
    
    backend dns_udp_backend
        mode udp
        balance roundrobin # 或 leastconn
        # 健康检查对UDP比较困难,通常依赖TCP的健康检查或外部脚本
        # HAProxy 对 UDP 的健康检查支持有限,通常依赖于后端服务器是否响应
        server dns_master 192.168.1.10:53 check # 'check' 对UDP可能无效或行为不同
        server dns_slave1 192.168.1.11:53 check
        server dns_slave2 192.168.1.12:53 check
    
    # DNS TCP Frontend and Backend (DNS也使用TCP,例如区域传送或大型响应)
    frontend dns_tcp_frontend
        bind 192.168.1.100:53 proto tcp # VIP 和 TCP 端口
        mode tcp
        default_backend dns_tcp_backend
    
    backend dns_tcp_backend
        mode tcp
        balance roundrobin
        option tcp-check # 使用TCP健康检查
        # TCP健康检查:尝试连接到服务器的53端口
        # 可以更复杂,例如发送一个简单的DNS查询并期望特定响应
        # default-server check port 53 inter 2s fall 3 rise 2
        server dns_master 192.168.1.10:53 check port 53 inter 2s fall 3 rise 2
        server dns_slave1 192.168.1.11:53 check port 53 inter 2s fall 3 rise 2
        server dns_slave2 192.168.1.12:53 check port 53 inter 2s fall 3 rise 2
    
    # HAProxy Stats Page (可选)
    listen stats
        bind *:8404
        mode http
        stats enable
        stats uri /stats
        stats realm Haproxy\ Statistics
        stats auth admin:password # 设置用户名和密码

    关于 HAProxy UDP 健康检查的说明:

    HAProxy 对 UDP 服务的健康检查能力有限。check 关键字在 mode udp 下的行为可能不如 TCP。更可靠的 UDP 健康检查通常需要:

    • 依赖于 TCP 端口的健康检查(如果服务同时监听 TCP)。
    • 使用外部脚本通过 option external-check 执行自定义的 UDP 健康检查。
    • 对于 DNS,一个简单的 TCP 连接检查到端口 53 通常可以作为指示。
  3. 允许 HAProxy 绑定到非本地 IP (VIP):

    bash 复制代码
    sudo sysctl -w net.ipv4.ip_nonlocal_bind=1
    # 持久化
    echo "net.ipv4.ip_nonlocal_bind=1" | sudo tee /etc/sysctl.d/90-haproxy.conf
  4. 启动 HAProxy 并设置开机自启:

    bash 复制代码
    sudo systemctl start haproxy
    sudo systemctl enable haproxy
    sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="0.0.0.0/0" port port="53" protocol="udp" accept'
    sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="0.0.0.0/0" port port="53" protocol="tcp" accept'
    sudo firewall-cmd --permanent --add-port=8404/tcp # 如果启用了stats页面
    sudo firewall-cmd --reload

步骤五:配置客户端

将客户端的 DNS 服务器设置为负载均衡器的 VIP:192.168.1.100


步骤六:(可选) 使用 Keepalived 实现 VIP 高可用和负载均衡器冗余

如果 HAProxy 本身成为单点故障,可以使用 Keepalived 来管理 VIP 并在多个 HAProxy 节点之间进行故障转移。

假设你有两台 HAProxy 服务器 (haproxy1: 192.168.1.20, haproxy2: 192.168.1.21)。

  1. 在两台 HAProxy 服务器上安装 Keepalived:

    bash 复制代码
    sudo yum install -y keepalived
  2. 配置 Keepalived (/etc/keepalived/keepalived.conf):

    • 在 haproxy1 (MASTER):

      conf 复制代码
      ! Configuration File for keepalived
      
      global_defs {
         router_id HAPROXY_DNS_01
      }
      
      # 脚本用于检查HAProxy进程是否在运行
      vrrp_script chk_haproxy {
         script "killall -0 haproxy"   # 检查haproxy进程是否存在
         interval 2                    # 每2秒检查一次
         weight 2                      # 如果成功,权重加2
      }
      
      vrrp_instance VI_DNS {
          state MASTER
          interface eth0                # 根据你的网卡名称修改
          virtual_router_id 51          # 必须在所有Keepalived节点上相同
          priority 101                  # MASTER 优先级更高
          advert_int 1
          authentication {
              auth_type PASS
              auth_pass yoursecret      # 密码,所有节点相同
          }
          virtual_ipaddress {
              192.168.1.100/24 dev eth0 label eth0:vip1 # VIP
          }
          track_script {
             chk_haproxy
          }
      }
    • 在 haproxy2 (BACKUP):

      conf 复制代码
      ! Configuration File for keepalived
      
      global_defs {
         router_id HAPROXY_DNS_02
      }
      
      vrrp_script chk_haproxy {
         script "killall -0 haproxy"
         interval 2
         weight 2
      }
      
      vrrp_instance VI_DNS {
          state BACKUP
          interface eth0
          virtual_router_id 51
          priority 100                  # BACKUP 优先级较低
          advert_int 1
          authentication {
              auth_type PASS
              auth_pass yoursecret
          }
          virtual_ipaddress {
              192.168.1.100/24 dev eth0 label eth0:vip1
          }
          track_script {
             chk_haproxy
          }
      }
  3. 启动 Keepalived 并设置开机自启 (在两台 HAProxy 服务器上):

    bash 复制代码
    sudo systemctl start keepalived
    sudo systemctl enable keepalived
    sudo firewall-cmd --permanent --add-protocol=vrrp # 允许VRRP协议
    sudo firewall-cmd --reload

    现在,192.168.1.100 这个 VIP 会由 Keepalived 管理。如果 haproxy1 上的 HAProxy 进程挂掉或服务器宕机,VIP 会自动漂移到 haproxy2


测试高可用性:

  1. 主从同步测试:

    • dns-master 上修改区域文件 (例如,添加一条 A 记录),并增加 SOA 序列号
    • 执行 sudo rndc reload mycluster.local (或 sudo systemctl reload named)。
    • 在从服务器上查看日志,确认区域已成功传送新的序列号。
    • 在从服务器上使用 dig @localhost new_record.mycluster.local 查询新记录。
  2. 负载均衡和故障转移测试 (HAProxy + BIND 节点):

    • 从客户端 dig @192.168.1.100 existing_record.mycluster.local,多次查询,观察 HAProxy 是否将请求分发到不同的后端 BIND 服务器 (可以在 BIND 服务器上开启查询日志来确认)。
    • 停止其中一个从 BIND 服务器 (sudo systemctl stop named on dns-slave1)。
    • 再次从客户端查询,请求应该仍然成功,并由其他健康的 BIND 服务器响应。HAProxy 的健康检查应该会将故障节点标记为 down。
    • 恢复 dns-slave1 上的 named 服务,它应该会自动重新加入到负载均衡池中。
  3. VIP 故障转移测试 (Keepalived + HAProxy 节点):

    • 在当前持有 VIP 的 HAProxy 服务器 (MASTER Keepalived) 上停止 keepalived 服务或 haproxy 服务 (如果 track_script 配置正确)。
    • 观察 VIP (192.168.1.100) 是否成功漂移到另一台 HAProxy 服务器 (BACKUP Keepalived)。可以使用 ip addr show 查看。
    • 从客户端继续查询 dig @192.168.1.100 existing_record.mycluster.local,应该仍然成功。

注意事项和改进:

  • 安全性:
    • 严格配置防火墙,只允许必要的端口和源 IP。
    • 保护 rndc.key 文件。
    • 考虑使用 TSIG (Transaction Signatures) 来保护区域传送。
    • 定期更新 BIND 和其他系统组件。
  • 日志和监控:
    • 配置详细的日志记录,并使用集中式日志管理系统。
    • 使用监控系统 (Nagios, Zabbix, Prometheus) 监控 BIND 服务、HAProxy、Keepalived 的状态以及 DNS 解析的健康状况。
  • DNSSEC: 如果你的区域需要 DNSSEC 签名,确保主服务器正确签名区域,从服务器能够处理已签名的区域。
  • 扩展性: 可以根据需要增加更多的从服务器和 HAProxy 节点。
  • Anycast: 对于更大规模或地理分布的 DNS 集群,可以考虑使用 Anycast IP 地址,这需要网络设备的支持。
  • 配置管理: 使用 Ansible, Puppet, Chef 等工具自动化部署和管理配置。

这是一个相对完整的搭建高可用 BIND9 集群的方案。根据你的具体需求和环境,可能需要进行调整。

相关推荐
Nightwish53 分钟前
Linux随记(二十一)
linux·运维·服务器
獭.獭.2 小时前
Linux -- 文件【上】
linux·运维·服务器·进程·pcb
搬码临时工4 小时前
使用FRP搭建内网穿透工具,自己公网服务器独享内外网端口转发
运维·服务器
ん贤4 小时前
GMP模型
运维·服务器·后端·golang
abbgogo4 小时前
子域名收集和c段查询
运维·服务器·信息收集
杜子不疼.5 小时前
Linux的生态与软件安装
linux·运维·服务器
哈基咩5 小时前
Go语言unsafe包深度解析
服务器·开发语言·后端·golang
wanhengidc5 小时前
服务器被网络攻击后该如何进行处理?
运维·服务器·网络
MickeyCV5 小时前
MySQL数据库本地迁移到云端完整教程
服务器·数据库·mysql·oracle
什么蜜桃绵绵冰6 小时前
linux易错题
linux·运维·服务器