プロキシの内側でDockerを使う
プロキシの内側でDockerを使おうとすると以下の問題に直面します。
- docker pullでプロキシ経由でイメージを取得させる必要がある。
- docker runでアプリ実行時にプロキシ設定を与える必要がある。
- docker buildでビルド実行時にプロキシ設定を与える必要がある。
1はデーモンの起動時に環境変数http_proxy
を与えることで解決できます。また、2はdocker runの引数に-e http_proxy=...
を与えることで解決できます。3はDockerfileに env http_proxy ...
を追記することで解決できますが、Dockerfileやイメージのポータビリティが低下します。ポータビリティが必要ない場合はこれが現実的な解決法になると思います。
本稿では、一風変わった解決法として、Dockerホストに透過型プロキシを設置する方法を説明します。この方法では2と3の問題を解決できます。
前提
- プロキシサーバは x.x.x.x:9090 とします。
- docker0ネットワークは 172.17.0.0/16 で、ホスト側のIPアドレスは 172.17.42.1 とします。(デフォルト設定)
設計
コンテナから外部にアクセスする際、DNATを適用してホストのSquidを経由するようにします。例として、コンテナ内のcurlでGoogleにアクセスする場合を以下に示します。
curl http://www.google.com/ | | DNAT rule: | Rewrites destination of the packet to 172.17.42.1:9090 | 172.17.42.1:9090 | | Squid: | Proxies the request to x.x.x.x:9090 | x.x.x.x:9090 | | www.google.com
構築
ホストのiptablesを設定します。
iptables -t nat -A PREROUTING -s 172.17.0.0/16 ! -d 172.17.0.0/16 -p tcp --dport 80 -j DNAT --to 172.17.42.1:9090
docker0ネットワークがないとエラーになるので、起動スクリプトで設定する方がよいと思います。systemdの例(/etc/systemd/system/docker-proxy-dnat.service
)を以下に示します。
[Unit] Description=Apply DNAT rule for transparent proxy After=docker.service [Service] Type=oneshot ExecStart=/usr/sbin/iptables -t nat -A PREROUTING -s 172.17.0.0/16 ! -d 172.17.0.0/16 -p tcp --dport 80 -j DNAT --to 172.17.42.1:9090 ExecStop=/usr/sbin/iptables -t nat -D PREROUTING -s 172.17.0.0/16 ! -d 172.17.0.0/16 -p tcp --dport 80 -j DNAT --to 172.17.42.1:9090 RemainAfterExit=yes [Install] WantedBy=multi-user.target
Squidをインストールして、/etc/squid/squid.conf
を設定します。
acl docker src 172.17.0.0/16 http_access allow docker http_access allow localhost http_port 172.17.42.1:9090 intercept cache_peer x.x.x.x parent 9090 0 never_direct allow all visible_hostname linux forwarded_for off request_header_access X-FORWARDED-FOR deny all request_header_access Via deny all request_header_access Cache-Control deny all
試験
コンテナ内でcurlコマンドを実行してみます。
docker run --rm centos:latest curl www.google.com
HTMLが表示されればOKです。
制約
HTTPSは透過的にプロキシできないため、従来通りhttps_proxy
を設定する必要があります。MITMすることでプロキシできなくもないですが、証明書の問題があるので難しいです。
上記のSquid設定は最小限のものなので、セキュリティ設計に応じて改良が必要です。また、Squidプロセスの監視も必要です。
Dockerプロキシ問題を解決する方法の一つとしてお役に立てば幸いです。 なお、本稿の内容は以下のGistにも書いています。