根据集群搭建PowerDNS生产环境。

dns的工作过程(DNS从入门到放弃系列)(1)

架构图

安装环境

服务器时区和时间统一:

# Ubuntu 22.04.1 LTS同步网络时间和更改时区 root@dnsdist01:/etc/powerdns# date Wed Dec 14 02:28:44 AM UTC 2022 root@dnsdist01:/etc/powerdns# timedatectl root@dnsdist01:/etc/powerdns# timedatectl list-timezones root@dnsdist01:/etc/powerdns# timedatectl set-timezone Asia/Shanghai root@dnsdist01:/etc/powerdns# apt install ntpdate root@dnsdist01:/etc/powerdns# ntpdate -u ntp.aliyun.com

负载均衡器和递归服务器配置:

# 192.168.10.100和192.168.10.110中部署dnsdist和pdns-recursor (负载均衡器和递归服务器) root@dnsdist01:~# hostnamectl --static hostname "dnsdist01" # 192.168.10.100 root@dnsdist02:~# hostnamectl --static hostname "dnsdist02" # 192.168.10.110 # 安装dnsdist cat >/etc/apt/sources.list.d/pdns.list<<EOF deb [arch=amd64] http://repo.powerdns.com/ubuntu jammy-dnsdist-17 main EOF cat >/etc/apt/preferences.d/pdns<<EOF Package: pdns-* Pin: origin repo.powerdns.com Pin-Priority: 600 EOF curl https://repo.powerdns.com/FD380FBB-pub.asc | sudo apt-key add - && sudo apt-get update && sudo apt-get install dnsdist systemctl status dnsdist.service systemctl stop dnsdist.service systemctl start dnsdist.service # 安装pdns-recursor cat >/etc/apt/sources.list.d/pdns.list<<EOF deb [arch=amd64] http://repo.powerdns.com/ubuntu jammy-rec-47 main EOF cat >/etc/apt/preferences.d/pdns<<EOF Package: pdns-* Pin: origin repo.powerdns.com Pin-Priority: 600 EOF curl https://repo.powerdns.com/FD380FBB-pub.asc | sudo apt-key add - && sudo apt-get update && sudo apt-get install pdns-recursor systemctl status pdns-recursor.service systemctl stop pdns-recursor.service systemctl start pdns-recursor.service

由于默认启动端口都是53,故pdns-recursor安装好后并没有启动成功,这里由于dnsdist和pdns-recursor部署在同一台机器中,故pdns-recursor的服务端口需要进行更改,在这里我更改为553端口。在下面的配置文件中说明。

说明Ubuntu 22.04.1 LTS网络问题:

# 如果系统53端口被systemd-resolved占用 systemctl stop systemd-resolved.service systemctl disable systemd-resolved.service # 修改/etc/resolv.conf文件 /etc/resolv.conf nameserver 192.168.10.254 # 可写网关IP或公共DNS options edns0 trust-ad search . # 网卡信息 network: ethernets: ens33: addresses: - 192.168.10.100/24 nameservers: addresses: - 192.168.10.254 search: [] routes: - to: default via: 192.168.10.254 version: 2

配置环境

服务器192.168.10.100的配置如下:

# dnsdist配置文件路径 /etc/dnsdist/dnsdist.conf -- 关闭安全更新 默认setSecurityPollSuffix("secpoll.powerdns.com") 安全漏洞会提醒 setSecurityPollSuffix("") -- 设置本地监听地址为192.168.10.100的53端口 默认127.0.0.1 如果要启用IPv6需要设置IPv6的地址和端口 setLocal('192.168.10.100:53') -- 允许列表内的IP来进行解析 setacl({'192.168.0.0/16', '172.18.0.0/16'}) -- dnsdist是一个负载均衡器 它本身不做任何 DNS 解析或服务 因此它需要下游服务器 设置QPS -- 新增服务器192.168.10.100:553,qps限制为10 newServer({address="192.168.10.100:553", qps=10}) -- 新增服务器192.168.10.110:553,qps限制为10 newServer({address="192.168.10.110:553", qps=10}) -- 新增服务器114.114.114.114,并使用本机的192.168.10.100与其进行通信 -- newServer({address="114.114.114.114", source="192.168.10.100"}) -- 设置服务负载方式为QPS查询 https://dnsdist.org/guides/serverselection.html setServerPolicy(firstAvailable) -- 开启内置Web服务和API Prometheus监控指标需要调用 Webserver("127.0.0.1:8083") -- 设置Web服务安全 只允许指定的IP访问 如192.168.10.0/24这个网段访问 不允许网段内的某个地址访问 setWebserverConfig({password="supersecretpassword", apiKey="supersecretAPIkey", acl="192.168.10.0/24, !192.168.10.1"}) -- supersecretpassword和supersecretAPIkey 自己设定安全的字符串 123这种就不建议了 可以使用密码生成器生成复杂的密码 -- DoH默认不启用 -- addDOHLocal('127.0.0.1:8053', '/etc/ssl/certs/example.com.pem', '/etc/ssl/private/example.com.key', "/", {customResponseHeaders={["link"]="<https://example.com/policy.html> rel=\\"service-meta\\"; type=\\"text/html\\""}}) -- DoT默认不启用 -- addTLSLocal('127.0.0.1:8053', {'/etc/ssl/certs/example.com.rsa.pem', '/etc/ssl/certs/example.com.ecdsa.pem'}, {'/etc/ssl/private/example.com.rsa.key', '/etc/ssl/private/example.com.ecdsa.key'})

上面的配置,192.168.10.100和192.168.10.110都默认该配置,修改下setLocal的IP地址即可。

递归服务器配置:

# 访问白名单 如果设置 则只允许这些逗号分隔的网络掩码递归 默认只允许访问RFC 1918私有 IP 地址 allow-from=127.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 169.254.0.0/16, 192.168.0.0/16, 172.16.0.0/12 # 可以把CIDR写入到文件中 文件中必须每行一个CIDR 不允许逗号分隔 不写绝对路径 是下面include-dir指定conf配置文件路径 # allow-from-file=primit-acl.conf # 目录路径 默认/etc/powerdns 如果编译安装的就是指定的SYSCONFDIR变量路径 config-dir=/etc/powerdns # 根提示文件 默认/usr/share/dns/root.hints 例如将所有查询转发给另外一台递归器时 可以关闭跟提示 hint-file=/usr/share/dns/root.hints # 其他配置文件的目录 include-dir=/etc/powerdns/recursor.d # 服务监听地址 默认127.0.0.1 IPv6的地址加端口需要方括号括起来IPv6地址 local-address=192.168.10.100 # 监听端口 默认53 local-port=553 # 转发域 如需要把内部域名转发到权威服务器中解析 格式 域名=IP:[端口] 可指定端口 不加冒号和端口就默认转发指定IP的53端口 # forward-zones=example.org=203.0.113.210:5300;127.0.0.1, powerdns.com=127.0.0.1;198.51.100.10:530;[2001:DB8::1:3]:5300 forward-zones=example.org=192.168.10.130:53;192.168.10.140:53 # 转发域文件 每行只能写一个域名 不可以逗号分隔 # 当转发域域名比较多时 forward-zones单行写就不够方便 可读性差 可直接写入到单独的文件中 # forward-zones-file=primit-forward-zone.conf # 优先递归查询权威服务器 如果查询不到 允许递归到公共DNS查询 forward-zones-recurse=.=223.5.5.5;114.114.114 # lua脚本高级配置支持 lua-config-file=/etc/powerdns/recursor.lua # 公共域名后缀列表 public-suffix-list-file=/usr/share/publicsuffix/public_suffix_list.dat # 禁止记录查询的记录和答案 quiet=yes # 禁用安全更新 默认值security-poll-suffix=secpoll.powerdns.com 不允许安全更新 security-poll-suffix= # 版本回复禁用 安全 version-string="not currently available" # Web服务和API启用 默认未启用 webserver=yes # 默认172.0.0.1 webserver-address=192.168.10.100 # 默认8082 webserver-port=8082 # Web访问密码 webserver-password=pdnsrecursorpassword # api-key api-key=changeme # 日志 文件格式化显示 logging-facility=0 # 默认等级 6 信息 loglevel=6 # 默认本地缓存最大时间 单位秒 max-negative-ttl=3600

原始文件进行备份:

mv /etc/powerdns/recursor.conf /etc/powerdns/recursor.conf.bak vim /etc/powerdns/recursor.conf # 复制上面的配置信息到该文件中

配置做好后,重启服务:

# 重启递归服务器 systemctl restart pdns-recursor.service systemctl status pdns-recursor.service # 重启负载均衡器 systemctl restart dnsdist.service systemctl status dnsdist.service

最终执行netstat命令查询进程信息:

dns的工作过程(DNS从入门到放弃系列)(2)

服务监听

或者ss命令查看:

dns的工作过程(DNS从入门到放弃系列)(3)

服务器192.168.10.110也是同上一样的配置,示例如下:

# dnsdist配置文件路径 /etc/dnsdist/dnsdist.conf -- 关闭安全更新 默认setSecurityPollSuffix("secpoll.powerdns.com") 安全漏洞会提醒 setSecurityPollSuffix("") -- 设置本地监听地址为192.168.10.110的53端口 默认127.0.0.1 setLocal('192.168.10.110:53') -- 设置访问控制列表 https://dnsdist.org/advanced/acl.html 不设置就允许所有来源IP访问 setACL({'192.168.0.0/16', '172.18.0.0/16'}) -- dnsdist是一个负载均衡器 它本身不做任何 DNS 解析或服务 因此它需要下游服务器 设置QPS -- https://dnsdist.org/guides/serverselection.html -- newServer({address="114.114.114.114", qps=10}) -- 新增服务器192.168.10.110:553 qps限制为10 newServer({address="192.168.10.110:553", qps=10}) -- 新增服务器192.168.10.100:553 qps限制为10 newServer({address="192.168.10.100:553", qps=10}) -- 新增服务器114.114.114.114 并使用本机的192.168.10.100与其进行通信 -- newServer({address="114.114.114.114", source="192.168.10.100"}) -- 开启内置Web服务和API webserver("127.0.0.1:8083") -- 设置Web服务安全 只允许指定的IP访问 如192.168.10.0/24这个网段访问 不允许网段内的某个地址访问 setWebserverConfig({password="supersecretpassword", apiKey="supersecretAPIkey", acl="192.168.10.0/24, !192.168.10.1"})

dnsdist服务配置文件如上,下面配置递归服务器配置:

# 访问白名单 如果设置 则只允许这些逗号分隔的网络掩码递归 默认只允许访问RFC 1918私有 IP 地址 allow-from=127.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 169.254.0.0/16, 192.168.0.0/16, 172.16.0.0/12 # 可以把CIDR写入到文件中 文件中必须每行一个CIDR 不允许逗号分隔 不写绝对路径 是下面include-dir指定conf配置文件路径 # allow-from-file=primit-acl.conf # 目录路径 默认/etc/powerdns 如果编译安装的就是指定的SYSCONFDIR变量路径 config-dir=/etc/powerdns # 根提示文件 默认/usr/share/dns/root.hints 例如将所有查询转发给另外一台递归器时 可以关闭跟提示 hint-file=/usr/share/dns/root.hints # 其他配置文件的目录 include-dir=/etc/powerdns/recursor.d # 服务监听地址 默认127.0.0.1 IPv6的地址加端口需要方括号括起来IPv6地址 local-address=192.168.10.110 # 监听端口 默认53 local-port=553 # 转发域 如需要把内部域名转发到权威服务器中解析 格式 域名=IP:[端口] 可指定端口 不加冒号和端口就默认转发指定IP的53端口 # forward-zones=example.org=203.0.113.210:5300;127.0.0.1, powerdns.com=127.0.0.1;198.51.100.10:530;[2001:DB8::1:3]:5300 forward-zones=example.org=192.168.10.130:53;192.168.10.140:53 # 转发域文件 每行只能写一个域名 不可以逗号分隔 # forward-zones-file=primit-forward-zone.conf # 优先递归查询权威服务器 如果查询不到 允许递归到公共DNS查询 forward-zones-recurse=.=223.5.5.5;114.114.114 # lua脚本高级配置支持 lua-config-file=/etc/powerdns/recursor.lua # 公共域名后缀列表 public-suffix-list-file=/usr/share/publicsuffix/public_suffix_list.dat # 禁止记录查询的记录和答案 quiet=yes # 禁用安全更新 默认值security-poll-suffix=secpoll.powerdns.com 不允许安全更新 security-poll-suffix= # 版本回复禁用 安全 version-string="not currently available" # Web服务和API启用 默认未启用 webserver=yes # 默认172.0.0.1 webserver-address=192.168.10.110 # 默认8082 webserver-port=8082 # Web访问密码 webserver-password=pdnsrecursorpassword # api-key api-key=changeme # 日志 文件格式化显示 logging-facility=0 # 默认等级 6 信息 loglevel=6 # 默认本地缓存最大时间 单位秒 max-negative-ttl=3600

之前一个递归服务器配置好后,dnsdist下游服务器只有一个UP,当两个递归服务器都配置好后,重启dnsdist服务器后,dnsdist的两个下游服务器都UP

dns的工作过程(DNS从入门到放弃系列)(4)

dns的工作过程(DNS从入门到放弃系列)(5)

下游服务器都显示UP状态。

权威服务器配置和安装:

数据库主从

数据库一主一丛,利用keepalived进行故障切换:

两台机器 A 和 B,A 为主库,负责读写,B 为从库,负责读数据。

如果 A 库发生故障,B 库成为主库负责读写,修复故障后,A 成为从库,主库 B 同步数据到从库 A。

dns的工作过程(DNS从入门到放弃系列)(6)

上图是从楼仔的原创文章截取过来,可直接到楼仔知乎查看。

主库搭建和配置:192.168.10.120上搭建主库同时搭建主PowerDNS Authoritative Server,正式环境建议使用RDS或者单独机器搭建数据库。

# apt-get安装MySQL 5.7.40 root@pdns01:/home/scops# apt update # 下载apt仓库的安装包,Ubuntu的安装包是.deb文件 wget https://dev.MySQL.com/get/mysql-apt-config_0.8.12-1_all.deb

弹出框中选择:ubuntu bionic (Ubuntu18.04系统的代号是bionic,选择18.04的版本库用来安装)

dns的工作过程(DNS从入门到放弃系列)(7)

MySQL 5.7.40

弹出框中选择:MySQL Server & Cluster

弹出框中选择:mysql-5.7

dns的工作过程(DNS从入门到放弃系列)(8)

mysql-5.7选择

dns的工作过程(DNS从入门到放弃系列)(9)

当前版本选择MySQL 5.7

如上图,确定当前版本是选择mysql-5.7,点击OK

# 首先导入仓库的密钥信息 apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 467B942D3A79BD29 # 更新仓库信息 apt update # 检查是否成功配置MySQL5.7的仓库 apt-cache policy mysql-server

dns的工作过程(DNS从入门到放弃系列)(10)

找到MySQL 5.7

# 使用apt安装mysql客户端和mysql服务端 apt install -f -y mysql-client=5.7* mysql-community-server=5.7*

dns的工作过程(DNS从入门到放弃系列)(11)

输入密码

​上图弹出框中输入root密码并选择ok,密码任意,这里设置中以hua321代替。

MySQL 5.7安装好后,MySQL启动默认配置文件路径为:/etc/mysql/my.cnf,说明下/etc/mysql目录下配置文件信息:

dns的工作过程(DNS从入门到放弃系列)(12)

配置文件目录

上图中,my.cnf.fallback 是备份的回滚文件,其他都是有作用的。

my.cnf 是符号链接,指向 /etc/alternatives/my.cnf,但是这个文件也是个符号链接,文件指向 /etc/mysql/mysql.cnf,故最终文件是mysql.cnf,如果my.cnf做修改mysql.cnf是同步的。

my.cnf里面没有具体参数,而是包含两个文件夹,并把不同模块配置分文件方式放在不同文件夹中:

!includedir /etc/mysql/conf.d/ !includedir /etc/mysql/mysql.conf.d/ # 所以下面我们主要需要修改/etc/mysql/mysql.conf.d/mysqld.cnf文件,这个文件中主要配置服务器参数配置

并且自动新建了systemd管理服务:mysql.service

# MySQL 5.7的状态和启停守护进程管理工具 systemctl status mysql.service systemctl stop mysql.service systemctl start mysql.service systemctl restart mysql.service

主节点启动配置文件配置:

# 登录主节点数据库 root@pdns01:/etc/mysql# mysql -uroot -p Enter password: # 输入上面的root密码 # 在主库上 设置一个复制使用的账户 并授予replication slave这里创建一个复制用户dnstosyn允许从服务器IP 192.168.10.130的主机进行连接 mysql> grant replication slave,replication client on *.* to 'dnstosyn'@'192.168.10.130' identified by 'powerdns666'; mysql> FLUSH PRIVILEGES;

主节点数据库配置文件参数修改:

[mysqld] # 进程文件路径 pid-file = /var/run/mysqld/mysqld.pid # 套接字文件路径 socket = /var/run/mysqld/mysqld.sock # 数据目录 datadir = /var/lib/mysql # 错误日志路径 log-error = /var/log/mysql/error.log # 默认只接受来自本地主机的连接 # bind-address = 127.0.0.1 # 禁用符号连接 为了安全 symbolic-links = 0 # [必须]配置唯一的server-id,不设置MySQL5.7以上会报错 这里以IP地址主机位标识 不重复即可 server-id = 120 # mysql会根据这个配置自动设置log_bin为on状态,即开启binlog 指定binlog的存储位置,日志格式为二进制 log_bin=/var/log/mysql/master-bin # 二进制日志记录格式,并且可以是 STATEMENT,ROW 或 MIXED 三选一 binlog_format=row # 需要同步的二进制数据库名 (有多个的话,配置多个binlog-do-db) binlog-do-db = powerdns # 默认情况下备份是主库的全部操作都会备份到从库,实际可能需要忽略某些库,可以在主库中增加如下配置: # 不同步哪些数据库(多个写多行) # binlog-ignore-db = mysql # binlog-ignore-db = information_schema # binlog-ignore-db = performance_schema # binlog-ignore-db = sys # 自动清理 7 天前的log文件,可根据需要修改 expire-logs-days=7 # 如果是 1 ,则 mysqld 仅使用 IPNumbers;在这种情况下,授权 table 中的所有Host列值都必须是 IP 地址 # skip_name_resolve=1 # 并发连接数 默认100 一般小于1000即可 默认151 max_connections=1000 # 更改字符集 init_connect='SET collation_connection = utf8_unicode_ci' init_connect='SET NAMES utf8' character-set-server = utf8 collation-server = utf8_unicode_ci skip-character-set-client-handshake

验证主库信息:

mysql> show master status; mysql> reset master; mysql> show processlist; mysql> flush logs;

从节点数据库配置:

[mysqld] pid-file = /var/run/mysqld/mysqld.pid socket = /var/run/mysqld/mysqld.sock datadir = /var/lib/mysql log-error = /var/log/mysql/error.log # By default we only accept connections from localhost # bind-address = 127.0.0.1 # Disabling symbolic-links is recommended to prevent assorted security risks symbolic-links=0 # 必须 不设置MySQL5.7以上会报错 这里以IP地址主机位标识 不重复即可 server-id=130 # mysql会根据这个配置自动设置log_bin为on状态,即开启binlog 指定binlog的存储位置,日志格式为二进制 relay_log=/var/log/mysql/mysql-relay-bin # 设置只读权限 read_only=on # 需要同步的数据库名(多数据库使用逗号,隔开) replicate-do-db=powerdns # 自动清理 7 天前的log文件,可根据需要修改 expire-logs-days=7 #设定需要复制的表 #replicate-do-table=table_name #设定需要忽略的复制表 #replicate-ignore-table=table_name # 如果是 1 ,则 mysqld 仅使用 IPNumbers;在这种情况下,授权 table 中的所有Host列值都必须是 IP 地址 # skip_name_resolve=1 # 并发连接数 默认100 一般小于1000即可 默认151 max_connections=1000

检查从节点数据库:

# 要设置从库与主库进行通信复制 使用必要的连接信息配置从库 在从库上执行以下代码 CHANGE MASTER TO MASTER_HOST='192.168.10.120',MASTER_PORT=3306,MASTER_USER='dnstosyn',MASTER_PASSWORD='powerdns666',MASTER_LOG_FILE='master-bin.000003',MASTER_LOG_POS=306; # 从节点数据库启动slave线程 mysql> start slave; mysql> show slave status; mysql> show processlist;

dns的工作过程(DNS从入门到放弃系列)(13)

设置从节点复制账户

​如上图所示,如果没有设置,打开从节点是没有用的。

查看从库服务器状态:mysql> show slave status\G;

需要保证Slave_SQL_Running和Slave_IO_Running是Yes状态,主从复制才正常。

dns的工作过程(DNS从入门到放弃系列)(14)

# 查看主库服务器的运行状态 show master status; # 查看从库服务器主机列表 show slave hosts; # 获取binlog文件列表 show binary logs; # 只查看第一个binlog文件的内容 show binlog events; # 查看指定binlog文件的内容 show binlog events in 'mysql-bin.000001'; # 启动从库复制线程 start slave; # 停止从库复制线程 stop slave; # 重置从库复制线程 reset slave;

Slave_SQL_Running配置问题:通过使用命令show slave status\G; 发现,Slave_SQL_Running的配置项为NO,需要修改为YES。

mysql> stop slave; Query OK, 0 rows affected (0.00 sec) mysql> set GLOBAL SQL_SLAVE_SKIP_COUNTER=1; Query OK, 0 rows affected (0.00 sec) mysql> start slave; Query OK, 0 rows affected (0.00 sec)

最后检查主从通信的复制状态:

Slave_IO_State # 从站的当前状态 Slave_IO_Running: Yes # 读取主程序二进制日志的I/O线程是否正在运行 Slave_SQL_Running: Yes # 执行读取主服务器中二进制日志事件的SQL线程是否正在运行,与I/O线程一样 Seconds_Behind_Master # 是否为0,0就是已经同步了

在主库中增加powerdns的默认表单结构:PowerDNS Authoritative Nameserver 4.7版本默认模板

# 创建数据库powerdns mysql> CREATE DATABASE powerdns CHARACTER SET utf8 COLLATE utf8_general_ci; # 切换到powerdns数据库 mysql> use powerdns; # SQL语句创建表结构 CREATE TABLE domains ( id INT AUTO_INCREMENT, name VARCHAR(255) NOT NULL, master VARCHAR(128) DEFAULT NULL, last_check INT DEFAULT NULL, type VARCHAR(8) NOT NULL, notified_serial INT UNSIGNED DEFAULT NULL, account VARCHAR(40) CHARACTER SET 'utf8' DEFAULT NULL, options VARCHAR(64000) DEFAULT NULL, catalog VARCHAR(255) DEFAULT NULL, PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE UNIQUE INDEX name_index ON domains(name); CREATE INDEX catalog_idx ON domains(catalog); CREATE TABLE records ( id BIGINT AUTO_INCREMENT, domain_id INT DEFAULT NULL, name VARCHAR(255) DEFAULT NULL, type VARCHAR(10) DEFAULT NULL, content VARCHAR(64000) DEFAULT NULL, ttl INT DEFAULT NULL, prio INT DEFAULT NULL, disabled TINYINT(1) DEFAULT 0, ordername VARCHAR(255) BINARY DEFAULT NULL, auth TINYINT(1) DEFAULT 1, PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE INDEX nametype_index ON records(name,type); CREATE INDEX domain_id ON records(domain_id); CREATE INDEX ordername ON records (ordername); CREATE TABLE supermasters ( ip VARCHAR(64) NOT NULL, nameserver VARCHAR(255) NOT NULL, account VARCHAR(40) CHARACTER SET 'utf8' NOT NULL, PRIMARY KEY (ip, nameserver) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE TABLE comments ( id INT AUTO_INCREMENT, domain_id INT NOT NULL, name VARCHAR(255) NOT NULL, type VARCHAR(10) NOT NULL, modified_at INT NOT NULL, account VARCHAR(40) CHARACTER SET 'utf8' DEFAULT NULL, comment TEXT CHARACTER SET 'utf8' NOT NULL, PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE INDEX comments_name_type_idx ON comments (name, type); CREATE INDEX comments_order_idx ON comments (domain_id, modified_at); CREATE TABLE domainmetadata ( id INT AUTO_INCREMENT, domain_id INT NOT NULL, kind VARCHAR(32), content TEXT, PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE INDEX domainmetadata_idx ON domainmetadata (domain_id, kind); CREATE TABLE cryptokeys ( id INT AUTO_INCREMENT, domain_id INT NOT NULL, flags INT NOT NULL, active BOOL, published BOOL DEFAULT 1, content TEXT, PRIMARY KEY(id) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE INDEX domainidindex ON cryptokeys(domain_id); CREATE TABLE tsigkeys ( id INT AUTO_INCREMENT, name VARCHAR(255), algorithm VARCHAR(50), secret VARCHAR(255), PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);

查看主库表:

dns的工作过程(DNS从入门到放弃系列)(15)

powerdns表结构

查看从库是否同步该表结构,检查发现表结构一致,从这代表主从复制搭建完成,特别记住这里实现的是单向复制,也就是主库的数据同步到从库。如果需要实现双向复制,自己自行了解,在Local DNS场景不建议使用。

keepalived切换

# Ubuntu 22.04.1 LTS安装Keepalived 也在192.168.10.120和192.168.10.130上安装 apt-cache madison keepalived apt install keepalived # 配置文件 cp /usr/share/doc/keepalived/samples/keepalived.conf.sample /etc/keepalived/keepalived.conf # 主 192.168.10.120 ! Configuration File for keepalived global_defs { router_id MySQL_HA script_user root root } vrrp_script chk_mysql_port { script "/etc/keepalived/chk_mysql.sh" interval 2 weight -5 fall 2 rise 1 } vrrp_instance VI_1 { state BACKUP interface ens33 virtual_router_id 50 nopreempt priority 101 advert_int 1 authentication { auth_type PASS auth_pass hua.com } virtual_ipaddress { 192.168.10.10/24 } track_script { chk_mysql_port } } # 备 192.168.10.130 ! Configuration File for keepalived global_defs { router_id MySQL_HA script_user root root } vrrp_script chk_mysql_port { script "/etc/keepalived/chk_mysql.sh" interval 2 weight -5 fall 2 rise 1 } vrrp_instance VI_1 { state BACKUP interface ens33 virtual_router_id 50 priority 100 advert_int 1 authentication { auth_type PASS auth_pass hua.com } virtual_ipaddress { 192.168.10.10/24 } track_script { chk_mysql_port } } # /etc/keepalived/chk_mysql.sh 脚本 #!/bin/bash counter=$(netstat -na | grep "LISTEN" | grep "3306" | wc -l) if [ "${counter}" -eq 0 ]; then /etc/init.d/keepalived stop fi

重启 keepalived ,发现在主服务器192.168.10.120中有 ens33网卡上 多出虚拟IP 192.168.10.10/24

dns的工作过程(DNS从入门到放弃系列)(16)

虚拟IP

至此完成MySQL Keepalived 的高可用安装和切换。

权威服务器安装

权威服务器还是在这两台设备上安装,实际生成环境我是把数据库和权威服务器分开安装。

安装 PowerDNS Authoritative Nameserver 4.7.3

# 创建官方提供的repo源文件,从官方仓库安装,路径:/etc/apt/sources.list.d/pdns.list cat >/etc/apt/sources.list.d/pdns.list<<EOF deb [arch=amd64] http://repo.powerdns.com/ubuntu jammy-auth-47 main EOF # 添加 /etc/apt/preferences.d/pdns cat >/etc/apt/preferences.d/pdns<<EOF Package: pdns-* Pin: origin repo.powerdns.com Pin-Priority: 600 EOF # 执行安装 curl https://repo.powerdns.com/FD380FBB-pub.asc | sudo apt-key add - && sudo apt-get update && sudo apt-get install pdns-server

查看管理状态:

# 查看权威服务器状态 systemctl status pdns.service # 启停 systemctl stop pdns.service systemctl start pdns.service

主从数据库新建数据库用户,作为主权威服务器读写数据库使用:

mysql> grant ALL PRIVILEGES on powerdns.* to 'pdnsadmin'@'%' identified by 'powerdns4321'; mysql> FLUSH PRIVILEGES;

如果MySQL数据库使用的存储引擎是InnoDB,建议加外键约束:

查看powerdns数据库使用什么存储引擎:show table status from powerdns;

ALTER TABLE records ADD CONSTRAINT `records_domain_id_ibfk` FOREIGN KEY (`domain_id`) REFERENCES `domains` (`id`) ON DELETE CASCADE ON UPDATE CASCADE; ALTER TABLE comments ADD CONSTRAINT `comments_domain_id_ibfk` FOREIGN KEY (`domain_id`) REFERENCES `domains` (`id`) ON DELETE CASCADE ON UPDATE CASCADE; ALTER TABLE domainmetadata ADD CONSTRAINT `domainmetadata_domain_id_ibfk` FOREIGN KEY (`domain_id`) REFERENCES `domains` (`id`) ON DELETE CASCADE ON UPDATE CASCADE; ALTER TABLE cryptokeys ADD CONSTRAINT `cryptokeys_domain_id_ibfk` FOREIGN KEY (`domain_id`) REFERENCES `domains` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;

主权威服务器配置文件:

cp /etc/powerdns/pdns.conf /etc/powerdns/pdns.conf.bak # 配置pdns.conf # 关闭安全更新 security-poll-suffix= # 启用API api=yes # 用于访问 REST API 的静态预共享身份验证密钥 api-key=Qno9k64Vkkkyfz1LtC3klk # 访问控制 allow-axfr-ips=0.0.0.0/0 allow-dnsupdate-from=0.0.0.0/0 allow-notify-from=0.0.0.0/0 allow-unsigned-notify=yes allow-unsigned-autoprimary=yes also-notify=192.168.10.120,192.168.10.120 # 不允许区域传输 数据库进行主从复制 disable-axfr=no # 作为守护进程运行 daemon=yes # 在守护进程中运行 guardian=no # 是否是主服务器 primary=yes # 启动权限 setgid=pdns setuid=pdns # 是否是从服务器 secondary=no # 开启详细查询日志 log-dns-details=yes # 不启用所有查询日志 log-dns-queries=no # 日志级别 loglevel=6 # 日志加上时间戳 log-timestamp=yes # 不同日志分类存储 logging-facility=0 # 记录query查询 query-logging=yes # 启用webserver webserver=yes # webserver监听地址 webserver-address=127.0.0.1 # webserver监听端口 webserver-port=8081 # pdns进程监听地址 启用IPv4 local-address=0.0.0.0 # pdns进程监听端口 local-port=53 # MySQL数据库配置 launch=gmysql # MySQL数据库地址 这里写VIP地址 gmysql-host= 192.168.10.10 # MySQL数据库端口 默认3306 gmysql-port=3306 # 要连接的数据库名 gmysql-dbname=powerdns # 数据库用户 gmysql-user=pdnsadmin # 数据库密码 gmysql-password=powerdns4321

从权威服务器配置文件:

# 关闭安全更新 security-poll-suffix= # 启用API api=yes # 用于访问 REST API 的静态预共享身份验证密钥 api-key=Qno9k64Vkkkyfz1LtC3klk # 访问控制 allow-axfr-ips=0.0.0.0/0 allow-dnsupdate-from=0.0.0.0/0 allow-notify-from=0.0.0.0/0 allow-unsigned-notify=yes allow-unsigned-autoprimary=yes also-notify=192.168.10.120,192.168.10.120 # 不允许区域传输 数据库进行主从复制 disable-axfr=no # 作为守护进程运行 daemon=yes # 在守护进程中运行 guardian=no # 是否是主服务器 primary=no # 启动权限 setgid=pdns setuid=pdns # 是否是从服务器 secondary=yes # 辅助节点检查区域更新秒数 默认60 xfr-cycle-interval=60 # 开启详细查询日志 log-dns-details=yes # 不启用所有查询日志 log-dns-queries=no # 日志级别 loglevel=6 # 日志加上时间戳 log-timestamp=yes # 不同日志分类存储 logging-facility=0 # 记录query查询 query-logging=yes # 启用webserver webserver=yes # webserver监听地址 webserver-address=127.0.0.1 # webserver监听端口 webserver-port=8081 # pdns进程监听地址 启用IPv4 local-address=0.0.0.0 # pdns进程监听端口 local-port=53 # MySQL数据库配置 launch=gmysql # MySQL数据库地址 这里写VIP地址 gmysql-host= 192.168.10.10 # MySQL数据库端口 默认3306 gmysql-port=3306 # 要连接的数据库名 gmysql-dbname=powerdns # 数据库用户 gmysql-user=pdnsadmin # 数据库密码 gmysql-password=powerdns4321

安装MySQL模块依赖包:主从权威服务器都需要安装,不然pdns启动不起来。

apt install pdns-backend-mysql

错误解决:

root@pdns01:/etc/keepalived# mysql -h 192.168.10.10 -u pdnsadmin -p Enter password: ERROR 1129 (HY000): Host '192.168.10.120' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'

指向这个命令解决:

mysql -u root -p -e 'flush hosts' Enter password: FLUSH HOSTS;

在192.168.10.120和192.168.10.130中启动pdns,权威服务器至此搭建完成:

# 配置文件完成修改 重启PDNS systemctl restart pdns.service # 查看状态 systemctl status pdns.service

总结

图中所画使用了7台服务器,实际我在文章搭建是使用了5台服务器,其中Web管理权威服务器的PDNS-Admin 服务还未搭建,将在下篇做搭建演示。

故文章中只使用了4台服务器,其中在192.168.10.100和192.168.10.110两台服务器同时搭建了dnsdist、pdns-recursor。

而在192.168.10.120和192.168.10.130中同时搭建了MySQL、Keepalived、和PowerDNS Authoritative Nameserver。其中数据库一主一从,做单向主从复制,Keepalived做数据库高可用,故障切换;PowerDNS Authoritative Nameserver权威服务器配置为主从架构。

至此架构图中最核心的组件和服务搭建完成,一套内部生成环境中使用的Local DNS就此完成;补充说明:实际生成环境数据库建议单独部署,不要和权威服务器搭建在同一台服务器,或者使用云数据库;如RDS等,可用性更好。

下一篇单独介绍下PDNS-Admin的搭建,这套Web管理权威服务器的增删改查系统,同时演示使用drill命令的基本操作和今天搭建的三套DNS组件管理工具,下一篇也将是DNS系列终篇,敬请期待。

,