使用 buildx 构建多平台 Docker 镜像
在工作和生活中,我们可能经常需要将某个程序跑在不同的 CPU 架构上,比如让某些不可描述的软件运行在树莓派或嵌入式路由器设备上。特别是 Docker 席卷全球之后,我们可以轻松地在 ARM 设备上通过容器部署各种好玩的应用,而不用在意各种系统的差异性。
但是想要跨平台构建 Docker 镜像可不是一件轻松的活,要么到不同 CPU 架构的系统上全部构建一遍,要么就得在当前系统上通过虚拟化技术模拟不同的 CPU 架构,最后可能还要想办法合并镜像,费力不讨好。
不过值得庆幸的是,Docker 19.03
引入了一个新的实验性插件,该插件使得跨平台构建 Docker 镜像比以往更加容易了。在介绍这个新特性之前,我们先来了解一下跨 CPU 架构构建程序的基础知识。
1 构建多平台 Docker 镜像
利用 Docker 19.03 引入的插件 buildx,可以很轻松地构建多平台 Docker 镜像。buildx 是 docker build ...
命令的下一代替代品,它利用 BuildKit 的全部功能扩展了 docker build
的功能。
下面就来演示一下如何在短短几分钟内使用 buildx
构建出不同平台的 Docker 镜像。步骤如下:
1.1 启用 buildx 插件
开启 Dockerd 的实验特性
要想使用 buildx
,首先要确保 Docker 版本不低于 19.03
,同时还要通过设置环境变量 DOCKER_CLI_EXPERIMENTAL
来启用。可以通过下面的命令来为当前终端启用 buildx 插件:
export DOCKER_CLI_EXPERIMENTAL=enabled
或者
编辑 /etc/docker/daemon.json
,新增如下条目
{
"experimental": true
}
1.2 安装 Buildx
export DOCKER_BUILDKIT=1
wget https://github.com/docker/buildx/releases/download/v0.10.0/buildx-v0.10.0.linux-amd64
mkdir -p ~/.docker/cli-plugins
mv buildx-v0.10.0.linux-amd64 ~/.docker/cli-plugins/docker-buildx
chmod +x ~/.docker/cli-plugins/docker-buildx
docker buildx介绍https://docs.docker.com/buildx/working-with-buildx/
docker buildx --help
,docker buildx COMMAND --help
查看用法,或者参考https://docs.docker.com/engine/reference/commandline/buildx/
1.3 安装模拟器
安装模拟器的主要作用是让 buildx 支持跨 CPU 架构编译。
docker run --rm --privileged docker/binfmt --install all
建议将 Linux 内核版本升级到 4.x 以上,特别是 CentOS 用户,你可能会遇到错误。
验证
docker buildx ls
会看到running 20.10.21 linux/amd64, linux/386, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/arm/v7, linux/arm/v6
1.4 从默认的构建器切换到多平台构建器
Docker 默认会使用不支持多 CPU 架构的构建器,我们需要手动切换。
先创建一个新的构建器:
docker buildx create --use --name mybuilder
docker buildx use mybuilder
启动构建器:
docker buildx inspect mybuilder --bootstrap
查看当前使用的构建器及构建器支持的 CPU 架构,可以看到支持很多 CPU 架构:
docker buildx ls
1.5 构建多平台镜像
现在我们就可以构建支持多 CPU 架构的镜像了!假设有一个简单的 golang 程序源码:
cat > hello.go <<EOF
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Printf("Hello, %s!\n", runtime.GOARCH)
}
EOF
创建一个 Dockerfile 将该应用容器化:
cat > Dockerfile <<EOF
FROM golang:alpine AS builder
ENV GO111MODULE auto
RUN mkdir /app
ADD . /app/
WORKDIR /app
RUN go build -o hello .
FROM alpine
RUN mkdir /app
WORKDIR /app
COPY --from=builder /app/hello .
CMD ["./hello"]
EOF
这是一个多阶段构建 Dockerfile,使用 Go 编译器来构建应用,并将构建好的二进制文件拷贝到 alpine 镜像中。
现在就可以使用 buildx 构建一个支持 arm、arm64 和 amd64 多架构的 Docker 镜像了,同时将其推送到 Docker Hub:
docker buildx build -t yaokun/hello --platform=linux/arm,linux/arm64,linux/amd64 . --push
需要提前通过 docker login
命令登录认证 Docker Hub。
现在就可以通过 docker pull yaokun/hello
拉取刚刚创建的镜像了,Docker 将会根据你的 CPU 架构拉取匹配的镜像。
背后的原理也很简单,之前已经提到过了,buildx 会通过 QEMU
和 binfmt_misc
分别为 3 个不同的 CPU 架构(arm,arm64 和 amd64)构建 3 个不同的镜像。构建完成后,就会创建一个 manifest list,其中包含了指向这 3 个镜像的指针。
如果想将构建好的镜像保存在本地,可以将 type
指定为 docker
,但必须分别为不同的 CPU 架构构建不同的镜像,不能合并成一个镜像,即:
docker buildx build -t yaokun/hello --platform=linux/arm -o type=docker .
docker buildx build -t yaokun/hello --platform=linux/arm64 -o type=docker .
docker buildx build -t yaokun/hello --platform=linux/amd64 -o type=docker .
1.6 测试多平台镜像
由于之前已经启用了 binfmt_misc
,现在我们就可以运行任何 CPU 架构的 Docker 镜像了,因此可以在本地系统上测试之前生成的 3 个镜像是否有问题。
首先列出每个镜像的 digests
:
docker buildx imagetools inspect yaokun/hello
运行每一个镜像并观察输出结果:
docker run --rm docker.io/yaokun/hello:latest@sha256:957012ecd4bbfc3b1fe6766163c52a54f1ca86c1a941992819f581abad7e3b6a
docker run --rm docker.io/yaokun/hello:latest@sha256:77dfa0171d8fa646f6903654068b5de5a0d0867d43caa18f92d3ed4ebf7c3754
docker run --rm docker.io/yaokun/hello:latest@sha256:8a85cf1b5dbabc18e32c2a14a47542756dd7d3054e57fb338d89aa8ee8178f35
参考链接: