これから仕事でDNS周辺技術を利用しそうなので,勉強のためにローカルにDNSサーバを構築して動かしてみました.
DNS関連で詳しい記事はたくさんありますが,自分のやりたかったこと(ローカルにキャッシュDNSと複数の権威DNSを立てる)がまとめられている記事がなかったので公開しました.
※docker&DNSの初心者が実装したとりあえず動くだけのものです.信頼しないでください.
対象者
- DNSの基礎的な知識はあるが,実装したことがない方
実行環境
- Windows10
- WSL2 (Ubuntu 22.04)
- Docker v2.21.0 (注: Docker desktop ではありません)
- CoreDNS v1.11.1
システムの全体像
Docker環境に3つのDNSサーバを構築します.
2つの権威DNSサーバがそれぞれ管理するドメインに対して,自前のキャッシュDNSサーバが名前解決を行います.
権威DNSサーバ1はexample.org
のドメインを管理し,そのサブドメイン"home".example.org
の管理を権威DNSサーバ2に委譲します.
本記事ではまず最初にCoreDNSを用いて権威DNSサーバを構築します.
キャッシュDNSサーバの構築手順は次回の記事 Docker+DNS入門 その2:Unboundを用いたキャッシュDNSサーバ構築で説明します.
CoreDNS とは
- CoreDNSはGo言語で実装された軽量で柔軟性のあるDNSです.
- CoreDNSはデフォルトではほとんど機能を持たず,必要な機能をプラグインとして追加することでカスタマイズできます.
- 追加するプラグインは設定ファイル (Corefile) に記述します.
用意するファイル
$ tree -a dns_test/
dns_test/
├── compose.yml
├── .env
├── example_auth
│ ├── Corefile
│ └── zone
│ └── db.example.org
└── home_example_auth
├── Corefile
└── zone
└── db.home.example.org
権威DNSサーバ1 (example.orgサーバ) の設定
- CoreDNSの設定ファイルを作成
./example_auth/Corefile
example.org { file /etc/coredns/zone/db.example.org log reload 5s }
- プラグインの説明
- example.orgドメインの問い合わせを受け付けます.
-
file {ファイルパス}
により,ファイルに記述したゾーン情報を参照します. -
log
により,CoreDNS実行中のログ情報が標準出力されます. -
reload 5s
により,5秒ごとにCorefileをリロードします.
- プラグインの説明
- Corefileが読み込むzoneファイル
./example_auth/zone/db.example.org
$TTL 2d ; default TTL for zone $ORIGIN example.org. ; base domain-name @ IN SOA ns1.example.org. noc.example.org. ( 2022090400 ; serial number 12h ; refresh 15m ; update retry 3w ; expiry 2h ; minimum ) ; name server resource record for the domain IN NS ns1.example.org. home IN NS ns1.home ; domain hosts includes NS records defined above ns1 IN A 172.19.0.21 ns1.home IN A 172.19.0.31
home IN NS ns1.home
により,*.home.example.org
のドメイン解決を別のサーバに委譲しています.
権威DNSサーバ2 (home.example.orgサーバ) の設定
- CoreDNSの設定ファイル(Corefle)を作成
./home_example_auth/Corefile
home.example.org { file /etc/coredns/zone/db.home.example.org log reload 5s }
- Corefileで読み込むzoneファイルを作成
./home_example_auth/zone/db.home.example.org
$TTL 2d ; default TTL for zone $ORIGIN home.example.org. ; base domain-name @ IN SOA ns1.home.example.org. noc.home.example.org. ( 2022090400 ; serial number 12h ; refresh 15m ; update retry 3w ; expiry 2h ; minimum ) ; name server RR for the domain IN NS ns1.home.example.org. ; domain hosts includes NS records defined above ns1 IN A 172.19.0.31 mail IN A 172.19.0.32 www IN A 172.19.0.33 ftp IN A 172.19.0.34
dockerの設定
- CoreDNS の docker imageをpull
docker pull coredns/coredns
- コンテナネットワークを作成
docker network create --subnet=172.19.0.0/16 dns_test
- compose.ymlを作成
./compose.yml
services: example_auth: image: coredns/coredns:1.11.1 container_name: example_auth restart: on-failure volumes: - './example_auth:/etc/coredns' networks: dns_test: ipv4_address: $ipv4_example_auth command: -conf /etc/coredns/Corefile -dns.port $dns_port home_example_auth: image: coredns/coredns:1.11.1 container_name: home_example_auth restart: on-failure volumes: - './home_example_auth:/etc/coredns' networks: dns_test: ipv4_address: $ipv4_home_example_auth command: -conf /etc/coredns/Corefile -dns.port $dns_port networks: dns_test: external: true
- compose.yml内の変数は
./.env
に記述
./.envdns_port=53 ipv4_example_auth=172.19.0.21 ipv4_home_example_auth=172.19.0.31
- compose.yml内の変数は
compose.yml の中身の説明
- オプションについての説明は以下が詳しいです.
- service:について
- volumes:で指定したパスにボリュームをマウントします.
- このパス以下に作成したデータはコンテナを破棄しても削除されません.
-
'./docker-dns/example_auth:/etc/coredns'
とすると,コンテナ側の/etc/coredns
にボリュームが用意され,かつホスト側の./docker-dns/example_auth
に紐付けられます. - つまり
./docker-dns/example_auth
配下の設定ファイルをコンテナ側が参照できるようになります.
- (service:配下の) networks:でコンテナが所属するネットワークならびに割当IPアドレスを指定します.
- 先ほど作成したネットワーク dns_testに所属させます.
-
ipv4_address: $ipv4_example_auth
により,サブネット (172.19.0.0/16) 内の適当なアドレスを割り当てます.
-
command: -conf /etc/coredns/Corefile -dns.port $dns_port
により以下を決めています.- CoreDNSの設定ファイル(Corefile)の読み込み
- 権威DNSサーバの稼働するポートを53番に指定 (デフォルトでも53番ですが)
- volumes:で指定したパスにボリュームをマウントします.
- networks:について
-
external: True
により,dns_testに所属するコンテナが他のネットワークとも通信可能となります.
-
動作確認
権威DNSサーバの起動
compose.yml
があるディレクトリでdocker compose up
を実行します.
~/dns_test$ docker compose up
[+] Running 2/2
✔ Container example_auth Created 0.1s
✔ Container home_example_auth Cre... 0.1s
Attaching to example_auth, home_example_auth
home_example_auth | home.example.org.:53
home_example_auth | [INFO] plugin/reload: Running configuration SHA512 = ~~~
home_example_auth | CoreDNS-1.11.1
home_example_auth | linux/amd64, go1.20.7, ae2bbc2
example_auth | example.org.:53
example_auth | [INFO] plugin/reload: Running configuration SHA512 = ~~~
example_auth | CoreDNS-1.11.1
example_auth | linux/amd64, go1.20.7, ae2bbc2
Corefileでlogを有効化したことでログが標準出力されています.起動したことが確認できます.
権威DNSサーバによる名前解決
- ホスト側で172.19.0.21(example.orgサーバ)を指定して,DNSクエリを投げて,名前解決できていることを確認します.
- +nocookieにより,DNS cookieを利用せず,最新の設定内容が得られます.
$ dig +nocookie @172.19.0.21 ns1.example.org
; <<>> DiG 9.18.18-0ubuntu0.22.04.1-Ubuntu <<>> +nocookie @172.19.0.21 ns1.example.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 9388
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;ns1.example.org. IN A
;; ANSWER SECTION:
ns1.example.org. 172800 IN A 172.19.0.21
;; AUTHORITY SECTION:
example.org. 172800 IN NS ns1.example.org.
;; Query time: 0 msec
;; SERVER: 172.19.0.21#53(172.19.0.21) (UDP)
;; WHEN: ~~~
;; MSG SIZE rcvd: 115
- 同様に172.19.0.31 (home.example.orgサーバ) を指定して,DNSクエリを投げて,名前解決できていることを確認します.
$ dig +nocookie @172.19.0.31 www.home.example.org
; <<>> DiG 9.18.18-0ubuntu0.22.04.1-Ubuntu <<>> +nocookie @172.19.0.31 www.home.example.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 61428
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;www.home.example.org. IN A
;; ANSWER SECTION:
www.home.example.org. 172800 IN A 172.19.0.33
;; AUTHORITY SECTION:
home.example.org. 172800 IN NS ns1.home.example.org.
;; Query time: 0 msec
;; SERVER: 172.19.0.31#53(172.19.0.31) (UDP)
;; WHEN: ~~~
;; MSG SIZE rcvd: 135
補足
ここまでの実装では,example.orgサーバからhome.example.orgサーバへの委譲を利用できません.
具体的には,ホストがwww.home.example.org
のIPアドレスを権威DNSサーバ1 (example.orgサーバ) へ問い合わせた時,サーバ1はそのIPアドレスを管理しているhome.example.orgサーバの情報を知らせるのみで,ホストもサーバ1もそれ以上は問い合わせない (反復問い合わせをしない) 状態です.
次回の話
次回の記事 Docker+DNS入門 その2:Unboundを用いたキャッシュDNSサーバ構築では,ホストに代わって反復問い合わせを行うキャッシュDNSサーバ(フルサービスリゾルバ)を,Docker+Unboundで実装します.
これによって,example.orgサーバからhome.example.orgサーバへの委譲を利用できます.