使用buildx實現Docker跨平台編譯
背景
傳統CDN價格比較昂貴,PCDN資源使用節約成本的一種思路,而市面上的盒子資源往往使用的都是ARM32和ARM64的架構,部署方式往往都是使用Docker部署,我們需要打多個鏡像來適配不同的架構。如果想要在自己的服務器上制作鏡像,往往會出現千奇百怪的問題。
構建ARM鏡像的方法主要為下面這幾種
- 在ARM設備上進行編譯(最新的Mac都是ARM64架構)
- 模擬ARM環境,可以使用QEMU實現(參考博客:https://blog.csdn.net/xiaofengxing1/article/details/105490843/)
- 交叉編譯,交叉編譯器可以編譯出另一個系統平台的可執行文件,可以參考Golang的編譯,支持的特別友好。
構建多平台的Docker鏡像
Docker 在19.03版本引入了新的插件buildx,可以實現構建多平台的Docker鏡像。
開啟buildx功能
使用19.X版本還需要進行一些配置才可以開啟,在20.X版本Docker默認開啟了buildx。下面說下19.x的開啟方法
#開啟環境變量
export DOCKER_CLI_EXPERIMENTAL=enabled
##驗證:
docker buildx version
github.com/docker/buildx v0.6.1-docker 260d07a9a19b03df969787496419a0808a27ac61
#啟用binfmt_misc(Mac跳過)
docker run --rm --privileged docker/binfmt:66f9012c56a8316f9244ffd7622d7c21c1f6f28d
#驗證
ls /proc/sys/fs/binfmt_misc/
qemu-aarch64 qemu-arm qemu-ppc64le qemu-s390x register status
cat /proc/sys/fs/binfmt_misc/qemu-aarch64
enabled
interpreter /usr/bin/qemu-aarch64
flags: OCF
offset 0
magic 7f454c460201010000000000000000000200b7
mask ffffffffffffff00fffffffffffffffffeffff
創建並使用多平台構建器
#創建
docker buildx create --use --name mybuilder
#啟動
docker buildx inspect mybuilder --bootstrap
+] Building 18.9s (1/1) FINISHED
=> [internal] booting buildkit 18.9s
=> => pulling image moby/buildkit:buildx-stable-1 18.2s
=> => creating container buildx_buildkit_mybuilder0 0.6s
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
構建多平台鏡像
使用一個goalng代碼進行測試
package main
import (
"fmt"
"log"
"net/http"
)
func listenServer() {
http.Handle("/", http.HandlerFunc(lServe))
http.ListenAndServe(":8080", nil)
}
func lServe(w http.ResponseWriter, r *http.Request) {
log.Println("response success")
fmt.Fprintln(w, "hello world")
}
func main() {
listenServer()
}
Dockerfile文件
FROM golang:alpine
MAINTAINER jiangfeng
WORKDIR $GOPATH/src/test
ADD . ./
ENV GO111MODULE=on
ENV GOPROXY="https://goproxy.io"
RUN go build -o test_docker .
EXPOSE 8080
ENTRYPOINT ["./test_docker"]
使用Docker buildx進行構建
docker buildx build -t jiangfeng2010/buildx_test --platform=linux/arm/v7,linux/arm64,linux/amd64 . --push
過程如下:
如果只是想保留到本地,可以使用如下命令
docker buildx build -t jiangfeng2010/buildx_test --platform=linux/arm64 -o type=docker .
查看鏡像digests:
docker buildx imagetools inspect jiangfeng2010/buildx_test
Name: docker.io/jiangfeng2010/buildx_test:latest
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest: sha256:49ec85eb495d740b3fa9dae75fb22616c4f6484a019f97ad8e1c56eb9e888469
Manifests:
Name: docker.io/jiangfeng2010/buildx_test:latest@sha256:ee3d8adecd00615a14d25499344981c462c1da1d87e34f48f2215a9a628c502e
MediaType: application/vnd.docker.distribution.manifest.v2+json
Platform: linux/arm/v7
Name: docker.io/jiangfeng2010/buildx_test:latest@sha256:c5600c69cc83ea4204b8717a58fc4cb107ebaab9cc42c480041f7f3bc68de11e
MediaType: application/vnd.docker.distribution.manifest.v2+json
Platform: linux/arm64
Name: docker.io/jiangfeng2010/buildx_test:latest@sha256:8a27ba2ad897f7857dff83df617aac8c6ce2185d9d327f1342dc7d8a659c0642
MediaType: application/vnd.docker.distribution.manifest.v2+json
Platform: linux/amd64
問題與思考
1.針對不同的架構,我們往往使用的是不同的基礎鏡像,比如制作ARM32的設備,我們一般會使用arm32v7/debian,在arm64的設備上,我們使用的是arm64v8/debian:10,其實使用buildx的時候只是交叉編譯的某一個架構的專屬鏡像,改如何解決這個問題,一鍵打包多平台的鏡像。
2.傳統的盒子資源內存都是十分寶貴的,虛盒資源也希望鏡像越小越好,以上面做的測試為例,鏡像達到了驚人的300M,這會導致部分盒子跑步起來的情況,如何能把鏡像做到50M以內。