[教學] 用 Docker 的 buildx 輕鬆多架構編譯 (multi-architecture build)

Docker 可以在程序層級上做為封裝系統環境的技術,並方便部署(或移轉)到別的機器上,
比起可以做到相同目標的 虛擬機 (VM) 比它輕量快速,近期成為熱門技術之一。
這麼好的技術還是有其相關限制的。例如: Docker image (映像檔) 仍受限於 CPU 架構 (architecture),
但標準的 Docker 的指令預設只能編譯一個 CPU 架構 (architecture)。

接下來要介紹算是某種新功能,新的 buildx 指令,讓 Docker 編譯製作 image (映像檔) 時,
能一次編譯各種你要的 CPU 架構的 image。


不知道您有沒有自己做過 Docker image 過?
我們複習一下標準的 Docker 編譯

原有的 docker build 流程

標準的 Docker 編譯如下:

$ docker build . -t MY_ACCOUNT/my-awesome-image:latest

相關說明:

  • . 點 (dot):代表當前目錄,也是預設名稱 Dockerfile 檔案名稱
  • -t 參數:給予 image 名字,如果要上傳到 Registry 倉庫的話,要改成對應名字
    例如: dockerHub 的格式 帳號 / 名稱,這個例子為: MY_ACCOUNT 帳號下的 my-awesome-image 套件,版本為 latest

再來就是用指令登入你的 dockerHub

$ docker login

輸入帳號與密碼

最後,上傳你的 image 到 Registry 倉庫

$ docker push MY_ACCOUNT/my-awesome-image:latest

但如今,宿主 (Host) 的 CPU 架構會因為你的使用伺服器環境的不同而不同
例如:你買了 Apple silicon (M1) 晶片,預設 CPU 架構跑 arm64
又例如:你想把你的 Docker 環境跑在樹莓派 (Raspberry Pi), CPU 架構跑 armv7 或者 arm64

各種情境,你可能會需要把你的 Docker 編譯模組換成能一次編輯多架構的。

新的 buildx 指令

要達成此目的,做法有二種,只講其中一種, docker buildx 指令

docker buildx 算是全新的指令,可以在官網去下載設定。

$ docker buildx version

查看是否有安裝,執行結果如下(我列出我的環境,你的可能會跟我不一樣):

$ docker version
Client:
 Cloud integration: v1.0.22
 Version:           20.10.13
 API version:       1.41
 Go version:        go1.16.15
 Git commit:        a224086
 Built:             Thu Mar 10 14:08:43 2022
 OS/Arch:           darwin/arm64
 Context:           default
 Experimental:      true

Server: Docker Desktop 4.6.0 (75818)
 Engine:
  Version:          20.10.13
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.16.15
  Git commit:       906f57f
  Built:            Thu Mar 10 14:05:37 2022
  OS/Arch:          linux/arm64
  Experimental:     false
 containerd:
  Version:          1.5.10
  GitCommit:        2a1d4dbdb2a1030dc5b01e96fb110a9d9f150ecc
 runc:
  Version:          1.0.3
  GitCommit:        v1.0.3-0-gf46b6ba
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

查看有哪些架構可用

$ docker buildx inspect --bootstrap
Name:   mybuilder
Driver: docker-container

Nodes:
Name:      mybuilder0
Endpoint:  unix:///var/run/docker.sock
Status:    running
Platforms: linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6

以小弟的電腦來說,有這麼多,你也不一定要全部都使用。

我選了幾個常用的

  • linux/amd64:適合 x64 的環境(不管宿主主機是 linux 還是 Mac )
  • linux/arm64:適合 arm64 的環境(例如:Apple silicon (M1) 晶片)
  • linux/arm/v7:適合 arm 環境(例如:樹莓派)

接下來,我們建立一個 builder 並使用(初次安裝執行一次即可)

$ docker buildx create --use

(其實他是建立 builder 與 使用 builder 的簡化版,相關指令我列在下方)

建立 builder

$ docker buildx create --name mybuilder

使用該 builder

$ docker buildx use mybuilder

列出有哪些 builder

docker buildx ls

更新原有 build 指令

我們更新原有 build 指令

$ docker build . -t MY_ACCOUNT/my-awesome-image:latest

變成這樣

$ docker buildx build --load -t MY_ACCOUNT/my-awesome-image:latest --platform linux/amd64 .

(為了開發方便,我們先編譯一個平台架構)

效果二者一樣。

如果 Dockerfile 編好了,準備編譯並打包上傳 dockerhub 可以用以下指令:

$ docker buildx build --push -t MY_ACCOUNT/my-awesome-image:latest --platform linux/amd64,linux/arm64,linux/arm/v7 .

加個 --push 參數就可以在編譯完成的時候,一併做上傳。

瀏覽你的 dockerHub 帳號,會看到多種你選取的平台出現在 dockerHub 中。

小提醒:別使用 docker push 指令,截稿至今,它還不支援多架構映像檔上傳,它只會幫你上傳單一架構而已,
你也可以測試看看。

以上就是這次的內容,希望對大家有幫助。

參考資料