これは、なにをしたくて書いたもの?
Dockerコンテナ内で、たまに名前解決できなくて困ることがあります。
それを、Dockerイメージをビルドする時に同じようにハマったら、どうしましょうか?という話。
環境
今回の環境は、こちら。Ubuntu Linux 18.04 LTS。
$ uname -srvmpio Linux 4.18.0-25-generic #26~18.04.1-Ubuntu SMP Thu Jun 27 07:28:31 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 18.04.4 LTS Release: 18.04 Codename: bionic $ docker -v Docker version 19.03.8, build afacb8b7f0
まずは、コンテナ実行時を確認してみる
Ubuntu Linuxのlatestイメージを起動してみます。
$ docker container run -it --rm ubuntu:latest bash
現時点では、実質Ubuntu Linux 18.04 LTSです。
# cat /etc/os-release NAME="Ubuntu" VERSION="18.04.4 LTS (Bionic Beaver)" ID=ubuntu ID_LIKE=debian PRETTY_NAME="Ubuntu 18.04.4 LTS" VERSION_ID="18.04" HOME_URL="https://www.ubuntu.com/" SUPPORT_URL="https://help.ubuntu.com/" BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" VERSION_CODENAME=bionic UBUNTU_CODENAME=bionic
ここで、apt updateしてみると…失敗する時があります。
# apt update -y Err:1 http://security.ubuntu.com/ubuntu bionic-security InRelease Temporary failure resolving 'security.ubuntu.com' Err:2 http://archive.ubuntu.com/ubuntu bionic InRelease Temporary failure resolving 'archive.ubuntu.com' Err:3 http://archive.ubuntu.com/ubuntu bionic-updates InRelease Temporary failure resolving 'archive.ubuntu.com' Err:4 http://archive.ubuntu.com/ubuntu bionic-backports InRelease Temporary failure resolving 'archive.ubuntu.com' Reading package lists... Done Building dependency tree Reading state information... Done All packages are up to date. W: Failed to fetch http://archive.ubuntu.com/ubuntu/dists/bionic/InRelease Temporary failure resolving 'archive.ubuntu.com' W: Failed to fetch http://archive.ubuntu.com/ubuntu/dists/bionic-updates/InRelease Temporary failure resolving 'archive.ubuntu.com' W: Failed to fetch http://archive.ubuntu.com/ubuntu/dists/bionic-backports/InRelease Temporary failure resolving 'archive.ubuntu.com' W: Failed to fetch http://security.ubuntu.com/ubuntu/dists/bionic-security/InRelease Temporary failure resolving 'security.ubuntu.com' W: Some index files failed to download. They have been ignored, or old ones used instead.
名前解決ができていないようです。
このような場合は、コンテナ内で/etc/resolv.confを修正してDNSサーバーを設定してあげるか、
# echo 'nameserver 8.8.8.8' >> /etc/resolv.conf
コンテナ起動時に「--dns」オプションでDNSサーバーを指定すれば解決します。
$ docker container run -it --rm --dns 8.8.8.8 ubuntu:latest bash
やるなら、後者ですよね。
docker image build時にどうしましょう
ところで、これと同じ事象が「docker image build」時に発生すると、けっこう困ります。
「docker image build」には、「--dns」オプションがないからです。
たとえば、ちょっと適当ですがこんなDockerfileを用意。
Dockerfile
FROM ubuntu:latest RUN apt-get update -y && \ apt-get install -y apache2 EXPOSE 80 ENTRYPOINT service apache2 start && tail -f /dev/null
Dockerイメージをビルドしてみます。
$ docker image build -t kazuhira/apache2:latest . Sending build context to Docker daemon 2.048kB Step 1/4 : FROM ubuntu:latest ---> 4e5021d210f6 Step 2/4 : RUN apt-get update -y && apt-get install -y apache2 ---> Running in 4d98785d4719 Err:1 http://archive.ubuntu.com/ubuntu bionic InRelease Temporary failure resolving 'archive.ubuntu.com' Err:2 http://security.ubuntu.com/ubuntu bionic-security InRelease Temporary failure resolving 'security.ubuntu.com' Err:3 http://archive.ubuntu.com/ubuntu bionic-updates InRelease Temporary failure resolving 'archive.ubuntu.com' Err:4 http://archive.ubuntu.com/ubuntu bionic-backports InRelease Temporary failure resolving 'archive.ubuntu.com' Reading package lists... W: Failed to fetch http://archive.ubuntu.com/ubuntu/dists/bionic/InRelease Temporary failure resolving 'archive.ubuntu.com' W: Failed to fetch http://archive.ubuntu.com/ubuntu/dists/bionic-updates/InRelease Temporary failure resolving 'archive.ubuntu.com' W: Failed to fetch http://archive.ubuntu.com/ubuntu/dists/bionic-backports/InRelease Temporary failure resolving 'archive.ubuntu.com' W: Failed to fetch http://security.ubuntu.com/ubuntu/dists/bionic-security/InRelease Temporary failure resolving 'security.ubuntu.com' W: Some index files failed to download. They have been ignored, or old ones used instead. Reading package lists... Building dependency tree... Reading state information... E: Unable to locate package apache2 The command '/bin/sh -c apt-get update -y && apt-get install -y apache2' returned a non-zero code: 100
まあ、コンテナ実行時に失敗していたのだから、こちらもやっぱり失敗します。
さて、どうしましょう。
Dockerfileで/etc/resolv.confを修正する
単純には、Dockerfile内で/etc/resolv.confを修正します。
RUN echo 'nameserver 8.8.8.8' >> /etc/resolv.conf && \ apt-get update -y && \ apt-get install -y apache2
これでうまくいくにはいきますが、ちょっと嫌です。
また、RUN命令を跨ぐとうまくいかなかったりします。
Dockerデーモンのオプションに「--dns」を指定する
Dockerデーモンの起動オプションには「--dns」が使えるので、こちらで回避する選択肢もありそうです。
手元の環境では、Dockerデーモンはsystemdで管理されているので、サービスユニット定義ファイルの「ExecStart」を修正して、
「--dns」オプションを加えます。
/etc/systemd/system/multi-user.target.wants/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --dns 8.8.8.8
設定変更を反映して、Dockerデーモンを再起動。
$ sudo systemctl daemon-reload $ sudo systemctl restart docker
これで、Dockerコンテナ内で利用するDNSサーバーが変わります。
とはいえ、起動オプションに設定するのもなぁ、と。
ホスト側のネットワークを使う
もうひとつ思ったのが、ホスト側のネットワークを使って問題ない場合は、ホスト側のネットワークを使ってビルドすればよいのでは?と。
幸い、「docker image build」には「--network」オプションはあるので。こんな感じで。
$ docker image build --network host -t kazuhira/apache2:latest .
これでもうまく行きます。
まあ、今後これで困った場合は、ホストネットワークでビルドですかねぇ。
オマケ
この話に関するissueがありました。
Support --dns or --addn-hosts for docker build · Issue #5779 · moby/moby · GitHub
結局、ここで書いた内容と似たようなことを言っています。
・ configure the daemon to use a different default DNS for containers (this can be configured through daemon.json)
・ use a custom network for your containers (and during build), so that the embedded DNS is used, which allows forwarding requests to the 127.0.0.x DNS server in the host's networking namespace
・ use --network=host to make the container run in the host's networking namespace
Dockerデーモンの設定を変更する、DNSを組み込んだカスタムネットワークを作成して使う、ホスト側のネットワークを使う。
2つ目はやっていませんが、まあいいかな、と。