前言
自从构建网络以来,为了图一时的方便,我一直在使用 Microsoft DNS Server 作为自己网域的权威 DNS 服务器。现在是时候抛弃专有软件,尝试一下朋友们都在用的 PowerDNS 了。
还有一件事就是,我打算对老核心网络节点(设在老家)去核心化,并把最重要的服务逐渐搬上云。
[alert]本文为操作笔记,并非教程。[/alert]
为什么
上云成本降低了,云端的稳定性相对比自有设备高很多,也不受浮动网络的影响。我于今年 7 月一下子购入了 5 年的 Aliyun 作为核心控制节点 —— 没错,核心业务都跑在一台机器上。
这时,有一个朋友(?)前来吐槽 —— “你为什么不用 Docker?” 或 “这样很容易发生单点故障!” 等等。
对于个人业务,在有限的资源环境下,现阶段我倾向于化繁为简。直接使用 systemd 来管理各业务,使用符号链接将配置文件集中管理,使用脚本记录部署过程以方便后续迁移。对于个人业务而言,这些足够了。相反使用 Docker 会消耗更多内存,对于区区 2 GB 内存的突发性能实例,实在是有点压力。最近看到群友相继入教 NixOS,我也略有兴趣,不过眼下咱还是继续留在 Debian 教派。
过程
现时我正在使用 Ubuntu 20.04 LTS。我选择使用 “PowerDNS Authoritative Server – master branch”。
1. 新建 “/etc/apt/sources.list.d/pdns.list”:
deb [arch=amd64] http://repo.powerdns.com/ubuntu focal-auth-master main
2. 新建 “/etc/apt/preferences.d/pdns”:
Package: pdns-* Pin: origin repo.powerdns.com Pin-Priority: 600
3. 安装:
curl https://repo.powerdns.com/CBC8B383-pub.asc | sudo apt-key add - && sudo apt update && sudo apt install pdns-server
4. 使用 MySQL 作为后端,新增 “/etc/powerdns/pdns.d/mysql.conf”:
# MySQL Configuration # Launch gmysql backend launch+=gmysql # gmysql parameters gmysql-host=localhost gmysql-port=3306 gmysql-dbname=powerdns gmysql-user=powerdns gmysql-password=Str0ngPasswOrd gmysql-dnssec=yes # gmysql-socket=
5. 初始化数据库内容,这里的 Schema 节选自文档 “Generic MySQL backend“,适配 4.3(或更高?)。内容来自 ( /usr/share/pdns-backend-mysql/schema/schema.mysql.sql) 注意不同版本的文件可能不同。也可以使用 mysql 直接导入:
mysql -u pdnsadmin -p pdns < /usr/share/pdns-backend-mysql/schema/schema.mysql.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(6) NOT NULL, notified_serial INT UNSIGNED DEFAULT NULL, account VARCHAR(40) CHARACTER SET 'utf8' DEFAULT NULL, PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE UNIQUE INDEX name_index ON domains(name); 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);
6. 安装 PowerDNS Admin 以简化管理。
git clone https://github.com/ngoduykhanh/PowerDNS-Admin.git /opt/web/powerdns-admin sudo apt install python3.8-venv sudo apt install -y libmysqlclient-dev libsasl2-dev libldap2-dev libssl-dev libxml2-dev libxslt1-dev libxmlsec1-dev libffi-dev pkg-config apt-transport-https virtualenv build-essential cd powerdns-admin python3 -mvenv ./venv source ./venv/bin/activate pip install --upgrade pip pip install -r requirements.txt npm install -g yarn yarn install --pure-lockfile export FLASK_APP=powerdnsadmin/__init__.py flask assets build
7. 设置 PowerDNS 专用数据库及用户。更改 “./powerdnsadmin/default_config.py”。最后进行 DB 迁移。
flask db upgrade deactivate
8. 设置 Gunicorn, systemd 服务及配置 Nginx 反向代理。
新建 “/etc/systemd/system/powerdns-admin.service”
[Unit] Description=PowerDNS-Admin Requires=powerdns-admin.socket After=network.target [Service] PIDFile=/run/powerdns-admin/pid User=www-data Group=www-data WorkingDirectory=/iedon/powerdns-admin ExecStart=/iedon/powerdns-admin/venv/bin/gunicorn --pid /run/powerdns-admin/pid --bind unix:/run/powerdns-admin/socket 'powerdnsadmin:create_app()' ExecReload=/bin/kill -s HUP $MAINPID ExecStop=/bin/kill -s TERM $MAINPID PrivateTmp=true [Install] WantedBy=multi-user.target
新建 “/etc/systemd/system/powerdns-admin.socket”
[Unit] Description=PowerDNS-Admin socket [Socket] ListenStream=/run/powerdns-admin/socket [Install] WantedBy=sockets.target
新建 “/etc/tmpfiles.d/powerdns-admin.conf”,设置相应目录权限,启动并设置相关服务自启。
d /run/powerdns-admin 0755 www-data www-data -
sudo mkdir /run/powerdns-admin/ sudo chown -R www-data: /run/powerdns-admin/ sudo chown -R www-data:www-data /iedon/powerdns-admin/powerdnsadmin/static sudo systemctl daemon-reload sudo systemctl start powerdns-admin.socket sudo systemctl enable powerdns-admin.socket sudo systemctl enable powerdns-admin.service
Nginx 反向代理关键配置段:
location / { proxy_pass http://unix:/run/powerdns-admin/socket; }
9. 在 PowerDNS Admin 中创建新用户(第一个用户将作为管理用户),并进行后续设置。最终我们可以得到类似于下图的效果:
10. 在搬运旧配置并适当更新后,我重启了 3 个 anycast 节点(BIND, 它们通过 AXFR 与主 DNS Server 联系以获得区域拷贝),在观察到区域传递正常后,我终于得以为老 DNS Server 按下停止的红色按钮:
验证
使用 Dig 来验证配置是否正确。我们通过查询全网递归服务器来检视结果是否符合预期。
dig @172.23.0.53 lg.iedon.xxxx ; <<>> DiG 9.16.1-Ubuntu <<>> @172.23.0.53 lg.iedon.xxxx ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10964 ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;lg.iedon.xxxx. IN A ;; ANSWER SECTION: lg.iedon.xxxx. 475 IN CNAME anycast-services.iedon.xxxx. anycast-services.iedon.xxxx. 475 IN A 172.23.91.1 ;; Query time: 240 msec ;; SERVER: 172.23.0.53#53(172.23.0.53) ;; WHEN: Fri Nov 26 20:39:46 UTC 2021 ;; MSG SIZE rcvd: 99
很好,我们再来看看反向解析(PTR):
dig -x 172.23.91.121 @172.23.0.53 ; <<>> DiG 9.16.1-Ubuntu <<>> -x 172.23.91.xxx @172.23.0.53 ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 57412 ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 512 ;; QUESTION SECTION: ;xxx.91.23.172.in-addr.arpa. IN PTR ;; ANSWER SECTION: xxx.91.23.172.in-addr.arpa. 900 IN CNAME xxx.0/25.91.23.172.in-addr.arpa. xxx.0/25.91.23.172.in-addr.arpa. 396 IN PTR 50me.xx-xxx-xxx1.bkb.iedon.xxxx. ;; Query time: 456 msec ;; SERVER: 172.23.0.53#53(172.23.0.53) ;; WHEN: Fri Nov 26 20:41:45 UTC 2021 ;; MSG SIZE rcvd: 123
非常棒。
参考
1. How to Install PowerDNS Server and PowerDNS Admin on Ubuntu 20.04, https://www.howtoforge.com/how-to-install-powerdns-admin-on-ubuntu-20-04/
2. Generic MySQL backend, PowerDNS Document, https://doc.powerdns.com/authoritative/backends/generic-mysql.html
3. PowerDNS-Admin Project, GitHub, https://github.com/ngoduykhanh/PowerDNS-Admin
Leave a Reply