前言:Docker Hub 逾時不一定是節點失效
執行 docker pull nginx、docker compose up 或建置映像時,如果終端機長時間停在 Pulling fs layer、Waiting,最後出現 context deadline exceeded、i/o timeout 或 TLS handshake timeout,很多人第一反應是更換 Clash 節點。然而,問題往往不在節點本身,而在於 Docker Engine 是一個獨立的背景服務。
瀏覽器能正常開啟 Docker Hub,只代表瀏覽器流量使用了代理;它並不能證明 Docker daemon、Docker Desktop、Containerd 或 CI 執行器也使用相同的代理設定。尤其在 Linux 上,Docker daemon 通常由 systemd 啟動,並不會自動讀取你在 Clash 客戶端中開啟的系統代理。Windows 與 macOS 的 Docker Desktop 則可能使用虛擬機或背景網路層,與一般應用程式的代理路徑有所不同。
本文會依照「先確認現象、再檢查 Clash、最後設定 Docker 服務」的順序,排查代理模式、分流規則、DNS、憑證與 daemon 環境變數。你不需要一開始就修改大量 YAML;只要先找出流量究竟卡在哪一層,就能用最小改動恢復映像拉取。
排查目標
確認 Docker Hub 網域可解析、TCP/TLS 連線可建立,並讓 Docker daemon 使用正確的 HTTP/HTTPS 代理,同時避免把私有 Registry、區域網路與 Docker Hub 登入流量錯誤地導向不適合的節點。
1先確認錯誤屬於哪一種類型
不同錯誤訊息代表的故障層級不同。先記下完整輸出,不要只截取最後一行,因為 docker pull 可能先成功連到 Registry,再於取得 Token 或下載 Blob 時失敗。
| 錯誤表現 | 較可能的原因 | 優先檢查項目 |
|---|---|---|
Could not resolve host |
DNS 解析失敗、污染或 Docker 使用了不同的 DNS | Clash DNS、Docker DNS、TUN 設定 |
TLS handshake timeout |
連線沒有經過代理,或節點無法穩定連到目標 | daemon 代理、Clash 日誌、節點延遲 |
i/o timeout |
TCP 路徑被阻斷、出口擁塞或代理埠填寫錯誤 | 代理埠、模式、系統防火牆 |
unauthorized 或 denied |
登入狀態、映像名稱或權限問題,不一定是網路故障 | docker login、Repository 權限 |
| 下載一層後卡住 | 某個 CDN 網域未被代理,或節點對大檔案連線不穩 | 規則命中、切換節點、並行下載設定 |
在終端機先執行下列命令,確認 Docker CLI 能否取得基本資訊。這些命令不會修改配置:
如果 docker version 顯示 Client 正常、Server 區段卻無法連線,問題是 Docker Engine 沒有啟動或目前帳號沒有權限;如果 Server 正常但 docker pull 逾時,才進一步排查代理與 DNS。
2檢查 Clash 代理模式與監聽埠
Docker 使用代理時,最常見的失誤是把 Clash 的「混合埠」與「HTTP 代理埠」搞混。Docker daemon 需要的是 HTTP 或 HTTPS proxy;如果你填入只接受 SOCKS5 的埠,可能會出現連線重置、TLS 失敗或完全沒有反應。
| 項目 | 用途 | 排查建議 |
|---|---|---|
| HTTP 代理埠 | 處理 HTTP CONNECT 與一般 HTTP 代理請求 | 優先提供給 Docker daemon |
| SOCKS5 埠 | 供支援 SOCKS5 的應用程式使用 | 不要直接填入 Docker 的 HTTP_PROXY |
| 混合埠 | 同時接受 HTTP 與 SOCKS5 | 可使用,但要確認 Clash 版本支援且埠未被占用 |
| 外部控制器埠 | 供 API 或管理介面使用 | 這不是代理埠,切勿誤填 |
在 Clash Verge 或 Clash Verge Rev 中,先確認客戶端已啟動,模式可暫時切換為「全域」進行測試,並記下設定頁顯示的 HTTP 或混合代理埠。若全域模式能成功拉取、規則模式卻失敗,代表問題大多在分流規則;若兩種模式都失敗,則應檢查 daemon 是否真的連到該埠。
Linux 主機可用 ss 確認本機是否正在監聽代理埠:
將範例中的埠號替換為 Clash 實際設定。接著用 curl 模擬 Docker 的 HTTPS 代理連線:
如果回傳 401 Unauthorized,反而通常是好現象,表示已成功抵達 Docker Registry,只是該 API 需要驗證;如果顯示連線逾時或拒絕,才需要修正代理埠、Clash 狀態或防火牆。
小撇步
不要使用 localhost 作為 Docker Desktop 或 Docker 虛擬機中的代理主機。對容器而言,127.0.0.1 通常指向容器自身,不是宿主機上的 Clash。
3補齊 Docker Hub 分流規則
Docker Hub 的流程不只會連線到一個網域。CLI 通常先連到 Registry 取得 API 回應,再連到 Token 服務,下載映像層時還可能使用 CDN 或儲存服務。如果只為 docker.io 加入規則,前面的請求也許成功,後面的 Blob 下載仍然可能走到錯誤路徑。
在 Clash 配置的 rules 區段中,建議把 Docker Hub 相關規則放在通用的 GEOIP,CN,DIRECT、MATCH,DIRECT 或其他寬泛規則之前:
上面的 Docker 是策略組名稱,必須與你的實際配置一致;Proxy 也只是示例名稱。若訂閱配置使用「節點選擇」、「自動選擇」或其他名稱,請依照現有策略組替換,不要直接複製後造成規則指向不存在的組別。
修改後重新載入配置,打開 Clash 的連線日誌,再執行一次 docker pull。你應該能看到 registry-1.docker.io、auth.docker.io 等請求,並確認它們命中了預期策略。如果只看到瀏覽器請求,完全沒有 Docker 相關紀錄,通常表示 Docker daemon 尚未使用 Clash;規則本身此時不是主要問題。
注意
不要把所有流量永久切換成全域代理來掩蓋規則問題。全域模式適合短暫驗證,長期使用應為 Docker Hub 建立獨立策略組,並讓內部 Registry、公司網域與區域網路保持直連。
4排查 DNS、TUN 與 IPv6 路徑
DNS 問題經常被誤認為節點品質不佳。Docker 可能使用主機的 /etc/resolv.conf,也可能由 Docker Engine 自己轉發 DNS;Docker Desktop 還可能在虛擬機內部完成解析。因此,即使瀏覽器已透過 Clash 的 Fake-IP 或遠端 DNS 工作,Docker 仍可能解析到不可達的地址。
確認網域解析與連線
先在宿主機測試 Registry 網域:
如果主機解析成功,但 Docker 仍顯示 Could not resolve host,可在 Docker daemon 設定固定的 DNS。Linux 的 /etc/docker/daemon.json 可以加入:
DNS 位址應按照你的網路環境與安全政策選擇;公司或校園網路可能要求使用內部 DNS,不宜盲目套用公共 DNS。修改後需重新啟動 Docker,並再次查看日誌。
何時使用 TUN 模式
如果 Docker 流量不遵循系統代理,TUN 模式能在更底層接管路由,對 Linux 主機、Docker Desktop 虛擬網路或沒有代理選項的工具特別有幫助。開啟前請確認 Clash 具備必要權限,並留意系統中是否同時存在其他 VPN、WireGuard 或安全軟體,避免路由表互相覆蓋。
若只有部分節點逾時,也要測試 IPv4 與 IPv6。某些環境的 IPv6 路徑不完整,Docker 優先取得 AAAA 記錄後便會連到不可達地址。可以暫時停用主機 IPv6 或在 Clash 的 DNS 設定中選擇適合的解析策略,然後以相同命令重測。這是定位問題的方法,不代表所有環境都應永久關閉 IPv6。
5設定 Docker daemon 使用 Clash 代理
這是最關鍵的一步。Shell 中執行 export HTTP_PROXY=... 只會影響目前終端機啟動的程序,通常不會影響已經由 systemd 執行中的 Docker daemon。你必須把代理寫入 Docker 服務的環境設定,並重新載入服務。
Linux:使用 systemd drop-in
建立 Docker 服務的覆寫目錄:
建立 /etc/systemd/system/docker.service.d/proxy.conf,內容如下。請把埠號換成 Clash 的 HTTP 或混合埠:
NO_PROXY 很重要。它可避免公司內部 Registry、區域網路與本機服務被送往外部節點。若你的代理需要帳號密碼,請妥善處理特殊字元並避免把憑證直接公開在腳本或版本庫中。
套用設定並確認 Docker 是否讀取成功:
若你使用的是 rootless Docker,服務名稱可能是 docker.service 的使用者層級實例,需改用 systemctl --user 管理;不要把 rootful 與 rootless 的設定檔混用。
Docker Desktop:在應用程式中設定
Docker Desktop 的 daemon 通常位於專用虛擬環境,宿主機的環境變數不一定會傳入其中。請開啟 Docker Desktop 的設定,找到 Resources、Proxies 或 Docker Engine 相關區域,依版本選擇代理設定方式。若有專用的 HTTP Proxy 欄位,填入 Docker Desktop 能夠存取的宿主機位址與 Clash 代理埠,而不是直接照抄 Linux 的 127.0.0.1。
在 Windows 上可先確認 Clash 允許區域網路連線,再使用宿主機可被 Docker Desktop 解析的地址;在 macOS 上則要特別留意 macOS 防火牆與 Docker Desktop 網路隔離。設定完成後,完全退出並重新開啟 Docker Desktop,再以 docker info 和 docker pull hello-world 驗證。
6重新驗證、最佳化與常見問題
完成設定後,不要只測試一個小型映像。建議依序執行以下檢查:先拉取 hello-world 確認基本連線,再拉取常用的 nginx 或 alpine,最後執行實際專案的 docker compose pull。同時觀察 Clash 日誌、Docker daemon 日誌以及下載速度,確認請求沒有在不同節點之間頻繁跳轉。
若仍然逾時,可將自動選擇節點暫時改為固定節點,測試不同地區與不同協議。大映像下載失敗時,還要考慮節點的長連線穩定性、流量限制、MTU、公司防火牆與 Docker Hub 的暫時性服務異常。不要連續快速重試數十次,這可能觸發 Registry 的速率限制。
Docker pull 為什麼不跟隨瀏覽器代理?
因為瀏覽器是桌面應用程式,Docker pull 的實際請求通常由 Docker daemon 發出。兩者可能使用不同的程序權限、DNS、網路命名空間與代理環境,所以瀏覽器正常並不能證明 daemon 已經連上 Clash。
HTTP_PROXY 應該填 HTTP 還是 SOCKS5?
優先填入 Clash 的 HTTP 代理埠或混合埠,例如 http://127.0.0.1:7890。除非你的 Docker 版本與部署方式明確支援 SOCKS5,否則不要把 socks5:// 直接寫入 HTTP_PROXY 或 HTTPS_PROXY。
只加入 docker.io 規則,為什麼還是會卡住?
Docker Hub 還會使用 Registry API、Token 服務與映像層 CDN。請從 Clash 日誌確認實際命中的網域,並為 registry-1.docker.io、auth.docker.io 及相關 CDN 補上規則;同時確保這些規則位於通用直連規則之前。
出現 unauthorized 是不是代理設定錯誤?
不一定。對 Registry API 而言,未登入時看到 401 Unauthorized 很常見,反而表示網路路徑已經打通。若拉取私有映像,請執行 docker login,並檢查映像名稱、標籤以及帳號是否具備存取權限。
最後檢查清單
Clash 正在執行、代理埠類型正確、Docker 網域規則位於前方、DNS 可以解析、daemon 已重新啟動,且 NO_PROXY 沒有錯誤攔截內部服務。完成這五項後,多數 Docker Hub 逾時問題都能獲得解決。