Docker Hub 下載逾時:先分清楚是哪一段連線失敗

在桌面版 Clash 或 Mihomo 開啟後,瀏覽器可以正常載入網頁,並不代表 Docker pull 一定會跟著成功。Docker 的下載流程通常由背景執行的 Docker daemon 負責,而不是目前使用者正在操作的終端機或瀏覽器。這代表你即使已在 Clash Verge Rev、Clash for Windows 或 Mihomo Party 開啟系統代理,Docker daemon 仍可能完全不知道代理存在,最後在連線 registry-1.docker.ioauth.docker.io 或映像檔儲存 CDN 時出現逾時。

常見錯誤包括 context deadline exceededClient.Timeout exceeded while awaiting headersi/o timeoutnet/http: TLS handshake timeout,以及登入驗證成功後,真正下載 layer 時才失敗。這些訊息看起來相似,但可能分別由代理沒有套用、DNS 解析錯誤、規則命中 DIRECT、Docker Desktop 虛擬機路由異常或單一節點不穩定造成。排查時不要一開始就反覆更換節點或刪除所有設定,應先確認請求究竟由哪個程序發出、走哪個本機埠,以及 Clash 連線列表是否看得到流量。

合規提醒:Clash/mihomo 是本機流量轉送與規則管理工具,不提供遠端節點。請只在合法授權、公司政策與 Docker Hub 服務條款允許的範圍內使用,並避免公開貼出私有 Registry 的帳號、Token 或訂閱連結。

現象 優先懷疑項目 第一個檢查位置
瀏覽器正常,Docker pull 逾時 daemon 沒有繼承系統代理 Docker Engine 或 Docker Desktop 代理設定
Docker Hub 登入成功,layer 下載失敗 Registry 與 CDN 命中不同規則 Clash 連線列表與規則命中紀錄
所有映像檔都無法解析 Docker DNS、TUN DNS 或本機解析器異常 docker info、DNS 設定與 Clash DNS
小映像檔成功,大映像檔中途斷線 節點抖動、連線逾時或 CDN 路徑不穩 固定節點重試並觀察下載中斷位置

先理解 Docker 代理模型:終端機代理不等於 daemon 代理

Docker 常被誤解為「在終端機輸入指令,所以它會使用終端機的代理環境變數」。實際上,docker pull 通常只是 Docker CLI 將請求送給 Docker daemon;真正連到 Registry、驗證服務與 layer CDN 的,是 daemon 所在的服務程序。Linux 上它可能是 systemd 管理的 dockerd,Windows 與 macOS 上則經常位於 Docker Desktop 管理的 Linux VM 或背景服務內。

因此,下面這類設定只代表目前 shell 看到代理,不代表 daemon 一定會使用:

Shellexport HTTP_PROXY=http://127.0.0.1:7890
export HTTPS_PROXY=http://127.0.0.1:7890
docker pull alpine:latest

你仍然可以用這些變數測試 CLI 或其他工具,但 Docker daemon 是否採用,必須在它自己的服務設定中確認。另一個容易忽略的細節是:Clash 的 HTTP 混合埠與 SOCKS 埠用途不同。若 Docker 設定欄位要求 HTTP 或 HTTPS Proxy,通常應填入混合埠,例如 http://127.0.0.1:7890;不要把只接受 SOCKS5 的埠直接當成 HTTP Proxy 使用。不同 Clash 客戶端的預設埠可能不一樣,請以設定頁實際顯示值為準。

確認本機代理埠真的可用

先在同一台主機確認 Clash 的核心已啟動、目前設定檔已啟用,並記下 HTTP/混合代理埠。可用 curl 做簡單對照,但要注意這個測試只驗證目前使用者能否透過代理發出請求,不能單獨證明 Docker daemon 已完成設定。

Shellcurl -I -x http://127.0.0.1:7890 https://registry-1.docker.io/v2/
docker info

對 Docker Hub Registry 而言,收到 401 Unauthorized 不一定是壞事;它通常表示請求已抵達 Registry,只是尚未提供登入驗證。相反地,如果 curl 一直卡住、連線拒絕或 TLS 逾時,應先處理 Clash 埠、節點、DNS 或規則問題,再繼續修改 Docker。

Linux 與 Docker Desktop:把代理設定到正確的服務層

在 Linux 使用 systemd 管理 Docker 時,常見做法是為 Docker service 建立 drop-in 設定。以下範例以本機 HTTP 混合埠為例,實際埠號請換成你的 Clash 設定。NO_PROXY 則應保留本機、內網與 Docker 常用的內部位址,避免把本地 Registry 或容器間通訊錯誤送進外部代理。

Shellsudo mkdir -p /etc/systemd/system/docker.service.d
sudo nano /etc/systemd/system/docker.service.d/proxy.conf
INI[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,.internal"

儲存後重新載入服務設定並重啟 Docker:

Shellsudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl show --property=Environment docker
docker info

若輸出裡沒有新的 HTTP_PROXYHTTPS_PROXY,代表設定檔位置、語法或服務名稱可能不正確。重新啟動後也要檢查 Docker daemon 日誌,確認它沒有因代理格式錯誤而立即退出。代理網址若包含帳號密碼,特殊字元需要正確 URL 編碼,否則 daemon 可能讀到一個看似存在、實際無法連線的網址。

Docker Desktop 的情況略有不同。Desktop 管理自己的引擎與虛擬網路,主機上的 127.0.0.1 不一定等同於引擎 VM 內的 127.0.0.1。請先開啟 Docker Desktop 的設定,找到 Resources、Proxies 或 Docker Engine 相關頁面,確認是否有專用的代理設定欄位。若你只在 Windows 或 macOS 的系統代理中填入 Clash,Docker Desktop 可能仍然不會自動繼承。

重要:Docker Desktop 與 Clash 都可能建立虛擬網路介面。若 Docker Desktop 引擎位於 VM 內,直接填入 127.0.0.1 可能指向 VM 自己,而非主機上的 Clash。此時應依 Docker Desktop 版本提供的主機代理位址或自動代理功能設定,並在 Clash 連線列表確認是否真的出現 Docker 流量。

TUN 模式與規則分流:解決「有代理但走錯路」

如果 Docker daemon 無法方便地配置傳統 HTTP Proxy,TUN 模式可以提供另一條路徑。TUN 會在網路層接管符合條件的流量,對不支援系統代理的服務較有幫助。不過,TUN 並不是開啟後所有封包都會自動走代理;路由模式、DNS 模式、私有網段排除,以及 Clash 規則順序都會影響結果。

在 Clash Verge Rev、Mihomo Party 或其他 Mihomo 客戶端中,先確認 TUN 已獲得所需的系統權限,並確認核心日誌沒有出現介面建立失敗、路由寫入失敗或 DNS hijack 錯誤。若同時開啟系統代理與 TUN,部分環境可能出現重複轉送或回環,建議先用單一模式測試:要嘛使用 Docker daemon 的 HTTP Proxy,要嘛使用 TUN 接管,不要一次疊加多層代理。

規則方面,至少要觀察下列主機是否被正確處理:

  • registry-1.docker.io:Docker Registry API 的主要入口。
  • auth.docker.io:公開映像檔常見的驗證服務。
  • hub.docker.com:登入、搜尋與網頁介面使用的主機,不等於所有 pull 流量。
  • 實際 CDN 主機:layer 下載可能被導向其他儲存或 CDN 網域,必須以 Clash 連線紀錄裡的實際主機補充規則。

不要只新增 DOMAIN-SUFFIX,docker.io 就停止檢查,也不要直接使用過寬的 DOMAIN-KEYWORD,docker。真正重要的是在執行一次 pull 時,查看連線列表中的主機名稱、命中規則與策略群組。若 Registry 走代理、CDN 卻命中 DIRECT,便會出現登入成功但 layer 下載失敗的典型症狀。對測試而言,先把相關主機固定送往同一個穩定策略群組,再逐步收窄規則,通常比一開始追求最細分流更有效率。

DNS、認證與 CDN:三個容易被忽略的瓶頸

Docker pull 的第一步不只是連線到一個固定 IP。它可能先解析 Registry,取得驗證資訊,再依回應導向實際 layer 儲存位置。只要其中一個主機解析異常,就可能表現成整個映像檔下載失敗。尤其在 TUN 模式下,如果主機、Docker VM 與 Clash 各自使用不同 DNS,會形成「瀏覽器解析正常、Docker 解析錯誤」的分裂。

可以先用以下指令確認 Registry 是否有解析結果,並檢查 Docker 引擎目前看到的資訊:

Shellgetent hosts registry-1.docker.io
getent hosts auth.docker.io
docker info
docker login
docker pull hello-world

docker login 的結果要分開理解。若帳號驗證失敗,應處理憑證、Token 或帳戶權限;若登入成功但 docker pull 仍逾時,問題更可能在 layer CDN、代理路徑或 DNS。測試時先選擇小型公開映像檔,例如 hello-worldalpine,避免大型映像檔下載時間過長,讓網路問題與單純檔案大小混在一起。

若你使用自訂 DNS,請避免同時在主機、Docker daemon、Clash fake-ip 與 TUN 設定中加入互相衝突的解析策略。Fake-IP、redir-host、hosts 映射與私有網段排除都可能改變 Docker 看見的結果。排查時可暫時使用較保守的 DNS 模式,清除 Docker Desktop 或本機的暫存解析資訊,再重新測試;完成定位後再恢復進階設定。不要把「改 DNS」當成萬用解法,因為 DNS 正常只能代表找到位址,不能證明 TLS、代理驗證與下載長連線都穩定。

建議的實作順序:用最少變更找出根因

  1. 固定測試條件:停止多餘的 VPN、其他代理軟體與下載器,只保留一個 Clash 設定檔、一個策略群組與一個小型公開映像檔,記下錯誤時間。
  2. 確認核心狀態:在 Clash 客戶端確認設定檔已啟用、節點可用、HTTP 混合埠正在監聽,並檢查連線列表是否能看見 Registry 相關主機。
  3. 先測代理本身:使用 curl -I -x 測試 registry-1.docker.io,若連代理測試都失敗,先不要修改 Docker daemon。
  4. 設定正確服務:Linux 修改 dockerd 的 systemd drop-in;Docker Desktop 則使用 Desktop 提供的代理或引擎設定,不要只修改目前 shell 的環境變數。
  5. 重新啟動並驗證:重載 daemon 後執行 docker info,再用 docker pull hello-world 測試,過程中同步觀察 Clash 命中規則。
  6. 處理 DNS 與 CDN:若驗證成功但 layer 失敗,記錄所有實際連線主機,補上必要規則,並用固定節點做第二次對照。
  7. 最後才啟用 TUN:當傳統代理路徑已確認可用,再以 TUN 測試未能繼承代理的 Docker 流量,避免同時更動代理、DNS 與路由而失去比較基準。

如果問題只在某一個節點發生,請不要急著重寫規則。先將 Docker Hub 相關主機固定到另一個出口,觀察 TLS handshake、下載速度與中斷時間是否改變。若所有節點都失敗,才回頭檢查 daemon 代理是否被服務管理器清掉、Docker Desktop VM 是否能到達主機代理,以及防火牆是否阻擋了對應埠。排障的重點不是讓錯誤訊息消失,而是確認每一層都能被獨立驗證。

常見問題

為什麼瀏覽器可以開 Docker Hub,Docker pull 卻逾時?

瀏覽器通常會遵循系統代理或瀏覽器自己的代理設定,但 Docker pull 多半由背景 daemon 發出。兩者可能使用不同 DNS、不同網路命名空間,甚至位於不同的 Docker Desktop VM。請先在 Clash 連線列表確認 Docker 流量是否出現,再到 daemon 或 Docker Desktop 的代理設定中補上正確配置。

Docker 代理應該填 Clash 的 HTTP 埠還是 SOCKS 埠?

若 Docker 設定欄位要求 HTTP/HTTPS Proxy,優先使用 Clash 的 HTTP 混合埠,格式通常是 http://127.0.0.1:埠號。只有在 Docker 或中間代理明確支援 SOCKS5 時,才使用 SOCKS 埠。填錯協議時,常見結果是連線被拒絕、TLS 直接失敗,或請求長時間沒有回應。

開啟 TUN 後是否可以刪除 Docker 的代理設定?

不一定。TUN 能否接管 Docker 流量,取決於 Docker Desktop 的虛擬網路、作業系統路由、權限與 DNS 行為。建議先保留一條可驗證的 daemon 代理路徑,確認它能正常 pull,再單獨測試 TUN。若兩種方式同時使用造成迴路或重複代理,應選擇較穩定且容易觀測的一種。

為什麼小映像檔成功,大型映像檔仍會中途失敗?

大型映像檔會產生較長的下載時間與更多 layer,對節點抖動、閒置逾時、CDN 路由與磁碟空間更敏感。請先固定節點、確認磁碟與 Docker 儲存空間充足,再查看失敗時的實際 CDN 主機與 Clash 規則。若每次都在不同 layer、不同時間點失敗,通常比單一固定 layer 報錯更像是連線穩定性問題。

相比之下,部分同類代理工具只提供瀏覽器級系統代理,對 Docker daemon、Docker Desktop VM 與 TUN 路由的說明不夠完整,使用者很容易在「瀏覽器能用、容器不能用」時反覆重裝或盲目更換設定。Clash 官網 則把代理埠、daemon 服務層、DNS、規則命中與 TUN 接管拆開說明,方便你依本文順序逐層驗證,而不是靠猜測修改整份 YAML;如果你正準備在桌面環境排查 Docker Hub 逾時,不妨前往下載合適的 Clash 官網 客戶端,再搭配連線日誌開始測試。