概要
自分の勤務先の環境では、社内のサーバーから外部のネットワークと通信する際プロキシを経由する必要がある。
各種アプリケーションを利用する際に個別にプロキシ設定が必要となる場合があるが、
Docker を利用する際も docker pull
などで外部のネットワークから docker image を取得するためにプロキシの設定が必要である。
この設定の際に、プロキシ認証のユーザー名に含まれる特殊文字の扱いで詰まったので、対処法をメモしておく。
※ docker および systemd 等については詳しくないので、不正確な記述等あれば教えてください
環境
Ubuntu 20.04
プロキシ設定の基本
まずは、docker に限定せずコマンドラインツール一般でのプロキシ設定について確認しておく。
シェルから起動する多くのコマンドラインツール (curl, wget 等) は、http_proxy
や https_proxy
という名前の環境変数からプロキシ設定を取得する。
たとえば、プロキシサーバーが proxy.example.com
でプロキシ接続に利用するポートが 8080
である場合
export http_proxy=http://proxy.example.com:8080 export https_proxy=http://proxy.example.com:8080
のように設定すれば良い。
ユーザー名、password の認証がある場合には、
export http_proxy=http://<username>:<password>@proxy.example.com:8080
のような形式にする。
プロキシ設定における特殊文字
認証情報の中に、@
のような認証情報とサーバーのアドレスを区切るのに使われている文字や、その他 HTTP の URL 上で特殊な意味を持つ文字を含む場合は注意を要する。
例えば、弊社ではユーザー名にメールアドレスを使う設定になっているが、
たとえば、メールアドレスが foo@example.com
, パスワードが 123
であるとして、
# 正しくない設定 export http_proxy=http://foo@exmaple.com:123@proxy.example.com:8080
のように書いてしまうと、ユーザー名に含まれる @
が認証情報とアドレス部分の区切り文字として解釈され、正しく設定できない。
正しく設定するには、@
を percent encoding して、
export http_proxy=http://foo%40exmaple.com:123@proxy.example.com:8080
のようにする必要がある。
Docker daemon のプロキシ設定
Docker のプロキシ設定と言っても、docker client 側と docker daemon 側それぞれについて設定が必要になる。 外部の registry から docker image をダウンロードしてくるための通信を発行したりするのは daemon 側であり、 今回はこの docker daemon 側のプロキシ設定について注目する。
公式ドキュメント含め、すでに詳しい解説は多くある。
Configure the daemon with systemd | Docker Documentation
プロキシのある環境でDockerを動かす方法 - Qiita
Set proxy on docker - Stack Overflow
簡単にまとめると、systemctl edit docker
で docker の設定ファイルを開いて
[Service]
Environment="http_proxy=http://<username>:<password>@proxy.example.com:8080"
の内容で保存し、
systemctl daemon-reload
systemctl restart docker
でデーモンを再起動すれば良い。(sudo
は必要に応じてつけること)
特殊文字に対する配慮
ユーザー名 foo@example.com
, パスワード 123
で認証情報を設定する場合、一見
# 正しくない設定 [Service] Environment="http_proxy=http://foo%40example.com:123@proxy.example.com:8080"
とすれば良さそうである。 しかし、実際この設定だと正常に動作しない。
docker の公式 documentをよく見ると、次のような注意書きがある。
Special characters in the proxy value, such as #?!()[]{}, must be double escaped using %%. For example:
[Service] Environment="HTTP_PROXY=http://domain%%5Cuser:complex%%23pass@proxy.example.com:3128/"
したがって、以下のように設定するのが正しい
# 正しい設定 [Service] Environment="http_proxy=http://foo%%40example.com:123@proxy.example.com:8080"
少しだけ深堀り
# 正しくない設定 [Service] Environment="http_proxy=http://foo%40example.com:123@proxy.example.com:8080"
だと何がまずいのか、原因を探ってみる。 この状態で、
systemctl show docker --property=Environment
を叩いて設定を確認すると、Environment=
と空になっている様子である。
/var/log/syslog
(または /var/log/messages
) を確認すると、以下のようなエラーが確認できる。(一部加工している)
Jul 28 10:39:12 <hostname> systemd[1]: /etc/systemd/system/docker.service.d/override.conf:2: Failed to resolve specifiers in http_proxy=http://foo%40example.com:123@proxy.example.com:8080, ignoring: Invalid slot
failed to resolve specifier
と、specifier が解釈できないという趣旨のエラーが見れる。
調べてみると、systemd の設定ファイル内では %
から始まる文字列が "specifier" として特別に解釈されるらしく、
%
そのものの文字を埋め込みたい場合には、%%
のように重ねて書く必要があるということらしい。
詳しい documentation は以下にある。