普段私はDNSサーバの開発や運用に携わっているのですが、仕事の傍らDockerを勉強しています。
DockerでBINDを試してみたので、備忘録も兼ねて共有しようと思います。
キャッシュ、権威DNSの構成も試しています。
#実行環境
私が試した環境は以下の通りです。
- Windows 10
- WSL2
- Docker Desktop
DockerがインストールされていればMacでもLinuxでも動くはずです。
#まずは1台の構成
###Dockerfileの用意
ディレクトリの構成は以下となっています。
bind/
├ Dockerfile
├ named.conf
└ example.com
FROM centos:7
RUN yum -y update
RUN yum install -y bind
RUN /usr/sbin/rndc-confgen -a -b 512 -k rndc-key
RUN chmod 755 /etc/rndc.key
EXPOSE 53/UDP
EXPOSE 53/TCP
COPY named.conf /etc/bind/
COPY example.com /etc/bind/master/
CMD ["/usr/sbin/named", "-c", "/etc/bind/named.conf", "-g", "-u", "named"]
include "/etc/rndc.key";
controls {
inet 127.0.0.1 allow { 127.0.0.1; } keys { "rndc-key"; };
};
acl "access-list" {
127.0.0.1;
172.17.0.0/16;
};
options {
directory "/etc/named/";
pid-file "/run/named/";
dump-file "/var/named/named_dump.db";
statistics-file "/var/named/named.stats.log";
zone-statistics yes;
version "";
masterfile-format text;
recursive-clients 10000;
tcp-clients 10000;
allow-recursion { access-list; };
allow-query { access-list; };
allow-query-cache { access-list; };
};
view "internal" {
recursion yes;
zone "example.com" IN {
type master;
file "/etc/bind/master/example.com";
};
};
$TTL 900
@ IN SOA example.com. postmaster.example.com. (
2020062101 ; Serial Number
1800 ; Refresh
900 ; Retry
1209600 ; expire
900 ; minimum
)
;
IN NS example.com.
IN A 1.2.3.4
www IN A 5.6.7.8
named.confの設定はほぼ最小限にしています。
###用意したファイルの説明
- BINDパッケージ
今回はBINDはyumでインストール。古いバージョンですが、試すだけなのでこれでも大丈夫です。
- Dockerfile内のEXPOSE
通信を想定するポートを指定します。DNSでは53ポートを使用します。
- named.conf, example.comといったファイルのコピー
BINDの設定に必要なファイルをイメージに追加します。
COPYするファイルはDockerfileを置いたディレクトリ内のファイルを指定します。
- BINDの起動
普通はsystemctlを使って起動するのですが、コンテナだと残念ながらできないようなので、直接named
を指定して起動します。
###イメージのビルド
$ docker build -t bind .
途中警告みたいなものがでるかもしれませんが、気にしなくても大丈夫です。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
bind latest b634adb26126 About an hour ago 412MB
イメージができたことを確認します。
###ビルドしたイメージを利用してコンテナを起動
docker run -dit -p 53:53 -p 53:53/udp --name bind bind:latest
ここでは -p
でポートマッピングを設定しています。
$ docker ps
b81999d14571 bind:latest "/usr/sbin/named -c …" About an hour ago Up About an hour 0.0.0.0:53->53/tcp, 0.0.0.0:53->53/udp bind
コンテナが起動できていることを確認できれば成功です。
###digで動作確認
digコマンドはドメインをDNSサーバに問いかけて、IPアドレスを教えてくれるコマンドです。
このコマンドを用いて動作確認を行いたいと思います。
ホスト側で以下のコマンドを打ってみてください
$ dig @localhost example.com
; <<>> DiG 9.16.1-Ubuntu <<>> @localhost example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58542
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 95bb6b3867347d2a659e18f05fa40fa7705d1af930ac0b3b (good)
;; QUESTION SECTION:
;example.com. IN A
;; ANSWER SECTION:
example.com. 900 IN A 1.2.3.4
;; AUTHORITY SECTION:
example.com. 900 IN NS example.com.
;; Query time: 10 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Thu Nov 05 23:43:51 JST 2020
;; MSG SIZE rcvd: 98
example.com
で設定したIPアドレス 1.2.3.4
が表示されていることがわかります。
ちなみに www.example.com
を問い合わせても設定したアドレス 5.6.7.8
が表示されています。
$ dig @localhost www.example.com
; <<>> DiG 9.16.1-Ubuntu <<>> @localhost www.example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 17044
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: fc8594f5fe0fda2a5b28b3f65fa41035d0243f359a253da7 (good)
;; QUESTION SECTION:
;www.example.com. IN A
;; ANSWER SECTION:
www.example.com. 900 IN A 5.6.7.8
;; AUTHORITY SECTION:
example.com. 758 IN NS example.com.
;; ADDITIONAL SECTION:
example.com. 758 IN A 1.2.3.4
;; Query time: 10 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Thu Nov 05 23:46:13 JST 2020
;; MSG SIZE rcvd: 118
#キャッシュ、権威DNSの構成を試す
先程は1台のDNSサーバのみでしたが、実際の運用だとクライアントからの問い合わせを受けて、クライアントの代わりに問い合わせを行うキャッシュDNSとゾーン情報を管理している権威DNS 2つの役割を持つDNSサーバを用います。
この構成もDockerで試してみたいと思います。
###コンテナ起動
まずは先程作成したコンテナを削除しましょう
$ docker rm bind
今度は2台のコンテナを作成します。
$ docker run -dit -p 53:53 -p 53:53/udp --name bind_cache bind:latest
$ docker run -dit --name bind_auth bind:latest
クライアントからの応答を受けるのはキャッシュDNSだけなので、キャッシュDNSにはポートマッピングの設定を入れます。
権威DNSはクライアントとは直接通信しないので設定していません。
一度 bind_cache
, bind_auth
のIPアドレスを確認しましょう。
$ docker inspect bind_cache | grep IPAddress
"SecondaryIPAddresses": null,
"IPAddress": "172.17.0.2",
"IPAddress": "172.17.0.2",
$ docker inspect bind_auth | grep IPAddress
"SecondaryIPAddresses": null,
"IPAddress": "172.17.0.3",
"IPAddress": "172.17.0.3",
bind_cache
の方は 172.17.0.2
、bind_auth
の方は 172.17.0.3
というIPアドレスであることがわかりました。
###キャッシュDNSの設定
キャッシュDNSの named.conf
を編集するために以下のコマンドを入力してコンテナの中に入ります。
$ docker exec -it bind_cache /bin/bash
vi などで view internal
の部分を以下のように編集します
・
・
・
view "internal" {
recursion yes;
zone "." {
type forward;
forwarders { 172.17.0.3; };
forward only;
};
};
forwarders
に先程確認した権威DNSのIPアドレスを入力します。
###権威DNSの設定
今度は権威DNSの named.conf
を見てみましょう。
$ docker exec -it bind_auth /bin/bash
同様にvi などで named.conf
を編集します
acl access-list
というところに注目してください。
include "/etc/rndc.key";
controls {
inet 127.0.0.1 allow { 127.0.0.1; } keys { "rndc-key"; };
};
acl "access-list" {
127.0.0.1;
172.17.0.0/16;
};
・
・
acl access-list
では通信を許可するIPアドレスを指定します。
先程確認したキャッシュDNSのIPアドレスは 172.17.0.2
でした。 今回は初期設定で 172.17.0.0/16
を許可しているのでこのままでも問題ないですが、キャッシュDNSのIPアドレスを指定しておきましょう。
include "/etc/rndc.key";
controls {
inet 127.0.0.1 allow { 127.0.0.1; } keys { "rndc-key"; };
};
acl "access-list" {
127.0.0.1;
172.17.0.2; // 172.17.0.2に変更
};
・
・
以上で設定は完了です。
設定を反映するために再起動しておきましょう。
2つコンテナが起動していることが確認できれば成功です。
$ docker restart bind_auth
$ docker restart bind_cache
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
NAMES
f0b2f14e26f2 bind:latest "/usr/sbin/named -c …" About an hour ago Up 6 minutes 53/tcp, 53/udp bind_auth
b81999d14571 bind:latest "/usr/sbin/named -c …" 2 days ago Up 6 minutes 0.0.0.0:53->53/tcp, 0.0.0.0:53->53/udp bind_cache
もし起動していない場合は、named.conf
の設定がうまく行っていないと考えられます。(;のつけ忘れなど, docker logs
を使えばエラーの内容が見れると思います)
その場合は、以下のコマンドで起動できなかったコンテナを一度削除して、コンテナを作成するところからやった方が楽かもしれません。
$ docker logs bind_XXX
$ docker rm bind_XXX または docker rm [コンテナID]
###digで動作確認
先ほどと同様にdigコマンドを用いて動作確認を行います。
$ dig @localhost example.com
; <<>> DiG 9.16.1-Ubuntu <<>> @localhost example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58542
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 95bb6b3867347d2a659e18f05fa40fa7705d1af930ac0b3b (good)
;; QUESTION SECTION:
;example.com. IN A
;; ANSWER SECTION:
example.com. 900 IN A 1.2.3.4
;; AUTHORITY SECTION:
example.com. 900 IN NS example.com.
;; Query time: 10 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Thu Nov 05 23:43:51 JST 2020
;; MSG SIZE rcvd: 98
example.com
で設定したIPアドレスが表示されていることがわかります。
ちなみに権威DNSで定義ていないドメインも引くことができます。
$ dig @localhost www.google.com
; <<>> DiG 9.16.1-Ubuntu <<>> @localhost www.google.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53253
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 4, ADDITIONAL: 9
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 3181d4115c9c0426b42bd02e5fa6a8a6a04cb4d481be1221 (good)
;; QUESTION SECTION:
;www.google.com. IN A
;; ANSWER SECTION:
www.google.com. 300 IN A 172.217.26.36
;; AUTHORITY SECTION:
google.com. 171777 IN NS ns1.google.com.
google.com. 171777 IN NS ns4.google.com.
google.com. 171777 IN NS ns3.google.com.
google.com. 171777 IN NS ns2.google.com.
;; ADDITIONAL SECTION:
ns4.google.com. 171777 IN A 216.239.38.10
ns2.google.com. 171777 IN A 216.239.34.10
ns1.google.com. 171777 IN A 216.239.32.10
ns3.google.com. 171777 IN A 216.239.36.10
ns4.google.com. 171777 IN AAAA 2001:4860:4802:38::a
ns2.google.com. 171777 IN AAAA 2001:4860:4802:34::a
ns1.google.com. 171777 IN AAAA 2001:4860:4802:32::a
ns3.google.com. 171777 IN AAAA 2001:4860:4802:36::a
;; Query time: 120 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Sat Nov 07 23:01:10 JST 2020
;; MSG SIZE rcvd: 335
#感想
思っていたよりも簡単にできました。
実運用で使えるのかどうかはわかりませんが、色々試してみたい思います。
次はキャッシュDNSにUnboundを使ってみようと思います。