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

发布于:2025-05-21 ⋅ 阅读:(21) ⋅ 点赞:(0)

在 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 上执行:

sudo yum update -y
sudo yum install -y bind bind-utils

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

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

    sudo vi /etc/named.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 (定义区域):

    sudo vi /etc/named.rfc1912.zones
    

    在文件末尾添加:

    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):

    sudo vi /var/named/db.mycluster.local
    
    $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. 设置区域文件权限:

    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. 检查配置并启动服务:

    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 部分):

    sudo vi /etc/named.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):

    sudo vi /etc/named.rfc1912.zones
    

    在文件末尾添加:

    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. 检查配置并启动服务:

    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:

    sudo yum install -y haproxy
    
  2. 配置 HAProxy (/etc/haproxy/haproxy.cfg):

    sudo vi /etc/haproxy/haproxy.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):

    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 并设置开机自启:

    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:

    sudo yum install -y keepalived
    
  2. 配置 Keepalived (/etc/keepalived/keepalived.conf):

    • 在 haproxy1 (MASTER):

      ! 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):

      ! 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 服务器上):

    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 集群的方案。根据你的具体需求和环境,可能需要进行调整。


网站公告

今日签到

点亮在社区的每一天
去签到