143
122

More than 3 years have passed since last update.

日立製作所の小出です。この記事ではDockerを使う際にプロキシを設定する方法と、それに関連するDockerの挙動について説明します。

はじめに

会社からインターネットに接続するためにはプロキシを経由する必要がある、というのはありがちなシチュエーションだと思いますが、Dockerは他のツールに比べて設定につまづくポイントが多いように思います。実際、Qiitaで検索してみると、以下の件数の記事がヒットします (2019/12/5時点)。

  • yum proxy: 1281件
  • apt proxy: 1042件
  • npm proxy: 832件
  • docker proxy: 2055件

という具合で、開発者の苦労が伺えます。

また、Docker本体にたびたび設定方法や細かい挙動の変更が入ることも混乱の一因かと思われます。そこで、この記事では2019年12月現在のDocker事情を反映した設定方法を紹介したいと思います。

動作環境

この記事は以下の環境での動作を基に執筆しました。

  • Ubuntu 18.04.3 LTS (Bionic Beaver)
  • Docker 19.03.5

なお、Dockerの実行や設定にはroot権限が必要です。

TL; DR

先に結論を書いておくと、以下の設定をしておけばイメージの取得からビルド、コンテナ内のコマンド実行まで、プロキシ経由で作業できます。
192.168.0.10:8080 でプロキシサーバが動いていると仮定した場合の例を記載するので、環境に合わせてIPとポートを書き換えてください。また、認証プロキシの場合は http_proxy=http://USER:PASSWORD@example.com:8080 のような書式でユーザ名とパスワードが指定できます。

1. systemdに環境変数を設定する

systemctl edit docker で設定ファイルを開き、以下を記載します。

/etc/systemd/system/docker.service.d/override.conf
[Service]
Environment = 'http_proxy=http://192.168.0.10:8080' 'https_proxy=http://192.168.0.10:8080' # 必要なら 'no_proxy=...'

2. Dockerクライアントを設定する

~/.docker/config.json
{
  "proxies": {
    "default": {
      "httpProxy": "http://192.168.0.10:8080",
      "httpsProxy": "http://192.168.0.10:8080"
    }
  }
}

Docker proxy deep dive

ここからはなぜ上記の設定で良いのかの解説です。

dockerdとdocker

Dockerはクライアントサーバモデルのソフトウェアです。MySQLを使うときmysqldに対してmysqlコマンドで話しかけるように、Dockerはdockerdに対してdockerコマンドで話しかけることができます。プロキシもこれら2つのプログラムに対して設定する必要があります。

コンテナの中で動くプログラムに対してプロキシを設定する場合はdockerを設定し、それ以外の場合 (pullとか) はdockerdを設定する、という風に分かれているようです。

dockerdの設定

dockerdにプロキシを設定する方法は、環境変数ただ1つです。
systemctl stop docker でサービスを止めて、dockerdをフォアグラウンドで動かしてみると検証しやすいと思います。
単にdockerdコマンドを実行すると、フォアグラウンドでdockerdが起動します。

$ sudo dockerd
INFO[2019-12-05T06:46:10.612966150Z] detected 127.0.0.53 nameserver, assuming systemd-resolved, so using resolv.conf: /run/systemd/resolve/resolv.conf
<いろいろ出ますが省略>
INFO[2019-12-05T06:46:10.892366184Z] Docker daemon                                 commit=633a0ea838 graphdriver(s)=overlay2 version=19.03.5
INFO[2019-12-05T06:46:10.892416069Z] Daemon has completed initialization
INFO[2019-12-05T06:46:10.909923228Z] API listen on /var/run/docker.sock

端末をもう一つ開いて、イメージをpullしてみます。この時点では何も設定していないのでpullに失敗します。

$ sudo docker pull alpine
Using default tag: latest
Error response from daemon: Get https://registry-1.docker.io/v2/: dial tcp: lookup registry-1.docker.io: No address associated with hostname

dockerdの標準出力にも、名前解決ができずエラーになったという旨のメッセージが表示されます。

WARN[2019-12-05T07:34:29.915501297Z] Error getting v2 registry: Get https://registry-1.docker.io/v2/: dial tcp: lookup registry-1.docker.io: No address associated with hostname
INFO[2019-12-05T07:34:29.915555514Z] Attempting next endpoint for pull after error: Get https://registry-1.docker.io/v2/: dial tcp: lookup registry-1.docker.io: No address associated with hostname
ERRO[2019-12-05T07:34:29.915607313Z] Handler for POST /v1.40/images/create returned error: Get https://registry-1.docker.io/v2/: dial tcp: lookup registry-1.docker.io: No address associated with hostname

dockerdにhttp_proxy, https_proxyを渡せば、pullできるようになります。

$ export http_proxy=http://192.168.0.10:8080
$ export https_proxy=http://192.168.0.10:8080
$ sudo -E dockerd
$ sudo docker pull alpine
Using default tag: latest
latest: Pulling from library/alpine
Digest: sha256:c19173c5ada610a5989151111163d28a67368362762534d8a8121ce95cf2bd5a
Status: Downloaded newer image for alpine:latest
docker.io/library/alpine:latest

また、docker infoでdockerdが認識しているプロキシを確認することもできます。

$ sudo docker info
Client:
 Debug Mode: false

Server:
 Containers: 0
  Running: 0
<略>
 Debug Mode: false
 HTTP Proxy: http://192.168.0.10:8080
 HTTPS Proxy: http://192.168.0.10:8080
 Registry: https://index.docker.io/v1/
<略>

この時点でdocker pullがうまく動かない場合は、そもそもネットワーク設定が正しくできていない可能性が高いので、OSの流儀に従ってネットワーク設定を見直してください。

systemdの設定

上記と同じ設定をdockerサービスに反映するために、systemdのserviceファイルを編集します。

systemdの設定ファイルは /etc/systemd/system ディレクトリにあります (他にもたくさんありますが、詳細は man systemd.unit を参照してください)。このディレクトリに docker.service というファイルを作って設定を記述すれば良いのですが、プロキシ設定のような「既存の設定にプラスアルファで付け加えたい」という類のものに適したドロップインファイルという機能があるので、それを使うのがおすすめです。

以下のコマンドを実行すると、ドロップインファイルの編集画面が開きます。

$ sudo systemctl edit docker

このファイル (/etc/systemd/system/docker.service.d/override.conf) に対して、環境変数の設定を記載すれば、dockerサービスがプロキシ経由で動くようになります。

/etc/systemd/system/docker.service.d/override.conf
[Service]
Environment = "http_proxy=http://192.168.0.10:8080" "https_proxy=http://192.168.0.10:8080"

あとはサービスを起動すれば、dockerdの設定は完了です。

$ sudo systemctl start docker
$ sudo docker pull alpine
Using default tag: latest
latest: Pulling from library/alpine
Digest: sha256:c19173c5ada610a5989151111163d28a67368362762534d8a8121ce95cf2bd5a
Status: Downloaded newer image for alpine:latest
docker.io/library/alpine:latest

かつて /etc/sysconfig/docker というファイルに環境変数を設定する、という方法もありましたが、今はdeprecatedになったようです。

dockerクライアントの設定

冒頭に書いた通り、 ~/.docker/config.json に設定を書けば良いのですが、この設定方法はDocker 17.07以降で有効な設定方法で、昔のバージョンでは使えませんでした (CentOS 7のextrasリポジトリで配布されているdockerは1.13.1のようなので、この方法は使えません)。

この設定ファイルができる前は、以下のように docker run の引数で環境変数を指定したり、

$ sudo docker run -it -e http_proxy=http://192.168.0.10:8080 -e https_proxy=http://192.168.0.10:8080 alpine
/ # wget https://qiita.com

コンテナの中で環境変数を設定していました。もちろん今でもこれらの方法は有効です。

$ sudo docker run -it alpine
/ # export http_proxy=http://192.168.0.10:8080
/ # export https_proxy=http://192.168.0.10:8080
/ # wget https://qiita.com

~/.docker/config.json にプロキシ設定を書いておくと、自動的に上記の環境変数を設定してくれます (大文字のHTTP_PROXY, HTTPS_PROXYも設定されます)。

$ sudo docker run -it alpine # ~/.docker/config.json を記載した上で起動
/ # env
HTTPS_PROXY=http://192.168.0.10:8080
HOSTNAME=e60420de06d3
SHLVL=1
HOME=/root
https_proxy=http://192.168.0.10:8080
http_proxy=http://192.168.0.10:8080
TERM=xterm
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
HTTP_PROXY=http://192.168.0.10:8080

ただし、環境変数が設定されるのはコンテナの生成時なので、起動済みのコンテナにexecするときは設定されません。

$ mv ~/.docker/config.json{,.bak} # ファイルをリネームして設定を無効化
$ sudo docker run -itd --name alpine alpine
$ mv ~/.docker/config.json{.bak,} # 有効化
$ sudo docker exec -it alpine ash
/ # env
<http_proxy は表示されない>

docker build

先述した設定がしてあれば、ビルド時に特別何かする必要はありません。「あれ? --build-arg でプロキシ指定するんじゃないの?」と思った方もいるかもしれません。もちろん指定しても動きますが、 ~/.docker/config.json で指定してあれば不要です。

ちなみに、17.05より前のバージョンでは --build-arg に指定した内容が docker history に漏れなく残っていたので、認証プロキシを使っているとどうしてもイメージにユーザ名やパスワードが残ってしまう問題がありました。17.06以降のバージョンであれば、 --build-arg を使う方法でも、~/.docker/config.json に指定する方法でも、イメージに情報が残ることはないので安心です (逆に残したい場合は、DockerfileにARGで明示的に指定するとhistoryに残せます)。

付録

~/.docker/config.json に書いてある "default" の部分には、dockerdが動いているマシンが指定できます。もし複数のマシンでdockerdを動かしていて、それぞれのマシンで起動するコンテナに別々のプロキシを設定したい場合は以下のように設定できます。

~/.docker/config.json
{
  "proxies": {
    "tcp://docker-host1:2375": {
      "httpProxy": "http://proxy1.example.com:8080",
      "httpsProxy": "http://proxy1.example.com:8080"
    },
    "tcp://docker-host2:2375": {
      "httpProxy": "http://proxy2.example.com:8080",
      "httpsProxy": "http://proxy2.example.com:8080"
    },
    "default": { // 2つ以外のマシンに適用される
      "httpProxy": "http://proxy.example.com:8080",
      "httpsProxy": "http://proxy.example.com:8080"
    }
  }
}

参考資料

143
122
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
143
122