前言:為什麼 Docker pull 會逾時?
在 2026 年,Docker 已經成為開發、測試與部署工作流程的重要基礎工具。不過,許多使用 Clash 的開發者會發現:瀏覽器可以正常開啟網站,主機上的命令列也能使用代理,但執行 docker pull 時卻長時間停在 Pulling from library、Waiting 或 Retrying,最後顯示 i/o timeout、context deadline exceeded 或 TLS handshake timeout。
這類問題通常不是 Docker Hub 本身停止服務,而是Docker Engine 與 Clash 的流量路徑沒有接上。Docker CLI 發出的請求會交給背景執行的 Docker daemon,並不一定會沿用桌面應用程式的系統代理設定。換句話說,即使 Clash Verge Rev 已經開啟代理,Docker daemon 仍可能直接使用本地網絡、錯誤的 DNS 或無法連通的出口。
本文會從流量路徑、Clash 透明代理、Docker daemon 設定、DNS、TLS 與日誌分析幾個面向,逐步建立一套可排查、可維護的配置。文中的命令以 Linux 上的 Docker Engine 為主,Windows 和 macOS 使用 Docker Desktop 的用戶也可以參考其中的測試思路。
本文目標
讓 Docker Hub 的 Registry、認證服務與映像層下載請求穩定通過 Clash;同時保留其他內網與本地服務的直連能力,避免不必要的全域代理。
1先理解 Docker 與 Clash 的流量路徑
排查之前,最重要的是分清楚「誰在發出網絡請求」。當你在終端執行 docker pull nginx 時,Docker CLI 通常只是透過 Unix socket 或 TCP API 將操作交給 Docker daemon。真正連接 registry-1.docker.io、auth.docker.io 以及 CDN 映像層地址的程序,是背景中的 dockerd。
因此,瀏覽器能否訪問 Docker Hub,並不能直接證明 Docker daemon 已經使用 Clash。常見的路徑大致如下:
- 終端機中的 Docker CLI 將拉取請求交給 Docker daemon。
- Docker daemon 解析 Registry、Token 服務與映像層 CDN 的域名。
- 請求由主機路由表、Docker bridge 或 Docker Desktop 虛擬機送出。
- Clash 透過 HTTP/SOCKS 代理、TUN 模式或透明代理規則接管流量。
- Clash 根據域名規則選擇代理節點,最後連接 Docker Hub。
其中任何一層出現偏差,都可能造成「瀏覽器正常、Docker 失敗」。例如,Docker daemon 沒有繼承桌面的 HTTP_PROXY,或 Docker bridge 的流量沒有經過 TUN 介面;也可能是 DNS 將 Registry 解析到一個主機可以解析、但代理節點無法訪問的地址。
小撇步
不要一開始就反覆更換節點。先用 curl、docker info 與 journalctl 確認失敗發生在解析、連線、TLS 還是認證階段,後續修改才不會失去方向。
2在 Clash 中加入 Docker Hub 分流規則
Docker Hub 並非只有一個域名。執行拉取時,Docker 可能先訪問 Registry,再訪問認證端點,最後從不同的 CDN 下載映像層。如果只加入 docker.io 規則,部分請求仍可能被錯誤地分到 DIRECT,造成連線卡住。
你可以在 Clash 的自訂規則或 YAML 配置中,將以下域名指向穩定的代理策略組。DOCKER 是示例策略組名稱,請替換成你配置中實際存在的名稱,例如 PROXY 或「自動選擇」。
如果你使用的是規則集(Rule Provider),也可以把 Docker 相關域名放在單獨的列表中,再由主配置引用。規則順序非常重要:Docker 規則應該放在寬泛的 GEOIP、FINAL 或 MATCH 規則之前,否則請求可能在到達 Docker 規則前就被提前匹配。
代理策略組應該如何選擇?
拉取映像時,速度不一定是唯一標準。Docker 下載需要持續傳輸多個 layer,節點若頻繁切換、連線重置或共享出口過度擁擠,即使測試延遲很低,也可能在大檔案下載中途失敗。建議使用固定節點或穩定的故障轉移組,避免使用會頻繁變更出口 IP 的負載均衡組。
注意
不要直接把所有 DOMAIN-KEYWORD,docker 流量永久送往代理。若公司內部存在私有 Registry,例如 registry.example.local,應使用更精確的 DOMAIN-SUFFIX 規則讓它保持直連。
3動手配置:讓 Docker 流量進入 Clash
這是本文的實作核心。你可以根據作業系統與部署方式,選擇「Docker daemon 使用代理」或「Clash TUN/透明代理」其中一種。兩者不一定要同時開啟;若同時設定,容易出現重複代理、回環路由或 DNS 行為不一致。
方案 A:為 Docker daemon 設定代理
這個方法適合 Docker Engine 位於 Linux 主機,且 Clash 在同一台主機上提供 HTTP 或 SOCKS 代理端口的情況。先確認 Clash 的監聽地址。若 Docker daemon 使用 127.0.0.1,而 Clash 只監聽在另一個容器或虛擬機內,兩者便無法互相連接。
建立 systemd drop-in 目錄與設定檔:
將 127.0.0.1:7890 替換為 Clash 實際提供的 HTTP 代理端口:
重新載入設定並重啟 Docker:
NO_PROXY 很重要。它可以避免內網 Registry、Kubernetes API、資料庫或本機服務被意外送到代理節點。若你的私有 Registry 使用特定域名,請將其完整加入 NO_PROXY。
方案 B:使用 Clash TUN 或透明代理
如果你希望不只 Docker daemon,連容器內的應用程式流量也能被統一接管,可以使用 Mihomo 支援的 TUN 模式。開啟 TUN 後,請確認配置中的自動路由、嚴格路由與 DNS 劫持選項符合你的環境。不同客戶端的名稱可能略有差異,但核心目標是讓主機與 Docker bridge 的流量都能進入虛擬網卡。
- 在 Clash 中開啟 TUN 模式,確認核心狀態為運行中。
- 重新啟動 Docker,避免舊的連線與 DNS 快取干擾測試。
- 檢查主機是否出現 TUN 介面,並確認預設路由沒有形成循環。
- 先執行單一 Registry 測試,再執行完整的
docker pull。
如果使用 TUN 後主機網絡正常、Docker 仍然失敗,問題可能出在 Docker bridge 路由或容器 DNS。此時不要盲目增加規則,先檢查 Docker daemon 的網絡模式與 Clash 日誌,確認請求是否真的出現在連線記錄中。
4Docker daemon.json、DNS 與 TLS 排查
代理設定與 Docker daemon 的 JSON 設定是兩個不同層次。/etc/docker/daemon.json 常用來設定 DNS、Registry mirror、日誌與儲存驅動器;代理環境通常建議使用 systemd drop-in。但如果你需要統一管理,也可以在 daemon 設定中檢查相關網絡選項。
確認 daemon.json 格式正確
JSON 不接受註解、尾隨逗號或重複鍵。修改後先執行格式檢查,再重啟 Docker:
若 DNS 解析不穩定,可以暫時指定可用的 DNS 伺服器進行對比測試。但要注意:DNS 伺服器是否可達、是否會污染,以及 Clash 是否接管 DNS,三者需要一起考慮。只修改 DNS 地址,並不能保證 Docker 的 HTTPS 流量會自動走代理。
在 Clash 開啟 fake-ip 或 redir-host 後,DNS 行為會有所不同。若主機可以解析 registry-1.docker.io,但 Docker 回報 no such host,可先執行:
TLS handshake timeout 的處理方式
TLS handshake timeout 表示 TCP 連接後,HTTPS 握手沒有在期限內完成。常見原因包括節點出口不穩定、代理協議端口填錯、SNI 被中間設備干擾,或系統時間不正確。請先確認主機時間:
接著使用 curl -v 觀察是否能收到 HTTP/2 401 Unauthorized 或類似回應。對 Registry 根路徑而言,401 並不一定是錯誤,反而通常代表你已經成功抵達 Docker Registry,只是尚未提供認證令牌。
5用日誌與分層測試定位故障
不要只根據 docker pull 最後一行錯誤判斷原因。建議由外到內分成四層測試,每一步都記錄結果,這樣可以快速縮小範圍。
| 測試層級 | 命令或觀察點 | 主要判斷 |
|---|---|---|
| DNS | getent hosts registry-1.docker.io |
能否解析,以及回傳地址是否合理 |
| HTTPS | curl -v https://registry-1.docker.io/v2/ |
TCP、TLS 與 Registry 回應是否正常 |
| Docker daemon | docker info、systemctl status docker |
daemon 是否運作,以及代理環境是否載入 |
| 映像拉取 | docker pull hello-world |
認證、layer 下載與解壓是否成功 |
Linux 上可以即時查看 Docker daemon 日誌:
如果 Clash 的連線日誌完全沒有出現 Docker Hub 域名,通常表示 Docker 流量尚未進入 Clash,應回頭檢查 daemon 代理、TUN 路由或 Docker Desktop 虛擬機設定。如果日誌顯示連線已經建立,但拉取中途反覆重試,則要優先檢查節點穩定性、MTU、TLS 和大檔案傳輸。
小撇步
先測試小型映像,例如 hello-world,再測試較大的基礎映像。小映像成功、大映像失敗,通常指向連線保持、MTU、頻寬或代理節點穩定性,而不是基本域名規則問題。
6常見配置錯誤與穩定化建議
以下問題在實際部署中非常常見。它們看似與 Clash 無關,實際上卻會讓代理配置難以生效。
- 只設定終端機代理: 在 shell 中執行
export HTTPS_PROXY=...只會影響當前命令列程序,通常不會影響 systemd 啟動的 Docker daemon。 - 使用錯誤的監聽地址: Clash 只監聽
127.0.0.1時,其他容器或虛擬機可能無法訪問。若要暴露到區域網絡,必須同時評估防火牆與安全風險。 - 把 SOCKS 端口當成 HTTP 端口:
HTTP_PROXY=http://...與socks5://...不能混用,請依 Clash 實際端口類型填寫。 - 規則被 MATCH 提前攔截: Docker 域名規則必須放在最終匹配規則之前。
- 代理私有 Registry: 內部服務可能需要直連。請使用
NO_PROXY與精確域名規則,避免認證或內網 DNS 被代理節點接管。 - 忽略 MTU: TUN、VPN、Docker bridge 多層封裝時,過大的 MTU 可能造成 TLS 或 layer 下載卡住。可在測試環境降低 MTU,確認是否改善後再做永久調整。
安全方面,建議不要把 Clash 的混合端口直接暴露到公網,也不要在配置檔案中公開訂閱連結、代理密碼或私有 Registry 憑證。修改代理後,最好重新啟動 Docker 並清理失敗的中間狀態,再重新拉取映像,以免舊連線讓測試結果失真。
常見問題 FAQ
Docker pull 顯示 401 Unauthorized,是不是代理失敗?
不一定。對 https://registry-1.docker.io/v2/ 直接請求時,Registry 常會先回傳 401,要求客戶端取得認證令牌。只要回應能快速返回,通常代表 DNS、TCP 與 TLS 已經成功。若 Docker 接著無法取得 token,才需要檢查 auth.docker.io 是否被正確分流。
瀏覽器可以開啟 Docker Hub,但 Docker 還是逾時,該怎麼辦?
先確認 Docker daemon 是否載入代理,不要只檢查瀏覽器的 Clash 狀態。執行 systemctl show --property=Environment docker,再用 journalctl -u docker 查看請求錯誤。如果 Clash 日誌沒有任何 Docker 域名,說明 daemon 或 TUN 路由尚未接通。
應該使用 daemon 代理,還是直接開 TUN 模式?
若只需要拉取 Docker Hub 映像,daemon 代理通常更容易控制,也較不會影響其他網絡。若你還需要接管容器內應用程式、套件管理器或其他非 HTTP 流量,才考慮 TUN 或透明代理。兩種方式同時使用前,請先確認不會造成重複代理與路由循環。
更換節點後仍然無法拉取,下一步檢查什麼?
依序檢查 DNS 解析、curl -v 的 TLS 結果、Docker daemon 環境變數與 Clash 連線日誌。若小型映像可成功、大型映像失敗,應測試 MTU、頻寬與連線保持時間,而不是繼續修改域名規則。