この投稿は 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 を作って置くだけです。
[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
公式ドキュメント
余談
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
version: '2'
services:
centos:
image: centos:7
environment:
- HTTP_PROXY=${HTTP_PROXY}
公式ドキュメント
- https://docs.docker.com/engine/reference/commandline/run/#/set-environment-variables--e---env---env-file
- https://docs.docker.com/compose/compose-file/#/environment
余談
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 で、ビルド中にだけ設定する環境変数を指定しておきます。
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} .
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 が、まさにこの目的でサポートされたのがわかりますね。
公式ドキュメント
- https://docs.docker.com/engine/reference/builder/#/arg
- https://docs.docker.com/engine/reference/commandline/build/#/set-build-time-variables---build-arg
- https://docs.docker.com/compose/compose-file/#/args
余談
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 にアクセスできない、という場合の方が多そうです。
公式ドキュメント
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 サポート、期待して待ってますー。