之前的文章中 [使用 docker buildx 实现多平台编译 - 环境篇]介绍了如何部署 docker buildx 环境。
笔者本文将要分享自身在使用中的几个比较有意义的案例
docker buildx
本身运行于容器环境, 所以 scheduler 和 builder 本机配置(ex, /etc/hosts
, /etc/docker/daemon.json
) 的大部分配置和场景 其实是不可用的。ssh://user@host
可以方便的执行远程构建, 尤其是在构建最基础的镜像,需要海外镜像时。docker buildx
现在仍然处于实验阶段,在不断的更新。 尤其是在 Dockerfile 的使用上有很多新特性, 可以参考[dockerfile experimental]github action
可以完全托管。之前的文章中, 我们通过 qemu
模拟了多架构的环境。 但实际在使用中, 在模拟架构中执行工作效率是特别低的, 如果已经执行某些项目编译, 那你就应该感同身受了。
如笔者之前维护的 opencv 双架构的项目, 通过 github action 进行跨平台编译, 长达三四小时。而在本架构下只需要短短的10几分钟。
因此, 在同架构下执行编译或其他工作的需求就特别迫切了。
docker buildx
可以支持 专机专用 - 根据机器架构执行对应的任务。docker
本身也支持基于 ssh://user@host
协议的远程调用。 通过免密码证书, 非常容易管理。假设有三台机器, 且 scheduler 能通过证书免密码登录两台 builder。
用途 | 主机地址 | CPU 架构 |
---|---|---|
scheduler | 10.100.100.10 | - |
arm64 builder | 192.168.100.101 | arm64 / aarch64 |
amd64 builder | 192.168.100.102 | amd64 / x86_64 |
在 scheduler(10.100.100.10) 创建 remotebuilder , 命令如下
ARM64=ssh://root@192.168.100.101 AMD64=ssh://root@192.168.100.102 ## 注意: 这里指定名称 remotebuilder DOCKER_HOST=${AMD64} docker buildx create --name remotebuilder --node hk-amd64 --platform=amd64 ### --append 表示追加, 而非重新创建 DOCKER_HOST=${ARM64} docker buildx create --append --name remotebuilder --node hk-arm64 --platform=arm64 ## 使用 remotebuilder docker buildx use remotebuilder ## 查看 remotebuilder 状态 docker buildx ls --builder remotebuilder
到此位置, remote builder
及创建成功了。
当我们在本地执行 docker buildx build ...
任务的时候, 任务就会分发到对应 cpu 架构的主机上。
这里 Dockerfile
非常简单, 仅仅就是拉取 centos:8
镜像。
mkdir -p centos/ && cd centos/ echo "FROM centos:8" > Dockerfile tree # . # └── Dockerfile # 0 directories, 1 file
docker buildx
命令拉取镜像。> 注意: 这里我们没有使用 --tag
指定目标镜像名称。
docker buildx build --platform=linux/amd64,linux/arm64 .
docker buildx
命令。> 注意: 这次我们使用了 --tag
和 --push
, 在构建完成后,会推送到目标 docker registry
> 注意2: 如果要执行 --push
成功, 只需要在 scheduler 主机上执行 docker login
即可, builder 上并无登录需求。
docker buildx build --platform=linux/amd64,linux/arm64 --tag tangx/centos:8 --push .
注意红框位置, 这次直接结果 , 多了 exporting
和 merging
当任务执行换成之后,所构建的 layer
缓存会存在与 remote builder
上, 同时 scheduler 上会保存多架构的 manifest 信息。
输出结果 [tangx/centos:8]可以在 dockerhub 上看到。
在国内使用 docker buildx
有一个最大的问题,就是网络。
由于 driver
是有运行在容器中, 参考官方文档 [buildx - github.com], 很多本机的配置因此而不能生效。
诸如 docker.io
这样国外官方镜像, 拉取速度就非常不理想了。
buildkitd.toml
# buildkitd.toml [registry."docker.io"] mirrors = ["wlzfs4t4.mirror.aliyuncs.com"]
并创建本地 builder
### create builder with mirror docker buildx create --use --name localbuilder --platform=linux/amd64,linux/arm64 --config=buildkitd.toml
Dockerfile
# Dockerfile FROM centos:8
并构建镜像
### build a image docker buildx build --platform=linux/amd64,linux/arm64 .
结果如上图所示, 耗时约 14s 左右
### without mirror docker buildx create --use --name localbuilder-no-mirror --platform=linux/amd64,linux/arm64 ### build a image docker buildx build --platform=linux/amd64,linux/arm64 .
从图片中可以看到, 在没有 mirror 的情况下, 出现了网络问题。
> 这是因为 builder 运行在容器类, 并没有使用宿主机的 /etc/docker/daemon.json
配置 (假设宿主机已经配置了 mirror), 即相当于国内直连 docker.io
拉去镜像。
如果你实现阅读了 [Dockerfile ARG
使用及作用域的分析], 那么以下两个 Dockerfile
就很简单了。
唯一作用: 对镜像重命名, 通过参数的方式实现了不通镜像的同步。
ARG IMAGE FROM ${IMAGE}
image=tangx/alpine tag=3.12 docker buildx build --platform=linux/amd64,linux/arm64 \ --tag ${image}:${tag} \ --file Dockerfile --build-arg IMAGE=alpine:3.12 \ .
这里通过 多阶 构建中 别名
及 ${TARGETARCH}
的方式, 将两个独立 tag 镜像合并成一个。
例如 minio/minio
的镜像。
ARG TARGETARCH FROM example.com/alpine:3.12-arm64 as arm64 FROM example.com/alpine:3.12-amd64 as amd64 FROM ${TARGETARCH}
docker buildx build --platform=linux/amd64,linux/arm64 \ --tag example.in/alpine:3.12 \ --file Dockerfile --build-arg IMAGE=alpine:3.12 \ .