1. はじめに
こんにちは!
最近docker-compose完全に理解した(してない)富田です!
突然ですが、DNSで俗に浸透と呼ばれる現象、ありますよね?
DNSサーバでゾーン情報を更新しても、その更新がユーザーの見える範囲に反映されるまで時間がかかるという、あの現象です。
今回はそれがどんなものなのかを直接見てみようと思い、手元で実験してみました!
(ちなみに、DNSの浸透という言葉を真面目に使うと、ネットワークつよつよの人からマサカリが飛んでくるらしいです。)
2. 実験環境の構成
2-1. 概要
ここで用いる実験環境はWSLのUbuntu上でdocker-composeを使って実験環境を構築しました。
(実験環境をコードで説明できるって便利ですよね!)
実験環境は以下の3つのサーバからなります。
- 権威サーバ:ゾーン情報の大本を保持するサーバです。今回BINDを使用しています。
- キャッシュサーバ:権威サーバの情報をキャッシュするサーバです。上に同じくBINDを使用しています。
- 観測用サーバ:権威サーバとキャッシュサーバが保持している内容を問い合わせるサーバです。
これら3つのサーバは下の構成図のように一つのサブネット(exnet)につながっています。
2-2. フォルダー構成とファイル内容
このサブセクションは細かい構成の話なので、結果が見たい人はセクション3まで読み飛ばして大丈夫です。
フォルダー構成は以下の通りです。
DNSExperiment
├── docker-compose.yml
├── bind_auth
│ ├── named.conf
│ └── zonefiles
│ └── example.com.zone
├── bind_cache
│ └── named.conf
└── observer
├── Dockerfile
└── observe.sh
ファイルの内容は、以下の通りです。
docker-compose.yml(全体の構成ファイル)
実験用のネットワークとして外界から隔離されたネットワークexnetを作成し、権威サーバとキャッシュサーバ、観測用サーバを接続します。
また、DNSの向き先は権威サーバとキャッシュサーバは権威サーバ、観測用サーバはキャッシュサーバを向くようにしています。
(結局、どのサーバもIPアドレス指定で参照するのであまり意味はないですが一応)
version: '3'
services:
# DNS権威サーバ
bind_auth:
image: ubuntu/bind9:9.18-22.04_beta
volumes:
- ./bind_auth/named.conf:/etc/bind/named.conf
- ./bind_auth/zonefiles:/var/lib/bind
networks:
exnet:
ipv4_address: 192.168.11.11
dns: 192.168.11.11
# DNSキャッシュサーバ
bind_cache:
image: ubuntu/bind9:9.18-22.04_beta
volumes:
- ./bind_cache/named.conf:/etc/bind/named.conf
networks:
exnet:
ipv4_address: 192.168.11.12
dns: 192.168.11.11
depends_on:
- bind_auth
# 観測用サーバ
observer:
build:
context: ./observer
dockerfile: Dockerfile
networks:
exnet:
ipv4_address: 192.168.11.21
dns: 192.168.11.12
networks:
# 実験用ネットワーク(EXperimental NETwork)
exnet:
driver: bridge
internal: true
ipam:
driver: default
config:
- subnet: 192.168.11.0/24
bind_auth/named.conf(権威サーバの設定ファイル)
ゾーン情報を持っているので、そのための項目をzoneで設定しています。
また、今回は実験を簡単にするため、dnssec-validationは切っています。
options {
directory "/var/cache/bind";
listen-on { any; };
listen-on-v6 { any; };
recursion no;
dnssec-validation no;
};
zone "example.com" IN {
type master;
file "/var/lib/bind/example.com.zone";
allow-update { none; };
notify no;
};
bind_auth/zonefiles/example.com.zone(実験対象のゾーン情報ファイル)
ゾーン情報本体です。
今回いじるのは1行目のTTLと、11行目のAレコードです。
普通はTTLは日単位のもう少し大きい数を指定すると思うのですが、今回は実験なので1分にしています。
$TTL 60
@ IN SOA example.com. postmaster.example.com. (
2024030211 ; Serial Number
1800 ; Refresh
900 ; Retry
1209600 ; expire
900 ; minimum
)
;
IN NS example.com.
IN A 192.168.10.100
bind_cache/named.conf(キャッシュサーバの設定ファイル)
権威サーバと違ってゾーン情報を持たないのでzoneの項目が無い代わりに、
forwardersに権威サーバを指定しています。
options {
directory "/var/cache/bind";
listen-on { any; };
listen-on-v6 { any; };
forwarders {
192.168.11.11;
};
recursion yes;
dnssec-validation no;
};
observer/Dockerfile(観測用サーバの構成ファイル)
観測用サーバはdigコマンドを用いて権威サーバとキャッシュサーバのレコードを確認するので、
digコマンドを含むdnsutilsをインストールし、digコマンドを実行するスクリプトobserve.shをコピーしてきます。
コマンドがすぐに終了するとコンテナが止まってしまうので、sleep infinityを実行することで「何もしない」をしてもらいます。
(sleep infinityはこれで初めて知りました(笑))
FROM ubuntu:22.04
RUN apt update -y
RUN apt install dnsutils -y
COPY observe.sh /root/observe.sh
RUN chmod u+x /root/observe.sh
CMD ["sleep", "infinity"]
observer/observe.sh(観測スクリプト)
digコマンドを使用して権威サーバとキャッシュサーバにそれぞれ問い合わせます。
#!/usr/bin/bash
echo "================"
echo "bind_auth"
dig example.com @192.168.11.11 +noall +ans
echo "================"
echo "bind_cache"
dig example.com @192.168.11.12 +noall +ans
echo "================"
3. 実験1:権威サーバのIPアドレスを変えてみる
3-1. 環境を立ち上げる
早速やってみましょう!
まず、環境を立ち上げます。
docker-compose up -d
観測用サーバで観測スクリプトを1秒おきに実行するようにします。
docker exec -t dnsexperiment_observer_1 watch -n 1 /root/observe.sh
観測スクリプトの結果がこんな感じに出てきます。
二段になってますが、上の段bind_authと書いてある方が権威サーバに問い合わせた結果で、
下の段bind_cacheと書いてある方がキャッシュサーバに問い合わせた結果です。
ゾーンファイルで設定した内容が出ていることが分かります。
この実験で注目する必要があるのは、2カラム目の数字と5カラム目のIPアドレスです。
2カラム目の数字はTTL(Time To Live)と言って、このゾーン情報の残りの有効時間(秒単位)を表します。
権威サーバはゾーンファイルに記されたTTLの値で固定で、キャッシュサーバは時間経過でカウントダウンしています。
3-2. 権威サーバのゾーン情報を書き換える
ここで、権威サーバに登録されているゾーン情報を変えてみようと思います。
ゾーンファイルを以下のように編集して
Diff$TTL 60
@ IN SOA example.com. postmaster.example.com. (
2024030211 ; Serial Number
1800 ; Refresh
900 ; Retry
1209600 ; expire
900 ; minimum
)
;
IN NS example.com.
- IN A 192.168.10.100
+ IN A 192.168.10.123
以下のコマンドで権威サーバのゾーン情報を更新します。
docker exec dnsexperiment_bind_auth_1 rndc reload
このようになりました。
権威サーバの方は確かにアドレスが変わりましたが、 キャッシュサーバの方は変わっていませんね。
キャッシュサーバ側のTTLが0になるまで待ってみます。(↓アニメーションGIFです)
TTLが切れると、キャッシュサーバの方も更新されました。
3-3. 実験1のまとめ
このことから、権威サーバが更新されてもキャッシュサーバはすぐには更新されず、TTLが0になるまでは古い情報を保持し続けることがわかりました。
4. 実験2:TTLを3秒にしてみる。
4-1. ゾーンファイルのTTLを3秒に変更
では、TTLを短くしたらすぐに更新されるのでは?と思ったので、今度は思い切ってTTLを3秒にしてみました。
Diff-$TTL 60
+$TTL 3
@ IN SOA example.com. postmaster.example.com. (
2024030211 ; Serial Number
1800 ; Refresh
900 ; Retry
1209600 ; expire
900 ; minimum
)
;
IN NS example.com.
IN A 192.168.10.123
先ほどと同じコマンドで権威サーバのゾーン情報を更新します。
IPアドレスと同じくすぐには変わりませんね。
また、TTLが切れるまで待つと、TTLが3秒になりました。
4-2. TTLが3秒の状態でIPアドレスを更新してみる。
ゾーンファイルを編集して更新すると
Diff$TTL 3
@ IN SOA example.com. postmaster.example.com. (
2024030211 ; Serial Number
1800 ; Refresh
900 ; Retry
1209600 ; expire
900 ; minimum
)
;
IN NS example.com.
- IN A 192.168.10.123
+ IN A 192.168.10.234
すぐに更新されました。
4-3. 実験2のまとめ
このことから、TTLを短くするとすぐに更新されるようになるが、TTLの値が反映されるまでは旧TTLの時間分待つ必要があることがわかりました。
5. まとめ
以上の実験から、
- キャッシュサーバの情報はIPアドレスもTTLも、キャッシュサーバに登録されている情報のTTLが切れるまでは更新されないこと
- TTLを短くするとすぐに更新されるようになること。
がわかりました。
このTTLの値は権威サーバに登録されているゾーン情報に由来することを考えると、キャッシュの更新の頻度は権威サーバに主導権があることもわかります。
つまり、ゾーン情報の更新をすぐにキャッシュサーバに反映したい場合は、 あらかじめ権威サーバに登録されているゾーン情報のTTLを短くしておけばよいということですね!
流石に3秒は短すぎますが(笑)
ちなみに、冒頭でチラッと言った「浸透」というワード、何が問題なのか調べてみたところ、「『浸透』にはその過程がコントロールできないニュアンスがありますが、実際はこのまとめの通りコントロールできるものなので不適当である」ということでした。