為什麼 Docker Hub 拉取映像檔會逾時
使用 Docker 拉取映像檔時,最容易誤判的情況是:瀏覽器可以開啟一般網站,Clash 連線紀錄也看似正常,但執行 docker pull 卻停在 Pulling from library、Waiting 或 Retrying,最後回報 context deadline exceeded、i/o timeout 或 TLS handshake 失敗。這不一定代表目前節點速度太慢,因為 Docker Engine 的連線路徑與瀏覽器不同,它可能由背景服務、虛擬機、WSL2 或 Docker Desktop 的獨立網路環境發出請求。
一次完整的 Docker Hub 拉取,通常不只連到一個主機。首先要取得 Registry API 的授權資訊,接著連線到 Docker Registry,再從內容分發網路下載映像檔的各個 layer。常見目的地包括 registry-1.docker.io、auth.docker.io、hub.docker.com,以及實際分發 layer 的 CDN 網域。只把其中一個網域加入規則,並不代表整條下載流程都已經進入代理。
另外,Docker CLI 顯示的錯誤位置不一定是根因。例如 Registry API 已成功回應,真正失敗的是後續的 layer CDN;又或者 DNS 查詢先解析到一個目前出口無法連線的位址,導致你看到長時間等待。排錯時不要只重試同一個指令,也不要一開始就反覆更換節點,而是先確認請求有沒有進入 Clash、命中了哪條規則、DNS 回傳了什麼,以及 Docker Engine 是否真的使用同一個代理入口。
先分辨 Docker、Clash 與 TUN 的流量邊界
Clash 的系統代理、TUN 模式與 Docker Engine 不是同一層功能。系統代理通常只會影響遵循作業系統代理設定的應用程式;Docker CLI 把請求交給 Docker daemon,而 daemon 可能在 Linux service、Docker Desktop 的 VM 或 WSL2 發出真正的外部連線。因此,即使瀏覽器已經可以透過 Clash 開啟 Docker Hub,Docker daemon 仍可能直接連線,甚至使用另一套 DNS。
| 使用方式 | 請求實際來源 | 常見問題 | 建議觀察位置 |
|---|---|---|---|
| Linux 原生 Docker | 宿主機上的 dockerd | shell 的代理環境變數沒有傳給 daemon | systemd 服務設定、Docker daemon 日誌 |
| Docker Desktop | Desktop 背景服務或內部 VM | 主機代理與 Desktop 代理設定不一致 | Desktop 設定、Clash 連線列表 |
| WSL2 執行 Docker CLI | WSL 網路與 Docker daemon 的組合 | Windows 的 localhost 代理位址在 WSL 內不可直接使用 | WSL 路由、nameserver、daemon 端設定 |
| TUN 模式 | 由虛擬網卡接管符合條件的封包 | 路由衝突、DNS 劫持或 Docker 私有網段被誤接管 | Clash 日誌、TUN 設定與系統路由表 |
這也是為什麼「我已經在 Clash Verge Rev 開啟系統代理」不能直接等同於「Docker 已經走代理」。若 Docker Engine 完全沒有出現在 Clash 的連線列表,優先處理流量入口;若列表中看得到請求卻顯示 DIRECT,才進一步檢查規則順序與網域匹配。
在啟用 TUN 之前,建議先記錄目前狀態,包括 Docker Desktop 是否正在執行、Docker daemon 的位置、Clash 的 mixed-port、TUN 的 DNS 模式,以及是否同時啟用了公司 VPN 或其他透明代理。排錯期間一次只改一個變數,否則即使問題消失,也很難知道真正有效的是代理、DNS,還是某個路由變更。
docker pull hello-world。如果完全沒有新連線,別急著修改 Docker Hub 規則,先處理 Docker daemon 沒有進入 Clash 的問題。
設定 TUN 與 Docker Registry 分流規則
當 Docker daemon 不支援或不穩定地讀取 HTTP/HTTPS Proxy 時,TUN 可以作為較完整的驗證方式。對 Clash Meta 或 Mihomo 核心而言,TUN 會建立虛擬網卡,讓原本不會讀取代理環境變數的程式也有機會被導入規則引擎。不過,TUN 不是「開啟後所有問題自動消失」的按鈕;如果 DNS 模式、路由排除或規則順序錯誤,反而可能讓 Docker 網路、容器內服務與本機代理互相干擾。
在圖形介面中,先確認 TUN 的實作方式、堆疊模式與 DNS 設定。不同版本的 Clash Verge Rev 可能把選項放在「設定」「核心設定」或「TUN」頁面,名稱也可能略有不同。原則上,排錯時應先使用較容易觀察的設定,避免同時啟用多套 DNS 劫持、覆寫路由與特殊防火牆選項。若電腦上有公司 VPN,請先確認兩者是否會爭用預設路由;必要時暫停其中一套作 A/B 測試。
分流規則應涵蓋 Docker Hub 的控制面與資料面。可以在自訂規則或規則覆寫區加入下列方向,實際策略群組名稱請依你的設定檔調整:
rules:
- DOMAIN-SUFFIX,docker.io,Proxy
- DOMAIN-SUFFIX,docker.com,Proxy
- DOMAIN,registry-1.docker.io,Proxy
- DOMAIN,auth.docker.io,Proxy
- DOMAIN-SUFFIX,dockerusercontent.com,Proxy
- MATCH,DIRECT
上述片段的重點不是盲目把所有相關網域永久送往同一節點,而是先建立可驗證的基準。規則載入後,重新執行拉取,接著在連線列表搜尋 docker、registry、auth 或實際出現的 CDN 主機。若規則命中的是一個新的 CDN 網域,應根據連線紀錄補充必要的後綴,而不是猜測一大批網域。完成測試後,再依地區、服務需求與安全政策縮小規則範圍。
規則順序尤其重要。若上方已有 GEOIP,CN,DIRECT、某個大型規則集,或以 IP 分類為主的條款,Docker Registry 的網域規則可能永遠沒有機會被執行。將具體的 DOMAIN 與 DOMAIN-SUFFIX 放在寬泛規則之前,並在 Clash 的命中資訊中確認實際策略,才算完成設定。不要只看 YAML 已經寫入檔案,因為訂閱更新、設定合併與覆寫層級都可能讓你編輯的內容沒有真正生效。
實際排錯流程:從 DNS 到 layer 下載
第一步:確認 Docker daemon 的連線狀態
先執行簡單、體積很小的映像檔測試,避免大型 layer 讓問題被下載時間掩蓋。使用 docker info 確認 Docker 引擎可用,再執行 docker pull hello-world 或其他可信的小型公開映像。若 Docker CLI 本身就無法連線 daemon,這是 Docker socket 或服務狀態問題,與 Clash 分流尚無關係。
Linux 使用者可查看 daemon 的即時日誌,觀察錯誤是 DNS、代理連線、TLS,還是遠端回應碼。Docker Desktop 使用者則應同時查看 Desktop 的診斷資訊,因為終端機中的錯誤訊息只反映 CLI 與 daemon 之間的結果,不一定包含內部 VM 的完整原因。若能在 Clash 中看見 Registry 請求,請把發生時間、目的地與策略名稱記下來,後續每次修改都用同一組資料比對。
第二步:分開測試 DNS、TLS 與代理
DNS 能解析不代表 HTTPS 一定能連通;HTTPS 能建立連線,也不代表後續 layer CDN 會使用同一出口。先用系統工具查詢 registry-1.docker.io 與 auth.docker.io,再檢查返回的位址是否頻繁變動或落在目前網路無法到達的路徑。若開啟 TUN 後 DNS 結果與未開啟時完全不同,請記錄兩組結果,不要在尚未理解差異前反覆切換 fake-ip、redir-host 或系統 DNS。
接著用最小化的 HTTPS 請求測試 Registry API。只要能得到明確的 HTTP 回應,就表示 DNS、TCP 與 TLS 至少走完了一部分;如果命令停在連線階段,才應把重點放在出口節點、TUN 路由或防火牆。若 curl 使用了代理而 Docker 沒有使用,兩者結果不同是預期現象,不能拿來證明 Docker Hub 服務本身異常。
curl -I --connect-timeout 10 https://registry-1.docker.io/v2/
docker pull hello-world
在 Linux 上也可以檢查 daemon 是否取得代理設定。以 systemd 管理的 Docker 為例,代理通常需要放在服務的環境設定,而不是只寫在目前 shell:
sudo systemctl show --property=Environment docker
sudo journalctl -u docker --since "10 minutes ago"
如果你使用 Docker Desktop,請在 Desktop 自身的網路或代理設定中確認,而不是只在終端機執行 export HTTPS_PROXY=...。Windows、macOS 與 WSL2 的 localhost 位址也不能一概而論:宿主機上的 127.0.0.1 對 WSL 或容器網路未必代表同一台代理服務。這類情況比較適合使用可被對應環境存取的閘道位址,並以 Clash 連線列表驗證請求是否真的進入。
第三步:分辨 Registry、授權與 layer CDN
若 docker pull 可以開始列出 layer,但某一層長時間停住,通常表示控制面已經成功,問題集中在 layer 下載。這時不要只檢查 registry-1.docker.io,要回到 Clash 連線紀錄找出最後出現的目的地。不同映像、不同時間甚至不同 layer,可能會使用不同的內容分發主機;規則需要以實際紀錄為準。
若每次失敗的 layer 都不相同,可能是節點對長連線、HTTP/2、多路傳輸或大型回應不穩定。你可以在相同規則下更換策略群組中的節點,並用同一個映像重試;若只在特定節點失敗,根因較接近出口品質,而非規則。相反地,若所有節點都看不到 Docker 相關請求,則應回到 daemon、TUN 路由與代理入口檢查。
最常見的配置錯誤與修正方向
- 只設定瀏覽器代理:瀏覽器通了不代表 dockerd 通了。請把測試對象改成真正發出請求的 Docker daemon,並在 Clash 連線頁面確認來源。
- 只加入一個 Registry 網域:授權、Registry 與 CDN 可能是不同目的地。以實際連線紀錄補齊必要規則,避免只靠固定清單猜測。
- 規則被寬泛條款提前攔截:檢查
GEOIP、大範圍RULE-SET、FINAL與MATCH的排列順序,確保 Docker 專用規則在前。 - 把 TUN 與其他 VPN 疊加:兩個虛擬網路介面可能同時修改路由或 DNS。排錯時先簡化成一個接管來源,再逐一恢復其他工具。
- 錯把憑證問題當成節點速度:如果錯誤包含 certificate、handshake 或 x509,請先確認系統時間、根憑證、TLS 檢查工具與代理中介行為,不要只更換節點。
- 容器內測試與宿主機測試混用:容器可能有自己的 DNS、預設路由與代理環境。應分別測試宿主機、Docker daemon 與容器內的連線結果。
- 修改了錯的設定檔:訂閱主檔、覆寫檔與目前載入設定可能是三個不同檔案。每次修改後都要在介面確認核心已重新載入,並重新檢查規則命中。
完成修正後,建議用固定流程驗證:先重載 Clash 設定,再確認 TUN 或系統代理狀態;接著清除不必要的舊容器重試紀錄,執行小型映像拉取;最後測試一個包含多個 layer 的常用映像。每一步都記下時間與連線策略,這樣下次遇到逾時時,可以快速判斷是 DNS 變化、節點品質、CDN 路徑,還是設定更新造成的回歸問題。
常見問題
Docker Hub 逾時一定要開 TUN 嗎?
不一定。如果 Docker daemon 能正確使用 HTTP/HTTPS Proxy,透過規則分流通常更容易維護,也較不會影響區網服務。TUN 適合用來驗證不讀取代理環境的背景服務,或處理你無法在 daemon 端方便設定代理的場景。開啟前請先確認與 VPN、DNS 及 Docker 私有網段的相容性。
只加入 docker.io 就足夠了嗎?
通常不夠。Docker Hub 的授權、Registry 與 layer 分發可能使用不同主機。建議先加入必要的控制面規則,再從 Clash 連線列表觀察實際 CDN 網域;規則應以你的映像、網路環境與目前版本的連線結果為準,避免無限制擴大網域清單。
為什麼 curl 成功,docker pull 卻失敗?
最常見原因是兩者不是由同一個程序或網路環境發出請求。curl 可能讀取了目前 shell 的代理變數,而 Docker pull 由未設定代理的 daemon 執行;Docker Desktop 與 WSL2 也可能使用獨立的 VM 或網路介面。請在 Clash 連線紀錄確認 Docker 實際請求,再檢查 daemon 或 Desktop 的代理設定。
只有某些 layer 卡住,代表映像檔壞了嗎?
不一定。layer 下載可能分配到不同 CDN 路徑,某一個出口對長連線或大型回應不穩定,就會形成單層逾時。若映像摘要或 Registry 回應沒有顯示完整性錯誤,先比較不同節點、TUN 與規則命中結果;只有在多個正常出口都重現同一個摘要錯誤時,才需要進一步檢查本地儲存與映像來源。
相較於只提供單一全域開關、遇到 Docker 背景服務就難以確認流量去向的工具,Clash 能把 TUN、DNS、Registry 網域與策略群組拆開觀察:你可以先讓一般網站維持直連,再把 Docker 授權、Registry 與實際 CDN 精準導向代理,並透過連線紀錄追蹤每一層的命中結果。若你正在尋找一套能同時處理透明代理與細緻分流、又方便逐步排錯的方案,Clash 會讓 Docker Hub 逾時不再只能靠反覆換節點猜測。