DockerからDNSキャッシュサーバUnboundを使う

DockerからDNSキャッシュサーバUnboundを使う
Page content

コンテナからのDNSアクセスはどこへ向かう?

Dockerコンテナを多数、Ubuntu 18.04のサーバ1台の中で動かしていて、それぞれのコンテナから特定の外部Web APIを秒単位で利用しているようなケースにて。

全体のパフォーマンスを確認するなかで、各コンテナのDNSアクセスはネットワークのどこへ向かっているのか、気になってきた。

デフォルトだと 8.8.8.8, 8.8.4.4 を参照

Docker 18.06.1-ceの環境で、ホスト側の/var/log/syslogを次のように確認してみる。すると、Dockerコンテナをそのままdocker runしたならば、それらのDNSサーバとしてデフォルトで、自動的に「8.8.8.8」「8.8.4.4」が指定されることがわかった。なるほど。

$ cat /var/log/syslog | grep dockerd
(省略) level=info msg="No non-localhost DNS nameservers are left in resolv.conf. Using default external servers: [nameserver 8.8.8.8 nameserver 8.8.4.4]"

次のように各Dockerコンテナの/etc/resolv.confでも、DNS設定を確認できる。

$ docker exec IMAGE名 cat /etc/resolv.conf
nameserver 8.8.8.8
nameserver 8.8.4.4
options edns0

コンテナ近くにDNSキャッシュサーバを立てる

Google Public DNS (8.8.8.8, 8.8.4.4) へは、今回のDockerコンテナからネットワーク的な距離が多少はあるはず。DockerコンテナからそのようなDNSサーバへのDNS参照を減らすためには、「DockerホストにDNSキャッシュサーバを立てて、それをDockerコンテナから参照させると良いのかな?」と思いつく。(ちなみにこの時点では、Ubuntuのデフォルトで動いているsystemd-resolvedというものの存在を私は知らなかった)

Ubuntuでは、UnboundというDNSキャッシュサーバが扱いやすそうなので (参考: unboundとは | OSSでのシステム構築・デージーネット)、これを次のようにaptコマンドでインストールした。

$ sudo apt install unbound

UnboundのDockerコンテナ向け設定

Dockerホスト側でのDNSに関する機構はそれぞれ分離しておきたいので、具体的には次の意図を込めて、

  • UnboundはDockerコンテナへのみサービスする
  • Ubuntuのデフォルトで動いているsystemd-resolvedには変更を加えない

Unboundの設定ファイルunbound.confを次のように書いてみた。他のキャッシュなどに関する設定はデフォルトでいいや、と割り切っている。

$ cat /etc/unbound/unbound.conf
server:
	verbosity: 1
	num-threads: 2                 # Dockerホストが2vCPUなので
	#interface: 127.0.0.1
	interface: 172.17.0.1          # Dockerホストのdocker0のIPアドレス
	access-control: 0.0.0.0/0 refuse
	access-control: 172.16.0.0/12 allow
	do-ip6: no
forward-zone:
	name: "."
	forward-addr: AAA.BBB.CCC.DDD  # 設置環境での推奨DNS1
	forward-addr: EEE.FFF.GGG.HHH  # 設置環境での推奨DNS2
	forward-addr: 8.8.8.8          # Google Public DNS
	forward-addr: 8.8.4.4          # Google Public DNS

Unboundの動作確認

Unboundの動作確認として、次のように、1) UnboundサービスをIPアドレス「172.17.0.1」で起動させておき、2) 外部Web APIを利用するDockerコンテナを「--dns 172.17.0.1」指定付きで動かしてから、3) Unboundがキャッシュしている内容を表示させて確認してみる。

$ sudo systemctl start unbound.service

$ docker run --dns 172.17.0.1 IMAGE名

$ sudo watch unbound-control dump_cache

dump_cacheの出力結果に、Dockerコンテナが利用する外部Web APIのアクセス先となるホスト名が現れていれば、「Unboundが当該ホスト名をキャッシュしている。ということは、コンテナのプロセスがUnboundを介して当該ホスト名をDNS参照したのだろう」と推定できる。

つまり、今回の狙い通り、DockerコンテナにDNSキャッシュサーバUnboundを参照させることができているはずだ。

UnboundとDockerの起動順に注意

UnboundとDockerの起動順には注意が必要である。次のようなケースがあるため、Docker (dockerd) → Unbound → Dockerコンテナ の順に起動が行われるよう、制御する必要が出てくる。>自分への宿題

  • 上記のようにunbound.confで「interface: 172.17.0.1」という設定を行っている場合。Dockerホストでdockerdが起動していないときには、IPアドレス「172.17.0.1」も存在しないので、Unboundを起動させても起動に失敗する。

  • UnboundがサービスしていないときにDockerコンテナが起動してDNS参照を試みた場合。実験はしていないが、「--dns 172.17.0.1」指定である以上、DockerコンテナのDNS参照は失敗するんじゃなかろうか。

最近の一枚