タワ記

気が向いた時にだけ書く、技術メモっぽいもの。

Proxy配下のUbuntu DesktopでDockerを動かした時に地味にハマった。

※この記事はUbuntu 16.04(Desktopのみ)を前提として記載しています。

この記事に書いてあること

  • Proxy配下にあるUbuntu 16.04 DesktopでDockerを動かした際にプロキシとネームサーバー関連の設定で困ったよ。

Docker

Dockerは言わずと知れた、コンテナ型仮想環境を利用するためのソフトウェアです。
詳細についてはここでは述べませんので、必要のある方はググってくださいませ。

Proxy配下のUbuntu DesktopでDockerを使いたい

Ubuntu Desktopを使っているけど、「手元環境上において、Docker Hubで環境が提供されているようなサービスを試食したい」というケースがあると思います。
個人のプライベートな環境ではおそらく問題になりませんが、企業内では当該の環境がProxyの配下におり、直接外には出られないことも多いのではないでしょうか。

docker pullができない

Proxy配下だと、Docker pullができなくていきなりハマります。
これについてはすでに触れられている方がいらっしゃいましたので、リンクを貼っておきます。
要はdockerdを起動するときに、環境変数HTTP_PROXYを適切に設定しておけばよい、ということになります。
qiita.com

コンテナ環境からDNSによる名前解決ができない

Dockerはよくできていて、DNS設定が書かれている/etc/resolv.confは、通常ですとホスト環境の/etc/resolv.confを利用するようになってます。
したがって特に何もしなくても、Dockerホストの環境上で名前解決ができている場合には、コンテナ側からも問題なく動作するはずです。
ところが、Ubuntu DesktopをDockerホストにした場合、/etc/resolv.confを見ると・・・

# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN

nameserver 8.8.8.8
nameserver 8.8.4.4

Google Public DNSを見に行くように設定されてしまいます。これらのアドレスへ直接アクセスできるネットワーク環境であれば問題にはなりませんが、Proxy配下にあるような場合は到達できず、名前解決ができません。

なぜGoogle Public DNSを見に行く設定になるのか

先ほども述べましたが、通常ですとホスト環境の/etc/resolv.confが利用されます。それがなぜ勝手にGoogle Public DNSになってしまうのでしょうか。
答えはsyslogに残っていました。

Feb 11 20:40:22 ubuntu-vm systemd[1]: Starting Docker Application Container Engine...
Feb 11 20:40:22 ubuntu-vm dockerd[7191]: time="2018-02-11T20:40:22.491330975+09:00" level=info msg="libcontainerd: new containerd process, pid: 7199"
.. 省略 ..
Feb 11 20:40:53 ubuntu-vm dockerd[7191]: time="2018-02-11T20:40:53.648196834+09:00" 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]"

「(ホストの)resolv.confの中にlocalhost以外のDNSサーバーがないから、8.8.8.8と8.8.4.4を使うよ」ということでした。
つまりホスト上のresolv.confと同じ内容にすると、自ら(localhost=自コンテナ)に対して名前問い合わせをすることになります。
一般的には(DNS機能のない)自らに問い合わせをしたところでエラーになるだけなので、代わりにGoole Public DNSを設定しておく仕様にしたのでしょうか。

なぜUbuntu Desktopのresolv.confは自分を指しているのか

ホスト環境の/etc/resolv.confでは、DNSとして127.0.1.1(自分)を引くようになっています。これはUbuntu Desktopが標準で抱えるNetwork ManagerがDNSのキャッシュを行っているので、それを利用するためです。
Ubuntu Desktopのデフォルトでは、DNSキャッシュはNetwork Manager管理下のdnsmasqが行なっています。
(なお厳密にはデフォルト設定だと「キャッシュ」は行なっておらず、単にForwarderとして動作しているだけだったりします)

Dockerホストに対してDNS問い合わせしたい

ホスト上にはDNSキャッシュが動いていますので、コンテナ側からはホストに対して問い合わせをすれば、期待通りに動きそうです。
そのためコンテナを起動する際に、--dnsオプションを使ってDockerホストのアドレスを(ここではホスト上のインターフェースdocker0が172.17.0.1の場合を例として)指定します。
以下、Docker Hub上のbusyboxイメージを使う場合で例示しています。

# docker run -it --dns=172.17.0.1 --rm busybox
/ # cat /etc/resolv.conf 
nameserver 172.17.0.1
/ # 

/etc/resolv.confが書き換わりました。これで引けるかと思いきや、ホスト側のdnsmasqはデフォルトでは127.0.1.1しかlistenしていません。
したがって、これだけですと問い合わせてもエラーとなりますので、172.17.0.1もlistenするように設定を追加する必要があります。
追加設定はホストの/etc/NetworkManager/dnsmasq.dにファイルを追加することで行います。
ここではdocker0というファイルを追加することにします。

# vim /etc/NetworkManager/dnsmasq.d/docker0

中身は以下のようにします。

listen-address=172.17.0.1

ファイルを作成したら、NetworkManagerを再起動します。

# systemctl restart network-manager.service

では、試してみましょう。

# docker run -it --dns=172.17.0.1 --rm busybox
/ # nslookup www.google.com
Server:    172.17.0.1
Address 1: 172.17.0.1

Name:      www.google.com
Address 1: 2404:6800:400a:809::2004 kix05s02-in-x04.1e100.net
Address 2: 216.58.199.228 kix05s02-in-f4.1e100.net
/ # 

期待通り、名前解決することができました。