企業ネットワーク、アクセス制限のあるサーバーでDockerを使用している、または特定のIPを介してコンテナがインターネットに接続する必要がある場合、正しいプロキシ設定がなければDockerはDocker Hubや他のレジストリからイメージをダウンロードできません。この記事では、デーモンから個別のコンテナまで、すべてのプロキシ設定のレベルを解説します。
なぜDockerにプロキシが必要なのか
Dockerは常に外部リソースにアクセスするツールです。docker pullやdocker buildのたびに、デーモンはDocker Hub、GitHub Container Registry、Google Container Registry、またはあなたのプライベートレジストリにアクセスします。ここで問題が発生します。
プロキシなしでは対処できない状況:
- ファイアウォールのある企業ネットワーク — すべてのトラフィックは企業のプロキシサーバーを通過する必要があり、そうでなければ接続がブロックされます。
- 地理的制限 — Docker Hubや特定のレジストリがあなたの国やデータセンターからはアクセスできません。
- インターネットへの直接アクセスがない制限されたサーバー — ゲートウェイを通じてのみインターネットにアクセスできる閉じたネットワークのVPS。
- コンテナのアウトバウンドトラフィックの制御 — コンテナ内のアプリケーションが特定のIPを介してネットワークにアクセスするようにしたい(例えば、パース、APIリクエスト、地理的に依存するコンテンツのテストなど)。
- リクエストの匿名化 — コンテナから外部サービスにアクセスする際にサーバーの実際のIPを隠す。
- レート制限 — Docker Hubは匿名ユーザーに対してプルリクエストの数を制限します(6時間で100プル)。IPのローテーションを使用したプロキシを介してこの制限を回避できます。
Dockerは単一のアプリケーションではなく、複数のコンポーネントからなるシステムであることを理解することが重要です。デーモン(dockerd)はホスト上で動作し、イメージをプルします。コンテナは独自のネットワーク設定を持つ隔離されたプロセスです。したがって、デーモンとコンテナのためのプロキシ設定は異なるタスクであり、異なる方法で解決されます。
Dockerのプロキシの3つのレベル
設定ファイルに入る前に、アーキテクチャを理解する必要があります。Dockerには、各々が独立したプロキシ設定を必要とする3つのレベルがあります:
| レベル | 何をするか | どこで設定するか |
|---|---|---|
| Dockerデーモン | イメージをダウンロードする(docker pull)、レジストリにアクセスする | systemdオーバーライドまたはdaemon.json |
| Dockerビルド | イメージビルド時のコマンドを実行する(RUN apt-get、pip installなど) | DockerfileのARGとENVまたは--build-arg |
| 実行中のコンテナ | HTTPリクエストを行う実行中のアプリケーション | docker run時のENVまたはdocker-compose.ymlで |
一般的な間違いは、1つのレベルにのみプロキシを設定し、なぜイメージが引き続きダウンロードできないのか、またはアプリケーションがプロキシを認識しないのかに驚くことです。それぞれのレベルを詳しく見ていきましょう。
Dockerデーモンのためのプロキシ設定(イメージのプル)
これは、プロキシを介してイメージをプルしたい場合に最も重要な設定です。Dockerデーモンはsystemdを介して起動されるシステムサービスです。ユーザーやrootの環境変数は認識しません。プロキシをサービスの環境に渡す必要があります。
方法1: systemdオーバーライドを使用する(推奨)
サービス設定をオーバーライドするためのディレクトリを作成します:
sudo mkdir -p /etc/systemd/system/docker.service.d
次の内容でファイル/etc/systemd/system/docker.service.d/http-proxy.confを作成します:
[Service] Environment="HTTP_PROXY=http://username:password@proxy-host:port" Environment="HTTPS_PROXY=http://username:password@proxy-host:port" Environment="NO_PROXY=localhost,127.0.0.1,::1,your-private-registry.example.com"
プロキシが認証なしの場合は、username:password@を削除します。ファイルを作成したら、systemdの設定をリロードし、Dockerを再起動します:
sudo systemctl daemon-reload sudo systemctl restart docker
設定が適用されたことを確認します:
sudo systemctl show --property=Environment docker
出力には、あなたの変数HTTP_PROXYとHTTPS_PROXYが表示されるはずです。
方法2: ~/.docker/config.jsonを使用する(Docker Desktopおよび新しいバージョン)
Docker Engine 23.0以降、クライアント設定ファイルを介してプロキシを設定するより便利な方法が登場しました。ファイル~/.docker/config.jsonを作成または編集します:
{
"proxies": {
"default": {
"httpProxy": "http://username:password@proxy-host:port",
"httpsProxy": "http://username:password@proxy-host:port",
"noProxy": "localhost,127.0.0.1,::1"
}
}
}
この方法は、root権限を必要とせず、デーモンを再起動する必要がないため便利です。設定は自動的にビルド時にコンテナに渡されます。ただし、デーモン自体のプルリクエストを管理するには、systemdを介した方法が必要です。
💡 NO_PROXYについて重要なこと
常にNO_PROXYに内部レジストリとサービスのアドレスを追加してください。そうしないと、Dockerはプロキシを介してそれらにアクセスしようとし、接続エラーが発生します。一般的なリスト:localhost,127.0.0.1,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
ビルド時のコンテナ内プロキシ
Dockerがイメージをビルドし、RUN apt-get install、RUN pip install、またはRUN npm installのようなコマンドを実行すると、これらのコマンドは一時的なコンテナ内で実行されます。デフォルトではホストのプロキシにアクセスできません。ビルド引数を介してプロキシを明示的に渡す必要があります。
--build-argを介してプロキシを渡す
docker build \ --build-arg HTTP_PROXY=http://proxy-host:port \ --build-arg HTTPS_PROXY=http://proxy-host:port \ --build-arg NO_PROXY=localhost,127.0.0.1 \ -t my-image .
Dockerfileでの設定
プロキシがビルド時のみ必要で、最終イメージに含めたくない場合は、ARGを使用し、ENVは使用しないでください:
FROM ubuntu:22.04 # ビルド引数を宣言 ARG HTTP_PROXY ARG HTTPS_PROXY ARG NO_PROXY # コマンドで使用 RUN apt-get update && apt-get install -y curl wget # このブロックの後、プロキシはコンテナのENVに含まれません
もしプロキシが実行中のコンテナでも必要な場合は、ENVを使用します:
FROM python:3.11 ENV HTTP_PROXY=http://proxy-host:port ENV HTTPS_PROXY=http://proxy-host:port ENV NO_PROXY=localhost,127.0.0.1 RUN pip install requests beautifulsoup4 CMD ["python", "app.py"]
⚠️ 注意:セキュリティ
公開される可能性のあるイメージやリポジトリにDockerfileにプロキシのログイン情報やパスワードをハードコーディングしないでください。--build-argを使用し、CI/CDシステムの環境変数から値を渡してください。docker historyコマンドはARGの値を表示できるため、秘密情報にはDocker BuildKitのシークレットを使用してください。
実行中のコンテナのためのプロキシ
これは、HTTPリクエストを行うアプリケーションにとって最も一般的なシナリオです。パーサー、ボット、特定のIPを介して出力する必要があるマイクロサービスなどです。ここでの設定は非常に簡単です:コンテナを起動する際に環境変数を渡す必要があります。
docker runを介して
docker run \ -e HTTP_PROXY=http://username:password@proxy-host:port \ -e HTTPS_PROXY=http://username:password@proxy-host:port \ -e NO_PROXY=localhost,127.0.0.1 \ my-image
人気のあるHTTPライブラリのほとんどは、自動的にHTTP_PROXYとHTTPS_PROXYの変数を取得します:Pythonのrequests、curl、wget、Goのnet/http、Node.jsのhttps-proxy-agentなど。コードに何も追加する必要はありません。
.envファイルを介して
設定を.envファイルに保存し、全体を渡すのが便利です:
# .envファイル HTTP_PROXY=http://username:password@proxy-host:port HTTPS_PROXY=http://username:password@proxy-host:port NO_PROXY=localhost,127.0.0.1
docker run --env-file .env my-image
コンテナ内のSOCKS5プロキシ
SOCKS5プロキシを使用している場合(例えば、住宅用プロキシは通常このプロトコルをサポートしています)、構文は少し異なります:
docker run \ -e ALL_PROXY=socks5://username:password@proxy-host:port \ my-image
注意:すべてのライブラリが追加の依存関係なしに環境変数経由でSOCKS5をサポートしているわけではありません。Pythonのrequestsはrequests[socks]をインストールする必要がありますし、curlはlibcurl-socksのサポートでビルドされる必要があります。
Docker Composeのプロキシ
実際のプロジェクトでは、単純にdocker runを使用することは稀です。通常はDocker Composeを使用し、複数のサービスが1つのファイルに記述されています。ここでのプロキシ設定は、各サービスのレベルまたは変数ファイルを介して行います。
オプション1: docker-compose.ymlのenvironment
version: '3.8'
services:
scraper:
image: my-scraper:latest
environment:
- HTTP_PROXY=http://username:password@proxy-host:port
- HTTPS_PROXY=http://username:password@proxy-host:port
- NO_PROXY=localhost,127.0.0.1
restart: unless-stopped
api:
image: my-api:latest
# このサービスはプロキシなしで、内部リソースにのみアクセスします
ports:
- "8080:8080"
オプション2: .envファイルを介して(推奨)
.envをdocker-compose.ymlのディレクトリに作成します。Docker Composeはこのファイルを自動的に取得します:
# .env PROXY_HOST=proxy-host PROXY_PORT=8080 PROXY_USER=username PROXY_PASS=password
version: '3.8'
services:
scraper:
image: my-scraper:latest
environment:
- HTTP_PROXY=http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}
- HTTPS_PROXY=http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}
- NO_PROXY=localhost,127.0.0.1
Composeでのビルド時のプロキシ
Composeにbuildセクションがあり、ビルド時にプロキシを渡す必要がある場合:
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
args:
HTTP_PROXY: http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}
HTTPS_PROXY: http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}
environment:
- HTTP_PROXY=http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}
- HTTPS_PROXY=http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}
Dockerに適したプロキシの種類
プロキシの種類の選択は、タスクによって異なります。Docker環境に関連する3つの主要なタイプがあり、それぞれに特定のニッチがあります:
| プロキシの種類 | 速度 | 匿名性 | Dockerに最適なシナリオ |
|---|---|---|---|
| データセンター | ⚡ 高速 | 中程度 | イメージのプル、CI/CDパイプライン、Docker Hubのレート制限の回避 |
| 住宅用 | 🔄 中程度 | 高い | 保護されたサイトのパース、地理的制限のあるAPI、テスト |
| モバイル | 🔄 中程度 | 最大 | モバイルAPI(Instagram、TikTok)を使用するアプリケーション |
イメージのプルとCI/CDには、データセンターのプロキシが最適です。これにより、大きなイメージ(数ギガバイト)のダウンロード時に最大速度と安定した接続が提供されます。
パーサーコンテナには、サイトの保護を回避し、通常のユーザーとして見えるようにするために、住宅用プロキシが適しています。これにより、実際の家庭ユーザーのIPが使用され、集中的なリクエストでもブロックされる可能性が低くなります。
モバイルプラットフォームで動作するアプリケーション(Instagram Graph API、TikTok API、サービスのモバイルバージョン)には、モバイルプロキシを検討する価値があります。これにより、携帯電話の通信事業者のIPが使用され、ボット対策システムによる疑いが最小限に抑えられます。
プロトコル:HTTP vs SOCKS5
DockerデーモンはHTTP/HTTPSプロキシのみをサポートしており、イメージのプルにはSOCKS5は機能しません。SOCKS5プロキシを使用してイメージをダウンロードする必要がある場合は、privoxyやmicrosocksのようなローカルコンバータを使用して、HTTPを受け取りSOCKS5を介してプロキシする必要があります。
実行中のコンテナの場合、状況は改善されます。ほとんどのHTTPライブラリは、ALL_PROXY=socks5://...を介してSOCKS5を直接サポートしています。
よくあるエラーとその修正方法
Dockerでのプロキシ設定時に直面する最も一般的な問題を解説します:
エラー1: プロキシがホストに設定されているがDockerが認識しない
症状:
Error response from daemon: Get "https://registry-1.docker.io/v2/": dial tcp: connection refused
原因: Dockerデーモンはシステムサービスとして起動され、現在のユーザーの環境変数を継承しません。たとえターミナルでexport HTTPS_PROXY=...を設定してもです。
解決策: 上記の方法1を使用してsystemdオーバーライドを介してプロキシを設定します。必ずsystemctl daemon-reload && systemctl restart dockerを実行してください。
エラー2: apt-get / pip / npmがビルド時に動作しない
症状:
Err:1 http://archive.ubuntu.com/ubuntu focal InRelease
Could not connect to archive.ubuntu.com:80
原因: デーモンのプロキシ設定は、Dockerfile内のRUNコマンドには自動的に適用されません。これは異なるコンテキストです。
解決策: プロキシを--build-argを介して渡すか、~/.docker/config.jsonを使用してproxiesセクションを設定します(Docker 23.0+、自動的にビルド時に引数を渡します)。
エラー3: 内部サービスがプロキシを介してアクセスできない
症状:
curl: (7) Failed to connect to internal-service.local port 8080: Connection refused
原因: プロキシは外部からアクセスできない内部アドレスへのリクエストをプロキシしようとします。
解決策: すべての内部ドメインとサブネットをNO_PROXYに追加します。企業ネットワークの場合、一般的なリストは次のとおりです:localhost,127.0.0.1,::1,.internal,.local,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
エラー4: プロキシの認証が機能しない — パスワードに特殊文字が含まれている
パスワードに特殊文字(@、#、%など)が含まれている場合、URLが正しく解析されません。
解決策: パスワードをURLエンコーディングでエンコードします。例えば、p@ss#word → p%40ss%23word。Pythonを使用してエンコードされたバージョンを迅速に取得できます:
python3 -c "from urllib.parse import quote; print(quote('p@ss#word', safe=''))"
# 出力: p%40ss%23word
エラー5: プロキシは機能するがSSL証明書が検証されない
企業のプロキシはしばしばSSLインスペクション(MITM)を実行し、証明書を置き換えます。この場合、Dockerはエラーを返します:
x509: certificate signed by unknown authority
解決策: 企業のルート証明書をホストの信頼された証明書に追加し、Dockerを再起動します。Ubuntu/Debianの場合:
sudo cp corporate-ca.crt /usr/local/share/ca-certificates/ sudo update-ca-certificates sudo systemctl restart docker
エラー6: Kubernetes / Docker Swarm — すべてのノードでプロキシが機能しない
クラスター環境では、各ノードに対してプロキシを個別に設定する必要があります。Kubernetesの場合、ポッドのマニフェストやConfigMapで環境変数を追加で設定する必要があります。これをAnsibleや他の構成管理ツールを使用して自動化できます。
結論
Dockerでのプロキシ設定は、単一の設定ではなく、イメージのプルのためのデーモン、ビルド時のための設定、実行中のコンテナのための設定という3つの独立したレベルがあります。このアーキテクチャを理解することで、どのトラフィックがプロキシを介して流れ、どのトラフィックが直接流れるかを柔軟に管理できるようになります。
正しい設定のための簡単なチェックリスト:
- ✅ イメージのプルのため — HTTP_PROXYとHTTPS_PROXYの変数を使用してsystemdオーバーライドを設定する
- ✅ ビルドのため — プロキシを
--build-argまたは~/.docker/config.jsonを介して渡す - ✅ 実行時のため —
-eまたは--env-fileを介して環境変数を使用する - ✅ 常に内部アドレスのためにNO_PROXYを設定する
- ✅ Dockerfileにプロキシのパスワードを保存しない — build-argsと.envファイルを使用する
- ✅ CI/CDパイプラインには高速なデータセンターのプロキシを選択する
- ✅ パーサーコンテナには住宅用またはモバイルプロキシを使用する
コンテナアプリケーションが外部サービスにリクエストを行ったり、データをパースしたり、地理的制限のあるAPIで作業したりする場合は、住宅用プロキシを使用することをお勧めします。これにより、サービスからの信頼性が高まり、集中的な作業でもブロックされるリスクが最小限に抑えられます。