Docker Hub だけが遅い・失敗する理由
Docker Hub のイメージ取得で「Pull が終わらない」「数分待った後に i/o timeout が出る」「context deadline exceeded や connection reset by peer が表示される」といった問題は、Clash のノードが単純に遅い場合だけに起きるものではありません。ブラウザで Docker Hub の Web ページを開けても、Docker daemon が同じ経路を使っているとは限らないためです。ブラウザは OS のシステムプロキシや Clash の TUN を利用していても、Docker Engine は独立したサービスとして動作し、別の DNS、別のプロキシ設定、別の権限環境を使うことがあります。
さらに、Docker のイメージ取得は一つのホストだけで完結しません。最初に registry-1.docker.io へ認証やマニフェストを問い合わせ、その後に認証トークンの発行先、イメージレイヤーを配信する CDN、場合によっては署名やメタデータ関連のホストへ接続します。そのため、Docker Hub のトップページだけを確認して「Clash は正常」と判断すると、実際の Pull でだけ失敗することがあります。本稿では、Clash の接続ログ、Docker 側のプロキシ、ルールの優先順位、DNS、ノード品質を順番に確認します。
前提:Docker Hub の利用規約、勤務先や学校のネットワークポリシー、取得するコンテナイメージのライセンスを確認したうえで設定してください。プロキシ設定は通信経路を変えるだけであり、信頼できないイメージを安全にするものではありません。
最初に症状を分類する
設定ファイルをいきなり書き換える前に、どの段階で止まっているかを記録します。同じタイムアウトでも、認証に失敗しているのか、レイヤーのダウンロードが遅いのかで対処が変わります。次のコマンドを実行した時刻と、Clash の接続一覧に表示されたホスト名・ポリシー名を控えておくと、原因を追いやすくなります。
- 名前解決で失敗する:
no such host、server misbehaving、または DNS 関連のエラーが出る場合です。Docker の DNS と Clash の DNS が分離している可能性があります。 - 認証段階で止まる:ログイン済みでも
unauthorizedや認証トークン取得のタイムアウトが出る場合です。レジストリ本体だけでなく認証用ホストも確認します。 - レイヤー取得だけ遅い:マニフェストは取得できるのに、数百 MB のレイヤーで止まるパターンです。CDN への接続、ノードの帯域、接続数制限が関係します。
- Clash のログに何も出ない:Docker daemon が Clash のポートを使っていない、または TUN がその通信を捕捉していない可能性が高いです。
まず公開イメージの小さなタグで再現します。巨大なイメージだけを使うと、ネットワーク障害と単純な転送時間を区別しにくくなります。
docker pull hello-world:latest
docker pull alpine:latest
docker info
失敗した直後に Clash の「Connections」や「Logs」を開き、docker.io、docker.com、registry-1.docker.io などの行を検索します。表示された実ホストが想定したプロキシグループを通っているか、ルール欄が DIRECT や広すぎる GEOIP になっていないかを確認してください。
Clash 側の動作を先に確認する
Clash Verge Rev、Clash Verge、Mihomo Party などを使っている場合は、最初に現在のプロファイルが読み込まれ、コアが稼働していることを確認します。システムプロキシをオンにしただけでは、Docker daemon の通信まで自動的にプロキシ化されるとは限りません。GUI の「General」や「Settings」で、Mixed Port または HTTP/SOCKS の待受ポートを確認してください。典型的には 7890、7897、9090 などですが、固定値だと決めつけず、実際の画面に表示された値を使います。
同じ PC 上の通常のターミナルから、Clash の混合ポート経由でレジストリへ到達できるかを確認します。以下の 127.0.0.1:7890 は、実際のポート番号に置き換えてください。
curl -I -x http://127.0.0.1:7890 https://registry-1.docker.io/v2/
curl -I -x http://127.0.0.1:7890 https://auth.docker.io/
401 Unauthorized が返っても、必ずしも失敗ではありません。Docker Registry が認証を要求していることを示すレスポンスであり、TLS 接続と HTTP 応答まで到達した証拠になります。一方、接続が長時間戻らない、名前解決エラーになる、Clash のログに該当行が現れない場合は、Clash のポート、プロファイル、ローカルファイアウォールを先に直します。
確認のコツ:ブラウザで Docker Hub を開くテストと、curl でレジストリ API を呼ぶテストは分けてください。前者が成功しても、後者のホストが別ルールで処理されていることがあります。
Docker daemon にプロキシを設定する
Docker CLI の環境変数と Docker daemon のプロキシ設定は別物です。ターミナルで HTTP_PROXY を設定しても、バックグラウンドでイメージを取得する daemon がその値を継承するとは限りません。特に Linux の systemd 管理下では、daemon 用の環境変数を明示的に登録する必要があります。プロキシを公開ネットワークへバインドせず、原則としてローカルホストからだけ利用してください。
- Clash の待受アドレスとポートを確認:
127.0.0.1で受け付ける HTTP 混合ポートを確認します。Docker が別の仮想マシンや WSL2 内で動く場合、ゲスト側の127.0.0.1はホスト側を指さないことがあるため、構成を先に整理します。 - daemon 用の設定を作成:Linux では
/etc/systemd/system/docker.service.d/http-proxy.confにHTTP_PROXYとHTTPS_PROXYを登録します。URL のスキームは Clash のポート種別に合わせてください。 - 除外先を指定:
NO_PROXYにlocalhost、127.0.0.1、Docker の内部ネットワーク、社内レジストリなどを登録します。内部サービスまで外部ノードへ送ると、認証や名前解決が壊れることがあります。 - 設定を反映して状態を確認:
systemctl daemon-reloadとsystemctl restart dockerを実行し、再起動後にsystemctl show --property=Environment dockerで値が反映されているか確認します。 - 小さなイメージで再試行:
docker pull hello-worldを実行し、同時に Clash の接続ログで Docker 関連の通信を確認します。
[Service]
Environment="HTTP_PROXY=http://127.0.0.1:7890"
Environment="HTTPS_PROXY=http://127.0.0.1:7890"
Environment="NO_PROXY=localhost,127.0.0.1,.local,registry.local"
Docker Desktop では、Linux の systemd ファイルを編集するのではなく、アプリの設定画面にある Docker Engine や Resources、Proxies の項目を使います。バージョンによって表示名や設定方法が異なるため、GUI にプロキシ項目がある場合はそちらを優先してください。設定を変更した後は Docker Desktop 自体を再起動し、daemon が新しい環境で起動したことを確認します。
Docker Hub 向けの分流ルールを整える
Clash のルールは上から評価されるため、Docker Hub 用のルールを広い GEOIP、MATCH、広告ブロック、地域別ルールより前に置く必要があります。まずはドメイン単位で対象をまとめ、動作確認後に必要な範囲へ絞ります。ホスト名はサービス変更で増える可能性があるため、ログに実際に現れたドメインを基準に更新してください。
| 用途 | 確認するホスト例 | 初期設定の考え方 |
|---|---|---|
| Registry API | registry-1.docker.io |
安定した Docker 用プロキシグループへ送る |
| 認証 | auth.docker.io |
Registry と同じグループで挙動を揃える |
| Docker Hub Web | hub.docker.com |
ブラウザ閲覧が必要な場合だけ追加する |
| レイヤー CDN | 接続ログに表示された配信ホスト | 実測したホストを個別に確認する |
rules:
- DOMAIN,registry-1.docker.io,DOCKER_HUB
- DOMAIN,auth.docker.io,DOCKER_HUB
- DOMAIN,hub.docker.com,DOCKER_HUB
- MATCH,FINAL
上の例で使っている DOCKER_HUB は、実際に設定ファイル内で定義したプロキシグループ名へ変更します。DOMAIN-SUFFIX,docker.io のように広く指定すると便利な反面、不要な通信まで同じノードへ送ることがあります。まずは registry-1.docker.io と auth.docker.io を明示し、Pull 中に現れた CDN を追加する方法が安全です。
DNS、TUN、Docker Desktop の境界を確認する
Docker が WSL2、仮想マシン、リモート Linux、Docker Desktop の内部 VM で動いている場合、Clash と Docker は同じネットワーク名前空間にいません。ホスト OS のブラウザが TUN を使えていても、ゲスト側の Docker daemon がホストの 127.0.0.1 に接続できるとは限りません。まず Docker を実行している環境内で getent hosts registry-1.docker.io や curl を使い、名前解決と TCP 接続を別々に確認します。
TUN を使う場合は、Clash が DNS を処理し、Docker の通信を仮想インターフェース経由で捕捉できているかを確認します。TUN の導入直後にすべての通信を強制すると、Docker の内部ブリッジ、社内レジストリ、ホストとの管理通信まで巻き込むことがあります。最初は Docker Hub への Pull だけで試し、正常になった後に必要な範囲へ拡大してください。
注意:Docker daemon のプロキシと TUN を同時に有効にすると、同じ接続が二重にプロキシ化される構成があります。タイムアウトが悪化した場合は、いったんどちらか一方だけを使い、Clash の接続ログで経路を比較してください。
ノードとタイムアウトを検証する
Clash のルールが正しくても、選択したノードが Docker のレイヤー配信に向いていないことがあります。小さな API リクエストは通るのに、大きなレイヤーを数十秒転送すると切れる場合、帯域よりも接続維持、混雑、CDN との相性、出口 IP の評価が問題になります。自動選択グループを使っている場合は、同じ Pull の途中でノードが切り替わっていないかも見てください。長いダウンロード中の切り替えは、再試行や接続リセットの原因になります。
検証では、まず固定ノードを一つ選び、同じイメージを数回取得します。次に別の地域や別のプロバイダーのノードへ変更し、成功率、名前解決時間、最初のバイトまでの時間、レイヤー転送速度を比較します。docker pull の表示だけでは判断しにくいため、Clash の接続履歴と Docker daemon のログを同じ時刻で照合するのが有効です。
- 固定ノードで安定する:url-test や load-balance の選択結果、または特定ノードの品質を疑います。
- すべてのノードで同じホストだけ失敗する:ルール、DNS、認証先、CDN の扱いを確認します。
- ホスト側は成功し、WSL2 や VM だけ失敗する:ゲストから Clash へ到達するアドレスとファイアウォールを確認します。
- 夜間だけ遅い:共有ノードの混雑や CDN との経路混雑が考えられます。別ノードで時間帯を変えて比較します。
よくある症状と対処
| 症状 | 可能性の高い原因 | 最初に行うこと |
|---|---|---|
| Clash にログがない | daemon がプロキシを使っていない | Docker daemon 用の環境変数または Docker Desktop の設定を確認 |
| 401 が返る | Registry へ到達済みで認証待ち | 認証用ホストと Docker のログイン状態を確認 |
| レイヤーだけ失敗する | CDN、ノード混雑、長時間接続の切断 | 接続ログから配信ホストを確認し、固定ノードで再試行 |
| WSL2 だけ直行する | ホストの localhost とゲストの localhost が別 | Clash の LAN 接続設定とゲスト側の接続先を確認 |
| 設定後も古い挙動が続く | daemon が再起動されていない | Docker daemon または Docker Desktop を再起動して環境を再確認 |
エラーメッセージだけで「Docker Hub が落ちている」と決めつけないことも重要です。公開レジストリ側の障害であれば、複数の回線やノードで同時に再現し、ステータスページやコミュニティにも同様の報告が出ます。自分の環境だけで発生しているなら、Clash のルール、daemon のプロキシ継承、DNS 境界を優先して調べる方が短時間で解決できます。
よくある質問
ブラウザで Docker Hub が開けば、Docker も同じように使えますか?
必ずしも使えるとは限りません。ブラウザはシステムプロキシを利用していても、Docker daemon は独自のサービスとして動いています。Docker 側に HTTP/HTTPS プロキシを設定し、再起動後に Clash の接続ログへ通信が現れることを確認してください。
Docker Hub をすべて DIRECT にしてもよいですか?
接続できるネットワークでは可能ですが、地域や ISP によっては Registry、認証、CDN のいずれかが不安定になることがあります。まずは対象ホストを専用グループへ送り、固定ノードと DIRECT の成功率を比較してください。社内レジストリやプライベートなエンドポイントは、必要に応じて NO_PROXY と DIRECT を使い分けます。
TUN モードを有効にすれば daemon の設定は不要ですか?
環境によります。ホスト上の Docker が TUN で確実に捕捉される構成なら不要な場合もありますが、WSL2、仮想マシン、リモート Docker daemon では TUN の範囲外になることがあります。TUN を前提にせず、Docker 側のログと Clash の接続履歴で実際の経路を確認するのが安全です。
市販の同類ツールや単純なシステムプロキシ設定は、ブラウザの表示確認までは簡単でも、Docker daemon、WSL2、認証ホスト、レイヤー CDN まで分けて追跡する場面では設定箇所が散らばり、ログも見つけにくいことがあります。Clash 公式サイト なら、Clash Verge Rev や Mihomo 系クライアントで混合ポート、TUN、接続ログ、ドメイン単位の分流を順に確認でき、今回のような「ブラウザは通るのに Docker だけ失敗する」切り分けを一つの手順にまとめられます。Docker Hub のプロキシ設定をこれから試すなら、環境に合うクライアントをダウンロードして、まず小さなイメージで疎通を確認してみてください。