Help us understand the problem. What is going on with this article?

防火壁の中の Docker

More than 3 years have passed since last update.

この投稿は Fujitsu Advent Calender 2016 の 9日目 の記事です。
この記事に書かれた見解は、個人のものであり、所属する会社・組織を代表するものではありません。


proxy に阻まれて Docker が思うように動かないという声を、他のソフトと比べるとよく聞きます。Docker の場合、proxy を意識しなければいけない箇所が少なくとも4つあって、何をしたいかによって、そのうちのどれを設定しないといけないかが変わるので、混乱しやすいのでしょう。加えて、公式ドキュメントに、その4つをまとめて説明してくれるページがないのも、それを助長しているのかもしれません。
そこで、その4つをまとめて説明してみます。

以下の説明で、proxy の URL や、NO_PROXY に設定するドメイン名/IPアドレスは、各自の環境に合わせて読み替えてください。

1. docker pull/push したい

Docker daemon に設定します。
daemon プロセスの環境変数 (HTTP_PROXY, HTTPS_PROXY, NO_PROXY) に設定してあれば効きます。
daemon を systemd で起動している場合は、公式ドキュメントに従って、
/etc/systemd/system/docker.service.d (なければ掘る) の下に、以下のような内容の http-proxy.conf を作って置くだけです。

http-proxy.conf
[Service]
Environment="HTTP_PROXY=http://proxy.hogehoge.com:8080/" "HTTPS_PROXY=https://proxy.hogehoge.com:8080/" "NO_PROXY=localhost,127.0.0.1,.hogehoge.com"

作ったあと

systemctl daemon-reload
systemctl restart docker

をお忘れなく。

正しく設定できていれば、docker info で最後の方に以下のように出ます。

Http Proxy: http://proxy.hogehoge.com:8080/
Https Proxy: https://proxy.hogehoge.com:8080/
No Proxy: localhost,127.0.0.1,.hogehoge.com

公式ドキュメント

https://docs.docker.com/engine/admin/systemd/#/http-proxy

余談

swarm mode でノードにアクセスするときも、この設定が効くかも。(swarm mode が daemon に入った v1.12 以降をいまだに触れてないのでよくわかりません。すいません。)
proxy のこっち側のノードのアドレスを NO_PROXY に設定しておかないと、proxy を越えてアクセスしに行ってエラーになり (そうな気がし) ます。

2. コンテナの中から curl したり git clone したりしたい

コンテナ内の環境変数 (HTTP_PROXY, HTTPS_PROXY, NO_PROXY、Java なやつは _JAVA_OPTIONS など) に設定しておけば、たいていのやつはいけます。
docker run --env か docker-compose.yml の environment: でコンテナ実行時に設定します。docker/docker-compose を起動するプロセスの環境変数に HTTP_PROXY などが設定されていれば、それをそのまま使うと楽ちん。

docker run --env HTTP_PROXY=${HTTP_PROXY} -it centos:7 bash
docker-compose.yml
version: '2'
services:
  centos:
    image: centos:7
    environment:
    - HTTP_PROXY=${HTTP_PROXY}

公式ドキュメント

余談

Dockerfile の ENV に書いてビルドしてしまってもいいのですが、そうすると、イメージに環境変数が焼き込まれてしまいます。会社固有の proxy URL や、まして認証 proxy のクレデンシャルが入ったイメージとか、社外には配布できませんから、お勧めしません。
かつて、Dockerfile で UNSETENV HTTP_PROXY みたいに書いて環境変数を unset した上で、環境変数が残ったレイヤーを潰す (squash) という PR もあったのですが、前者の PRは、レビューの結果、まっとうなユースケースが考えられないという理由でクローズされました。後者の PR は v1.13 で experimental として入るようです。

3. Docker build 中に yum install とか curl とか git clone とかしたい

build-arg を使います。
まず、Dockerfile に ARG で、ビルド中にだけ設定する環境変数を指定しておきます。

Dockerfile
ARG HTTP_PROXY

次に、docker build--build-arg オプションか、docker-compose.yml の build: オプションの args: で、ビルド環境変数の値を指定します。
ここでも、docker/docker-compose を起動するプロセスの環境変数が設定されていれば、それをそのまま使えます。

docker build -t myimage --build-arg HTTP_PROXY=${HTTP_PROXY} .
docker-compose.yml
version: '2'
services:
  myimage:
    build:
      context: .
      args:
      - HTTP_PROXY=${HTTP_PROXY}

Dockerfile の ARG で指定していない環境変数を docker build --build-arg や docker-compose.yml で指定するとエラーになります。ただし、HTTP_PROXY など proxy 関係の環境変数は predefine されています。つまり、ARG で指定していなくても、docker build や docker-compose.yml で指定できます。build-arg が、まさにこの目的でサポートされたのがわかりますね。

公式ドキュメント

余談

build 中のコンテナには、docker run のように --env を渡せません。なので、v1.9.0 以前は Dockerfile に ENV で指定するしかなかったのですが、前項で書いたようにイメージに環境変数が残ってしまいます。前述の PR がクローズされた代わりかどうかわかりませんが、v1.9.0 から build-arg がサポート されました。

4. Docker CLI からリモートの daemon を操作したい

CLI のプロセスの環境変数 (HTTP_PROXY, HTTPS_PROXY, NO_PROXY) に設定してあれば効きます。

export HTTP_PROXY="http://proxy.hogehoge.com:8080/"
export NO_PROXY="localhost,127.0.0.1,.hogehoge.com"

proxy の向こうの daemon を操作するというよりは、NO_PROXY をちゃんと設定しておかないと proxy のこっち側の daemon にアクセスできない、という場合の方が多そうです。

公式ドキュメント

https://docs.docker.com/engine/reference/commandline/cli/#/environment-variables

5. 全部に共通の注意事項

5.1 NO_PROXY に IP アドレスを指定する場合

NO_PROXY に IP アドレス を指定する際、CIDR記法やワイルドカードは書けない、というか、書いても効きません。

NO_PROXY=localhost,127.0.0.1,.hogehoge.com,10.0.0.0/8
NO_PROXY=localhost,127.0.0.1,.hogehoge.com,10.*
NO_PROXY=localhost,127.0.0.1,.hogehoge.com,10.

のように書いてもだめということ。IP アドレスは、手書きなり、シェルスクリプトで展開するなりして、個別アドレスを全部列挙するしかありません。

余談

CIDR記法がサポートされていない理由が「curl も wget もサポートしていない、つまり非標準だから」って言うんだけど、curl や wget と一緒になって、みんな一斉にサポートしよー、ってならないもんですかねぇ。(他力本願
https://github.com/docker/docker/issues/9145
https://github.com/docker/docker/issues/19256

5.2 認証 proxy のクレデンシャル

認証 proxy のクレデンシャルは、URL に書けば、たいていの場合効きます。

HTTP_PROXY=http://proxy-user:proxy-pw@proxy.hogehoge.com:8080/

Java なやつは、

_JAVA_OPTIONS="-Dhttp.proxyUser=proxy-user -Dhttp.proxyPassword=proxy-pw -Dhttp.proxyPort=8080 -Dhttp.proxyHost=proxy.hogehoge.com -
Dhttp.nonProxyHosts=localhost|127.0.0.1|*.hogehoge.com"

みたいに、オプションで -D しないとだめなようです。(私は、Java に関してはからっきし知識がないので、つっこみはご容赦のほどを...)

あとアがき

このところ手を動かせてなくて、ずいぶん前に書いた Dockerfile やら docker-compose.yml やらと、公式ドキュメントと、首っぴきで思い出しながら書いてみました。不備や誤りにお気づきの場合は、お手数ですが編集リクエストを投げていただけましたら、謹んで訂正させていただきます。

ちなみに関係ないけど、この記事はせっかくなので Kobito で書いたのですが、残念ながら Kobito さんは proxy を通過してくれなかったので、やむなく md ソースをコピペしました。proxy サポート、期待して待ってますー。

jeffi7
fujitsu
富士通グループのソフトウェア技術者有志により運営しているコミュニティです。
http://www.fujitsu.com/jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away