使用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以内。