手当たり次第に書くんだ

飽きっぽいのは本能

Docker のプロキシ設定 – systemd drop-in で daemon の外部接続を制御する

プロキシ環境で Docker を使う場合、どこに proxy を設定するのかを分けて考える必要があります。

Docker CLI に proxy を設定しても、Docker daemon が外部レジストリへ到達できるとは限りません。コンテナ内に proxy を設定しても、daemon の image pull には効きません。Docker build 時の proxy も、daemon の proxy とは別の話です。

この記事では、Docker daemon の外部接続を systemd drop-in で制御する方法を中心に、daemon、container、build の proxy の違いを整理します。

Docker の proxy はどこに効くのか

Docker の proxy 設定で混乱しやすいのは、設定先によって効く範囲が違うことです。

設定対象主な用途効く範囲
Docker daemonimage pull、registry への接続dockerd の外部通信
Docker CLICLI 自体の通信基本的には client 側の動作
Container起動したコンテナ内の外部通信アプリケーションや package manager の通信
Docker buildbuild 中の package 取得RUN apt update など build step 内の通信

たとえば、docker pull nginx が失敗する場合、まず見るべきは Docker daemon の proxy 設定です。コンテナ内の HTTP_PROXY を設定しても、daemon の pull には効きません。

systemd drop-in で Docker daemon に設定する

systemd 管理の Docker では、サービスファイル本体を直接編集するのではなく、drop-in ファイルを作成して proxy を設定します。

パッケージ更新でサービスファイルが変わっても、drop-in は分離して管理できます。構成管理やレビューの観点でも、この方法の方が扱いやすいです。

sudo mkdir -p /etc/systemd/system/docker.service.d
sudo tee /etc/systemd/system/docker.service.d/proxy.conf <<'EOF'
[Service]
Environment="HTTP_PROXY=http://proxy.example.local:3128"
Environment="HTTPS_PROXY=http://proxy.example.local:3128"
Environment="NO_PROXY=localhost,127.0.0.1,::1,10.0.0.0/8,192.168.0.0/16,registry.local"
EOF

NO_PROXY には、内部レジストリ、内部 DNS、社内ネットワーク、localhost など、proxy を経由させない宛先を入れます。

設定を反映して確認する

drop-in を作成したら、systemd の設定を再読み込みし、Docker daemon を再起動します。その後、環境変数が反映されているか確認します。

sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl show --property=Environment docker
systemctl status docker --no-pager

確認時は、単に Docker が起動しているかだけでなく、Environment に proxy 設定が反映されているかを見ます。

image pull で確認する

Docker daemon の proxy 設定が必要になる代表例は、外部レジストリからの image pull です。

docker pull hello-world
docker image ls hello-world

外部レジストリへの接続が proxy 経由で許可されている場合は、pull が成功します。失敗する場合は、proxy の宛先許可、認証、証明書、DNS、Docker daemon の環境変数を分けて確認します。

container 内 proxy とは別である

Docker daemon の proxy 設定は、起動したコンテナ内のアプリケーション通信にはそのまま適用されません。

コンテナ内で aptcurl、アプリケーションが外部通信する場合は、コンテナ側にも proxy 設定が必要になることがあります。

docker run --rm -e HTTP_PROXY=http://proxy.example.local:3128 -e HTTPS_PROXY=http://proxy.example.local:3128 ubuntu:24.04 env | grep -i proxy

この設定は、container 内のプロセスが見る環境変数です。Docker daemon が image を pull するための proxy とは責務が違います。

Docker build 時の proxy も分ける

Dockerfile の build 中に package を取得する場合も、proxy の扱いを分けて考えます。

build 時だけ必要な proxy を image に残したくない場合は、build argument として渡す方が扱いやすいことがあります。

docker build --build-arg HTTP_PROXY=http://proxy.example.local:3128 --build-arg HTTPS_PROXY=http://proxy.example.local:3128 -t example/app:dev .

build 時の proxy は、Dockerfile の中で外部通信する処理に関係します。daemon の image pull、container 実行時の外部通信とは別の確認対象です。

内部レジストリと NO_PROXY

内部レジストリを使う環境では、NO_PROXY が特に重要です。

内部レジストリへの pull / push まで proxy 経由にしてしまうと、不要な経路を通ったり、証明書や名前解決の問題が増えたりします。内部向け通信は直接到達させ、外部レジストリだけ proxy 経由にする構成が自然です。

ただし、NO_PROXY の CIDR 表記や IPv6 表記の扱いは、実装によって差が出ることがあります。期待通りに除外されているかは、実際の pull / push とログで確認する必要があります。

トラブル時の確認点

Docker の proxy 問題は、単に proxy の URL が間違っているだけとは限りません。

症状確認すること
docker pull が失敗するDocker daemon の proxy、DNS、proxy 側の宛先許可
container 内の curl が失敗するcontainer 側の環境変数、アプリケーション設定
build 中の apt update が失敗するbuild argument、Dockerfile 内の proxy 設定
内部レジストリへ接続できないNO_PROXY、証明書、名前解決、レジストリの TLS
証明書エラーが出るproxy の TLS inspection、CA 証明書、Docker daemon の trust 設定

重要なのは、どの通信が失敗しているのかを分けることです。daemon の通信、container の通信、build の通信を混ぜると、設定箇所を間違えます。

まとめ

Docker の proxy 設定では、Docker daemon、container、build の責務を分けて考える必要があります。

外部レジストリから image を pull するための proxy は、Docker daemon 側に設定します。systemd 環境では、drop-in ファイルを使うと管理しやすくなります。

一方で、container 内のアプリケーション通信や Docker build 中の外部通信は別の設定対象です。内部レジストリを使う場合は、NO_PROXY で内部通信を除外する設計も重要になります。

プロキシ環境で Docker を安定して使うには、どこに proxy を設定するかではなく、どの通信を誰が行っているのかを切り分けることが重要です。

関連する記事

Docker のプロキシ設定 – systemd drop-in で daemon の外部接続を制御する

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

トップへ戻る