业务需要同时运行在 x86_64 和 arm64 两种架构的机器上,贫穷让公司选择了跨平台构建。
安装 buildx
buildx 是作为 docker cli 的一个插件存在的,所以如果已经在系统中配置了 docker 仓库的话,直接用系统的包管理器安装 docker-buildx-plugin
即可,这也是最推荐的方案。
如果非要手动安装,可以自行从 docker buildx github releases 进行下载,然后拷贝到 /usr/local/lib/docker/cli-plugins
目录下即可。仅当前用户使用的话也可以放到 $HOME/.docker/cli-plugins
目录。
初始化构建器
docker buildx 跨平台打包镜像有两种方案,第一种使用不同架构的机器来做 worker ,但是如果有这种资源我还是比较倾向用 kaniko,所以这里暂不赘叙,有需求可以看一下官方文档。这里主要介绍一下第二种,通过 binfmt_misc 和 QEMU 来实现跨平台构建。
buildx 的跨平台构建,实际上是通过 QEMU 作为构建器后端,然后再利用 binfmt_misc 模块注册 QEMU 作为其他CPU架构可执行文件的处理程序来实现的。我们首先需要先启用 binfmt_misc,这里可以通过 tonistiigi/binfmt 这个脚本镜像直接实现:
1 2 3
| # 这里最后的 --install all 是安装所有支持的架构,如果只有特定需求也可以手动指定 # 例如 --install arm64,riscv64,arm $ docker run --privileged --rm tonistiigi/binfmt --install all
|
执行完毕之后,可以通过这两种方法验证是否已经成功开启 binfmt_misc :
1 2 3 4 5 6 7 8 9
| # 该命令可以查看当前所有可用构建器,如未启用则 PLATFORMS 应该仅支持 amd64 和 386 相关的架构 $ docker buildx ls NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS default* docker \_ default \_ default running v0.12.5 linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/386, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
# 该命令可以查看 binfmt_misc 的开启状态 $ cat /proc/sys/fs/binfmt_misc/status
|
确认无误后,即可开始创建构建器:
1
| $ docker buildx create --name mybuilder --bootstrap --use
|
创建完之后就有了一个可用的,名称叫 mybuilder 构建器,这里再详细介绍一些参数:
1 2 3 4 5 6 7
| $ docker buildx create \ --name mybuilder \ --driver=docker-container \ --driver-opt "network=host" \ --config /etc/buildkitd.toml \ --bootstrap \ --use
|
第一个参数 –name 就不用讲了,我们从第二个开始。
–driver=docker-container
其实在安装 docker buildx 之后,就可以通过 docker buildx ls 看到一个 default 构建器,但是这个构建器并不可用到跨平台构建上,即使启用了 binfmt_misc 。原因就是因为这个 driver。docker driver 的构建器只会有一个 default ,无法单独指定创建,不使用 buildx 的时候的 docker 操作,其实都是在使用这个构建器。
docker driver 考虑的更多的是简单和易用两个方面,而我们这里指定的 docker-container driver 比 dokcer driver 要灵活很多,可以指定 BuildKit 版本、通过 QEMU 进行跨平台构建以及更高级的缓存导出功能(ps.这里的更高级指的是相对于 docker drvier 只能将缓存导出到镜像中而言)。同时也是 docker buildx create
默认 driver,所以也基本不用指定。
除了 docker 和 docker-container 之外还有 kubernetes 和 remote 两个 driver,主要差异在于使用场景上,这里不多缀述,有兴趣可以看一下官方文档。
–driver-opt “network=host”
构建器实际上是打开一个 buildkit 容器进行构建,如果对这个容器有任何的配置需求,基本都是写在这个参数中,包括资源限制、启动的镜像、重启策略、环境变量以及我们这里写的网络的配置,具体可选配置可参考该表格。
这里单独使用了一个 network=host 是因为遇到过构建时网络情况和预期不一致的情况。譬如拥有两个dns,一个用于内网一个用于外网,如果不使用 host 网络,则构建时就会使用 docker 内部 dns。作为一个构建镜像的基础服务,为了规避可能存在的干扰,还是建议使用 host 网络。
–config /etc/buildkitd.toml
与所有服务一样的,buildkit 也是有配置文件的,具体的配置内容可以参考官方的配置文件。当然了,这里的大多数配置都是无须更改的,这里单独将 config 拎出来,是因为有一种比较常见的情况是,构建的 base image 来自私有仓库,使用 http 或者自签 SSL 证书。
因为构建时并不在物理机而是在 buildkit 镜像内,所以它也没办法读 /etc/docker/daemon.json
的配置,必须要单独配置,例如:
1 2 3
| [registry."192.168.189.102:5000"] http = true insecure = true
|
–bootstrap –use
bootstrap 就是创建的同时启动这个构建器使用的 buildkit 容器,use 就是创建的同时切换到这个构建器。
开始构建
前置准备虽然漫长,但是实践总是很简单的,首先准备一个Dockerfile:
1 2
| FROM alpine:3.19 RUN apk add curl
|
然后执行构建命令:
1 2 3 4 5 6
| $ docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t ccr.ccs.tencentyun.com/openimage/alpine:3.19 --push .
... (以下省略一堆输出) => => pushing manifest for ccr.ccs.tencentyun.com/openimage/alpine:3.19@sha256:d2ca9689374079757822ac8a9bd1e298a96fd10fc7648c4a5043499f61a1e432 2.1s => [auth] openimage/alpine:pull,push token for ccr.ccs.tencentyun.com
|
命令执行成功,构建完成,当你使用 --push
参数的时候,buildx 甚至自动创建了 manifest ,保证了多个架构镜像共用一个 tag,可以通过 docker buildx imagetools inspect
进行验证。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| $ docker buildx imagetools inspect ccr.ccs.tencentyun.com/openimage/alpine:3.19
Name: ccr.ccs.tencentyun.com/openimage/alpine:3.19 MediaType: application/vnd.oci.image.index.v1+json Digest: sha256:d2ca9689374079757822ac8a9bd1e298a96fd10fc7648c4a5043499f61a1e432
Manifests: Name: ccr.ccs.tencentyun.com/openimage/alpine:3.19@sha256:dc6b015793c2ac537f61ec80348a7f34739cfa6580813f24e813d653fc37faf3 MediaType: application/vnd.oci.image.manifest.v1+json Platform: linux/amd64
Name: ccr.ccs.tencentyun.com/openimage/alpine:3.19@sha256:a3df735a618653a5bb73c1f09fe73feb30f352c19760326155bebf29172a7de5 MediaType: application/vnd.oci.image.manifest.v1+json Platform: linux/arm64
Name: ccr.ccs.tencentyun.com/openimage/alpine:3.19@sha256:1cf066565331d3feb598c1d7fb5a181a151bd6a965ffd891f9ab459e0a708afb MediaType: application/vnd.oci.image.manifest.v1+json Platform: linux/arm/v7
Name: ccr.ccs.tencentyun.com/openimage/alpine:3.19@sha256:d43c80d6216bc643f283163c89b6f3d5813d02e8fa76f5a86115bcf8b16d10a2 MediaType: application/vnd.oci.image.manifest.v1+json Platform: unknown/unknown Annotations: vnd.docker.reference.digest: sha256:dc6b015793c2ac537f61ec80348a7f34739cfa6580813f24e813d653fc37faf3 vnd.docker.reference.type: attestation-manifest
Name: ccr.ccs.tencentyun.com/openimage/alpine:3.19@sha256:c2e29cae1de1f6d4f285ed5055c871c745862054c8693b2e4d51fa9c3cb49954 MediaType: application/vnd.oci.image.manifest.v1+json Platform: unknown/unknown Annotations: vnd.docker.reference.digest: sha256:a3df735a618653a5bb73c1f09fe73feb30f352c19760326155bebf29172a7de5 vnd.docker.reference.type: attestation-manifest
Name: ccr.ccs.tencentyun.com/openimage/alpine:3.19@sha256:b593bc641ba6ea8d046ff4d6e78f73ac4be1422c1ad3db0fc23dfc07950d049b MediaType: application/vnd.oci.image.manifest.v1+json Platform: unknown/unknown Annotations: vnd.docker.reference.digest: sha256:1cf066565331d3feb598c1d7fb5a181a151bd6a965ffd891f9ab459e0a708afb vnd.docker.reference.type: attestation-manifest
|
最后更新时间: