本文目錄
先確定超時發生在 Docker、建置還是已經執行的容器
VS Code Dev Containers 走 Clash 不是只填一個代理位址。拉基礎映像檔、執行 Dockerfile、容器內執行 Git,以及遠端擴展下載分別由不同處理程式發起。
在「Dev Containers」輸出裡找到失敗命令所屬的階段,再把代理傳給對應處理程式。否則 containerEnv 寫得再完整,也修不了尚未建立的容器。
四個網路位置
| 失敗動作 | 實際發請求的元件 | 設定入口 |
|---|---|---|
| docker pull / 拉基礎映像檔 | Docker daemon | Docker Desktop 或 daemon 代理 |
| Dockerfile RUN apt/npm | 映像檔建置階段 | build args 或 BuildKit 設定 |
| 容器內 curl/Git/pip | 正在執行的容器 | containerEnv、remoteEnv 或工具設定 |
| VS Code 遠端擴展下載 | Dev Containers 遠端服務 | 容器環境與擴展自己的網路請求 |
錯誤出現在「Starting Dev Container」之前,通常不能靠 .devcontainer/devcontainer.json 中的 containerEnv 修復,因為容器尚未執行。先記下失敗命令和 VS Code 輸出面板中的階段。
- VS Code 主機機負責拉取擴展與啟動 Docker
- Docker 建置階段讀取 build args 或 Docker 代理設定
- 執行中的容器讀取 containerEnv
- 遠端擴展與終端讀取 remoteEnv 或工具自己的設定
失敗發生在哪一段,就只給那一段代理。不要把主機機、建置階段和容器執行階段當成同一套環境變數。
容器中的 127.0.0.1 不是主機機
Clash 執行在主機機時,容器中的 http://127.0.0.1:7890 指向容器自己。Docker Desktop 在 Windows 與 macOS 提供 host.docker.internal;Linux Docker 可以透過 host-gateway 映射同名位址。
Clash 若只監聽主機機回環位址,容器仍可能連不到。開啟允許區域網路或把 mixed-port 監聽到容器可達介面時,同時用系統防火牆限制來源;不應把 7890 直接暴露給公用網路。
CLASH_HOST=host.docker.internal
CLASH_PORT=7890
getent hosts "$CLASH_HOST" || true
curl -v -x "http://$CLASH_HOST:$CLASH_PORT" https://www.example.com/
# Linux Docker 临时测试
docker run --rm --add-host=host.docker.internal:host-gateway curlimages/curl:latest -v -x http://host.docker.internal:7890 https://www.example.com/Linux 主機機把 host-gateway 寫進 devcontainer.json
{
"runArgs": [
"--add-host=host.docker.internal:host-gateway"
]
}修改後執行 Dev Containers: Rebuild Container,舊容器不會自動獲得新的 hosts 映射。
Docker Compose 專案則在服務下使用 extra_hosts: ["host.docker.internal:host-gateway"]。不要同時在兩個地方重複新增。
連接埠可達後,再給執行中的容器設定代理
上一步只有在 curl 收到 HTTP 回應後才算透過。接下來把同一個位址交給容器內的終端和 VS Code 遠端處理程式;如果 mixed-port 不是 7890,下面三處連接埠必須一起修改。
{
"containerEnv": {
"HTTP_PROXY": "http://host.docker.internal:7890",
"HTTPS_PROXY": "http://host.docker.internal:7890",
"NO_PROXY": "localhost,127.0.0.1,::1,host.docker.internal"
},
"remoteEnv": {
"HTTP_PROXY": "${containerEnv:HTTP_PROXY}",
"HTTPS_PROXY": "${containerEnv:HTTPS_PROXY}",
"NO_PROXY": "${containerEnv:NO_PROXY}"
}
}HTTPS_PROXY 使用 http:// 開頭通常是正確的:它表示透過 HTTP CONNECT 代理存取 HTTPS,並不是把代理連接埠本身變成 HTTPS。NO_PROXY 還應加入 Compose 服務名、公司內部網路與本機開發網域,否則容器存取資料庫或 API 時可能繞去 Clash。
儲存後 Rebuild Container,再在新終端執行 env | grep -i proxy。已有終端處理程式不會自動重新整理 remoteEnv。
映像檔拉取與 Dockerfile 建置要單獨設定
FROM 映像檔拉取由 Docker daemon 發起,應在 Docker Desktop 的 Proxies 頁面或 daemon 設定中處理。Dockerfile 的 RUN 命令發生在建置容器裡,可以用 build.args 傳入臨時代理,但不要把個人連接埠或認證資訊寫成 ENV 留在映像檔層。
{
"build": {
"dockerfile": "Dockerfile",
"args": {
"HTTP_PROXY": "http://host.docker.internal:7890",
"HTTPS_PROXY": "http://host.docker.internal:7890",
"NO_PROXY": "localhost,127.0.0.1"
}
}
}curl 成功後,Git、apt 和擴展仍要各測一次
在容器終端確認 HTTP_PROXY、HTTPS_PROXY 和 NO_PROXY 已經出現,然後分別執行 Git 和套件管理員命令。Git 通常會讀取環境變數;若它仍指向舊位址,再檢查 Git 自己的設定。
遠端擴展由容器側 VS Code Server 下載。修改 remoteEnv 後必須 Rebuild Container,再從輸出面板觀察 marketplace 請求。
REPO_URL='https://github.com/octocat/Hello-World.git'
env | grep -i '_proxy'
git config --show-origin --get-regexp 'http.*proxy' || true
git ls-remote "$REPO_URL"
# 只有 Git 不读取环境变量时才临时写入
git config --global http.proxy http://host.docker.internal:7890
git config --global --unset-all http.proxycurl 成功,Git 仍連線舊連接埠
執行 git config --show-origin --get-regexp 'http.*proxy',清理使用者或儲存庫殘留。
apt update 失敗
查看實際儲存庫網域、憑證與 /etc/apt/apt.conf.d 中的獨立代理。
專案能執行,遠端擴展裝不上
在 Dev Containers 日誌中找 marketplace 請求,確認遠端服務繼承了 remoteEnv。
容器能聯網,本機資料庫連線失敗
把資料庫服務名和私有網段加入 NO_PROXY。
Rebuild 階段仍失敗
回到 daemon 拉映像檔或 Dockerfile build args,不繼續改執行容器。
共享儲存庫不要寫死個人代理
團隊專案可以在 devcontainer.json 使用 ${localEnv:HTTP_PROXY} 讀取開發者本機環境,或提供不含實際位址的 .env.example。
README 裡寫清楚 HTTP_PROXY 應是完整位址,例如 http://host.docker.internal:7890。提交前檢查代理 URL 中沒有使用者名稱、密碼和 token。
驗證完成後應能分別完成 docker pull、Rebuild Container、容器內 Git/套件管理員和本機服務存取。哪一項失敗,就保留該階段的日誌,不把四層網路再次混成「Dev Container 沒網」。
