BIND に代わる権威 DNS サーバの実装として巷で話題の PowerDNS と NSD を組み合わせて、DNS クラスタを構築してみる。
特徴
PowerDNS とは
PowerDNS とはオープンソースの DNS サーバで、バックエンドに MySQL などの RDB を使うことができる。その特徴から、多数のサードパーティ製 Web UI や API が存在する。権威サーバの pdns-server
とキャッシュサーバの pdns-recursor
がある。
NSD とは
NSD (Name Server Daemon) もまたオープンソースの権威 DNS サーバで、高性能でシンプルだと謳われている。キャッシュサーバの機能はない。バージョン4からは、ゾーンの動的な追加、削除が可能となっている。
要件
今回構築するシステムでは、次のような項目を要件とする。
- レコード情報は RDB で管理する
- 適当な Web UI を用意する
- master にゾーンを追加、削除した際の slave への同期は自動化する
- インターネットからの名前解決要求には NSD が答える
これを実現するために、次のような構成を検討する。
- master: PowerDNS × 1台
- slave: NSD × 2台以上
レジストリや NS レコードには、権威サーバとして slave のみを登録し、インターネットから master が直接参照されないようにする。
構築
それでは早速 master および slave サーバを構築していく。OS はいずれも Ubuntu 12.04.4 を使う。
$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=12.04
DISTRIB_CODENAME=precise
DISTRIB_DESCRIPTION="Ubuntu 12.04.4 LTS"
PowerDNS
まずは PowerDNS で master サーバを構築する。backend には MySQL を使う。
必要なパッケージを入れる。
# apt-get update
# DEBIAN_FRONTEND=noninteractive apt-get install -y pdns-server pdns-backend-mysql mysql-server mysql-client
設定を編集する。
# diff /etc/powerdns/pdns.conf.orig /etc/powerdns/pdns.conf
6c6
< # allow-axfr-ips=
---
> allow-axfr-ips=(slave の IP アドレスの範囲 (カンマ区切りで複数可))
57c57
< disable-axfr=yes
---
> disable-axfr=no
132c132
< # master=no
---
> master=yes
DNSSEC は使わないので無効にしておく。
# sed -i 's/^gmysql-dnssec=yes/gmysql-dnssec=no/' /etc/powerdns/pdns.d/pdns.local.gmysql
データベースのテーブルを作成する。スキーマは公式マニュアルの MySQL specifics からもらってくる。
# mysql -u root pdns
mysql> CREATE TABLE ...
リロードする。
# service pdns reload
ログの出力先を変更する。
# echo 'local0.* /var/log/pdns.log' > /etc/rsyslog.d/pdns.conf
# echo 'local0.none -/var/log/syslog' >> /etc/rsyslog.d/pdns.conf
# service rsyslog reload
これだけで PowerDNS がインストールできた。
Poweradmin
PowerDNS には多数のサードパーティ製 Web UI があるが、今回はそのうちの一つである Poweradmin を入れてみる。
まず必要なパッケージを入れる。
# apt-get install -y apache2 php5 php5-mcrypt php5-mysql git
# service apache2 reload
ソースコードを配置する。
# mkdir ~/src
# cd ~/src
# git clone https://github.com/poweradmin/poweradmin.git
# cp -pr poweradmin /var/www/
# chown -R www-data:www-data /var/www/poweradmin
Web ブラウザでインストール画面にアクセスする。
- http://(IP アドレス)/poweradmin/install/
データベースの接続情報は PowerDNS の設定ファイルで確認できる。
# cat /etc/powerdns/pdns.d/pdns.local.gmysql
インストールが済んだら、インストール画面を無効化する。
# mv /var/www/poweradmin/install /var/www/poweradmin/install.bak
# chmod 0 /var/www/poweradmin/install.bak
ログイン画面にアクセスする。 (admin / 設定したパスワード)
- http://(IP アドレス)/poweradmin/
試しに Add master zone から適当なゾーンを追加してみる。今回は example.com
とする。その後、PowerDNS で引けるようになるか確認する。
$ dig @127.0.0.1 example.com. soa +short
ns1.example.jp. hostmaster.example.jp. 2014051100 28800 7200 604800 86400
これで master 側の準備ができた。
NSD
次は NSD で slave サーバを構築する。
Ubuntu 14.04 では apt で nsd4 が入るが、挙動が微妙だったのでソースからビルドすることにする。手順は下記の記事を参考にする。なお、現時点での最新バージョンは 4.0.3 だった。
make install
できたら、設定ファイルを編集する。肝は pattern
を定義すること。
# diff /etc/nsd4/nsd.conf.sample /etc/nsd4/nsd.conf
143c143
< # control-enable: no
---
> control-enable: yes
182c182,186
< # pattern:
---
> pattern:
> name: "slavezone"
> zonefile: "%s.zone"
> allow-notify: (master の IP アドレス) NOKEY
> request-xfr: (master の IP アドレス) NOKEY
起動スクリプトを配置する。
# install -o root -g root -m 755 /path/to/nsd-4.0.3/contrib/nsd.init /etc/init.d/nsd
# sed -i 's#/etc/nsd.conf#/etc/nsd4/nsd.conf#' /etc/init.d/nsd
# sed -i 's#^sbindir="/usr/sbin"#sbindir="/usr/local/sbin"#' /etc/init.d/nsd
起動する。
# /etc/init.d/nsd start
念のため master から AXFR でゾーン転送できるか確認しておく。
# dig @(master の IP アドレス) example.com. axfr +short
ns1.example.jp. hostmaster.example.jp. 2014051100 28800 7200 604800 86400
ns1.example.jp. hostmaster.example.jp. 2014051100 28800 7200 604800 86400
nsd-control
の addzone
で slave ゾーンを追加してみる (slavezone
の部分は設定ファイルで指定した名前)。
# nsd-control addzone example.com slavezone
ok
master からゾーン転送できているか確認する。
# dig @127.0.0.1 example.com. soa +short
ns1.example.jp. hostmaster.example.jp. 2014051100 28800 7200 604800 86400
うまくいったようなので、2台目以降の slave も同様に構築する。
同期の自動化
これまでの手順で、PowerDNS の master と NSD の slave による DNS を構築できた。
ただし現時点では、master にゾーンを追加、削除するたびに、各 slave で nsd-control
の addzone
や delzone
を実行しなければならない。これは面倒なので、master から slave へのゾーンリストの同期を自動化する。
流れとしては次のような感じ。
- master でゾーンのリストを作る
- slave でゾーンのリストを作る
- slave でリストを照合し、差分を追加、削除する
まずは master サーバ側で、ゾーンリストを生成するスクリプトを作成する。名前は ~ubuntu/zone_sync/master_zones.sh
とする (ubuntu
は任意のユーザ)。
#!/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
DIR=$(cd $(dirname $0); pwd)
cd $DIR
mysql -BN -u root pdns -e "SELECT name FROM domains WHERE TYPE = 'master';" \
| sort \
> .master_zones.txt.tmp \
&& mv .master_zones.txt.tmp master_zones.txt
実行権を与える。
# chmod +x master_zones.sh
多重起動を防止するために daemontools
の setlock
を使う。
# apt-get install -y daemontools
cron に登録する。実行間隔は適当に調整する。
# crontab -u ubuntu -e
* * * * * setlock -n /tmp/master_zones.lock /home/ubuntu/zone_sync/master_zones.sh
これで定期的に master サーバ上でゾーンのリスト (master_zones.txt
) が吐き出されるようになった。
以降は slave で作業する。まず ssh の公開鍵を生成する。
# ssh-keygen
ssh の設定ファイルを作成する。
# vi /root/.ssh/config
Host (master の IP アドレス)
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
master に鍵を配置する。
# ssh ubuntu@(master の IP アドレス) 'cat >> .ssh/authorized_keys' < .ssh/id_rsa.pub
master に鍵認証で ssh ログインできるか確認する。
# ssh ubuntu@(master の IP アドレス) hostname
Warning: Permanently added 'XXX.XXX.XXX.XXX' (ECDSA) to the list of known hosts.
ns0.example.jp
同期スクリプトを作成する。名前は /root/zone_sync/zone_sync.sh
とする。
#!/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MASTER_HOST=(master の IP アドレス)
MASTER_USER=ubuntu
set -e
DIR=$(cd $(dirname $0); pwd)
cd $DIR
scp -p $MASTER_USER@$MASTER_HOST:zone_sync/master_zones.txt .
nsd-control zonestatus | grep '^zone:' | awk '{print $2}' | sort > slave_zones.txt
for i in $(diff master_zones.txt slave_zones.txt | grep '^<' | awk '{print $2}'); do
nsd-control addzone $i slavezone > /dev/null || :
done
for i in $(diff master_zones.txt slave_zones.txt | grep '^>' | awk '{print $2}'); do
nsd-control delzone $i > /dev/null || :
done
nsd-control write
同じく daemontools を入れる。
# apt-get install -y daemontools
cron に登録する。
# crontab -e
* * * * * setlock -n /tmp/zone_sync.lock /root/zone_sync/zone_sync.sh
これで自動的に同期されるようになった。試しに Poweradmin で適当にゾーンを追加、削除して、動作を確認してみると良い。
おわりに
以上で PowerDNS と NSD を組み合わせた DNS クラスタが構築できた。今後は大量のゾーン、レコードを投入しての動作検証や、dnsperf などを用いた負荷テストをやりたい。
参考ページ
- WebFrontends – PowerDNS/pdns Wiki
- PowerDNS のご紹介 – slideshare
- Unbound/NSD 最新情報 – slideshare
コメント