使用遠端 Windows 主機編譯 Docker Image

自從換了 ARM 架構的蘋果晶片 M2 Mac 後,在本機編譯 Docker Image 的速度大幅下降, 猜測是因為架構不同,中間透過 QEMU 轉換效率極低,導致速度變慢。

最近突然想到,有沒有可能在本地開發,然後把編譯 image 的工作交給一台強大的 Windows 主機, 因為手邊正好有一台幾乎只用來上網的 13700K Windows 主機, 結果發現這個想法可行,而且速度比本機還「飛」快,方法也很簡單。

Windows Docker 設定

以下假設 Windows 主機的區域網路 IP 為 192.168.1.101,請將 IP 換成你自己的:

  1. 安裝 Docker Desktop
  2. 於 Docker Desktop 的設定中,啟用「Expose daemon on tcp://localhost:2375 without TLS」。
  3. 待設定生效後訪問「http://127.0.0.1:2375」,如果看到 {"message":"page not found"} 回應,表示有連線成功。
  4. 以你的區域網路 IP 訪問相同的 port http://192.168.1.101:2375,沒有得到任何回應是正常的,這是因為 Docker 跑在 Windows 的 WSL2 中,預設只允許 localhost 訪問。
  5. 以 Admin 運行 PowerShell,執行
    netsh interface portproxy add v4tov4 listenport=2376 listenaddress=0.0.0.0 connectaddress=127.0.0.1 connectport=2375
    

    這會將 2376 port 的請求轉發到 2375,並讓 2376 port 可以被區域網路的其他電腦訪問。
    再次訪問 http://192.168.1.101:2376,如果看到 {"message":"page not found"} 回應,表示有連線成功。

  6. 設定防火牆,對外公開 2376 port。
    打開網際網路設定找到已連線的網路 → 進行防火牆及安全設定 → 進階設定。

    新增一個 Inbound Rule,設定如下:規則選「連接埠」→ 連接埠選「特定本機連接埠」→ 連接埠輸入「2376」。

完成以上設定後,如果可以在 Mac 上訪問 Windows 主機 http://192.168.1.101:2376 看到 {"message":"page not found"} 回應,表示設定成功。

Mac 開發端

Docker 指令用法都一樣,只要在指令前加上 -H 參數指定遠端 Windows 主機的 IP 與 port:

docker -H 192.168.1.101:2376 image ls

只要指令有即時回應,沒有跳 error,即表示透過 docker CLI 與遠端 Windows 主機連線成功。

也可以使用 DOCKER_HOST 環境變數作為設定遠端主機 IP 與 port:

export DOCKER_HOST=192.168.1.101:2376
docker buildx build --platform linux/amd64 .
docker image ls

讓我意外感到方便的有兩點:

  1. 只要開發端具有 push 權限,使用 docker push 作用於遠端,不需要額外的設定,就可以把 image 推到 registry server。
  2. docker build 會把 context 傳到遠端主機,完全不需要額外的設定,而且因為是區域網路,快到就像在本機直接傳輸 context 一樣。

效能比較

於開發端與遠端各跑一次 no cache build,結果如下:

  • 開發端:Building 700.2s (17/17) FINISHED → 11 分鐘 40 秒
  • 遠端:Building 70.7s (17/17) FINISHED → 1 分鐘 10 秒

有這麼誇張的差異,當然跟 CPU 本身的效能也有關。

build image 當中最後一個環節是每次編譯必做的 CSS/JS 編譯、壓縮指令, 直接在本機運行該指令需要 44 秒;本機 docker build 需要 336 秒;遠端 docker build 只需要 15 秒。

通常每次版本更新,需要 build image 的時候,前面幾個環節都不會變動,會被快取,只有最後一個環節會變動, 所以這對我來說是幾乎就是 20 倍以上的效率提升,太舒服啦!

上述介紹的方法是應用在自家區域網路內,如果是在公開網路上,也就是把區域網路 IP 改成實體 IP 也是可以的, 但請務必注意安全性,以免 image 被竊取,使用 VPN 或是其他安全機制來限制此 Windows docker host 被外部連線, Docker Host 也有 SSH 的方式可用,有興趣的讀者可搜尋關鍵字研究。

留言