Docker Buildx 教程
# 前戏
随着国产化和信创的推进,为应用适配多个操作系统和处理器架构的需求越来越普遍。常见做法是为不同平台单独构建一个版本,当用来开发的平台与部署的目标平台不同时,实现这一目标并不容易。例如在 x86 架构上开发一个应用程序并将其部署到 ARM 平台的机器上,通常需要准备 ARM 平台的基础设施用于开发和编译
一次构建多处部署的镜像分发大幅提高了应用的交付效率,对于需要跨平台部署应用的场景,利用 docker buildx 构建跨平台的镜像也是一种快捷高效的解决方案。
大部分镜像托管平台支持多平台镜像,这意味着镜像仓库中单个标签可以包含不同平台的多个镜像,以
docker hub
的python
镜像仓库为例,3.9.6
这个标签就包含了 10 个不同系统和架构的镜像(平台 = 系统 + 架构);通过docker pull
或docker run
拉取一个支持跨平台的镜像时,docker
会自动选择与当前运行平台相匹配的镜像。由于该特性的存在,在进行镜像的跨平台分发时,我们不需要对镜像的消费做任何处理,只需要关心镜像的生产,即如何构建跨平台的镜像。默认的
docker build
命令无法完成跨平台构建任务,我们需要为docker
命令行安装buildx
插件扩展其功能。buildx
能够使用由 Moby BuildKit (opens new window) 提供的构建镜像额外特性,它能够创建多个 builder 实例,在多个节点并行地执行构建任务,以及跨平台构建。
# docker buildx
# 1. 启用 buildx
macOS 或 Windows 系统的 Docker Desktop,以及 Linux 发行版通过
deb
或者rpm
包所安装的docker
内置了buildx
,不需要另行安装。如果你的
docker
没有buildx
命令,可以下载二进制包进行安装:- 首先从 Docker buildx (opens new window) 项目的 release 页面找到适合自己平台的二进制文件。
- 下载二进制文件到本地并重命名为
docker-buildx
,移动到 docker 的插件目录~/.docker/cli-plugins
。 - 向二进制文件授予可执行权限。
如果本地的
docker
版本高于 19.03,可以通过以下命令直接在本地构建并安装,这种方式更为方便:$ DOCKER_BUILDKIT=1 docker build --platform=local -o . "https://github.com/docker/buildx.git" $ mkdir -p ~/.docker/cli-plugins $ mv buildx ~/.docker/cli-plugins/docker-buildx
1
2
3使用
buildx
进行构建docker buildx build .
buildx
和docker build
命令的使用体验基本一致,还支持build
常用的选项如-t
、-f
等基础命令
$ docker buildx --help Usage: docker buildx [OPTIONS] COMMAND Build with BuildKit Options: --builder string Override the configured builder instance Management Commands: imagetools Commands to work on images in registry Commands: bake Build from a file build Start a build create Create a new builder instance du Disk usage inspect Inspect current builder instance ls List builder instances prune Remove build cache rm Remove a builder instance stop Stop builder instance use Set the current builder instance version Show buildx version information Run 'docker buildx COMMAND --help' for more information on a command.
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
# 2. buildx 实例
docker buildx
通过 builder 实例对象来管理构建配置和节点,命令行将构建任务发送至 builder 实例,再由 builder 指派给符合条件的节点执行。- 我们可以基于同一个
docker
服务程序创建多个 builder 实例,提供给不同的项目使用以隔离各个项目的配置,也可以为一组远程docker
节点创建一个 builder 实例组成构建阵列,并在不同阵列之间快速切换。 - 使用
docker buildx create
命令可以创建 builder 实例,这将以当前使用的 docker 服务为节点创建一个新的 builder 实例。要使用一个远程节点,可以在创建示例时通过DOCKER_HOST
环境变量指定远程端口或提前切换到远程节点的docker context
。
# 2.1 创建 builder 实例
$ docker buildx create --driver docker-container --platform linux/amd64 --name multi-builder
# 创建 docker-container 驱动实例时可通过 --driver-opt image=moby/buildkit:v0.10.5 选项配置所使用的 buildkit 镜像版本。
# 刚创建的 builder 处于 inactive 状态,可以在 create 或 inspect 子命令中添加 --bootstrap 选项立即启动实例
2
3
4
# 2.2 查看 实例
$ docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS PLATFORMS
multi-builder docker-container
multi-builder0 unix:///var/run/docker.sock inactive linux/amd64*
default * docker
default default running linux/amd64, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
2
3
4
5
6
- 使用某实例:
docker buildx use
- 查看实例详情:
docker buildx inspect
- 停止实例:
docker buildx stop
- 删除实例:
docker buildx rm
# 3. 添加远程实例
- 默认的 docker build 命令无法完成跨平台构建任务,我们需要为 docker 命令行安装 buildx 插件扩展其功能。buildx 能够使用由 Moby BuildKit 提供的构建镜像额外特性,它能够创建多个 builder 实例,在多个节点并行地执行构建任务,以及跨平台构建。
# 3.1 docker 远程开启
编辑 /usr/lib/systemd/system/docker.service文件
在如下位置添加 -H tcp://0.0.0.0:2375
重启docker
systemctl daemon-reload systemctl restart docker
1
2测试连接
curl http://localhost:2375/version
1
# 3.2 buildx 添加远程节点
创建并添加远程节点
# docker 20.X 以下版本需要开启环境变量 export DOCKER_CLI_EXPERIMENTAL=enabled # 创建新builder 实例 multi-builder $ docker buildx create --driver docker-container --platform linux/amd64 --name multi-builder multi-builder # 添加远程arm平台的buidler $ export DOCKER_HOST=tcp://192.168.99.100:2375 #(前提:远程docker开启远程访问) $ docker buildx create --name multi-builder --append --node remote-builder #启动新buidler实例 multi-builder $ docker buildx inspect --bootstrap multi-builder Name: multi-builder Driver: docker-container Last Activity: 2023-04-14 09:59:15 +0000 UTC Nodes: Name: multi-builder0 Endpoint: unix:///var/run/docker.sock Status: running Buildkit: v0.9.3 Platforms: linux/amd64, linux/386 Name: remote-builder Endpoint: tcp://192.168.100.2:2375 Status: running Buildkit: v0.11.5 Platforms: linux/arm64, linux/arm/v7, linux/arm/v6 # 查看现有builder所有实例 $ docker buildx ls NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS multi-builder * docker-container multi-builder0 unix:///var/run/docker.sock running v0.9.3 linux/amd64, linux/386 remote-builder tcp://192.168.99.100:2375 running v0.11.5 linux/arm64, linux/arm/v7, linux/arm/v6 default docker default default running 20.10.12 linux/arm64, linux/arm/v7, linux/arm/v6
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
# 3.3 启用实例
启用新建的multi-builder
$ docker buildx use multi-builder
1
# 4. buildx 构建镜像
# 4.1 构建单个镜像(arm)
构建arm的镜像到本地
# 构建arm的镜像到本地 $ OVN_IMAGE=harbor.yusur.tech/yusur_ovn/ovn-daemonset-f:second-cni-aarch64 $ docker buildx build --build-arg BUILDPLATFORM=linux/aarch64 --build-arg TARGETPLATFORM=linux/aarch64 --platform=linux/arm64 -t $OVN_IMAGE -o type=docker -f Dockerfile.fedora .
1
2
3
# 4.2 构建单个镜像(amd)
构建amd的镜像到本地
$ OVN_IMAGE=harbor.yusur.tech/yusur_ovn/ovn-daemonset-f:second-cni-amd64 $ docker buildx build --build-arg BUILDPLATFORM=linux/amd64 --build-arg TARGETPLATFORM=linux/amd64 --platform=linux/amd64 -t $OVN_IMAGE -o type=docker -f Dockerfile.fedora .
1
2
# 4.3 构建多个镜像(arm、amd)
编译完成后就直接push到hub
$ OVN_IMAGE=harbor.yusur.tech/yusur_ovn/ovn-daemonset-f:second-cni $ docker buildx build --push --platform linux/arm64,linux/amd64 -t $OVN_IMAGE -f Dockerfile.fedora .
1
2docker buildx build --help
Usage: docker buildx build [OPTIONS] PATH | URL | - Start a build Aliases: build, b Options: --add-host strings Add a custom host-to-IP mapping (host:ip) --allow strings Allow extra privileged entitlement, e.g. network.host, security.insecure --build-arg stringArray Set build-time variables --builder string Override the configured builder instance --cache-from stringArray External cache sources (eg. user/app:cache, type=local,src=path/to/dir) --cache-to stringArray Cache export destinations (eg. user/app:cache, type=local,dest=path/to/dir) -f, --file string Name of the Dockerfile (Default is 'PATH/Dockerfile') --iidfile string Write the image ID to the file --label stringArray Set metadata for an image --load Shorthand for --output=type=docker --network string Set the networking mode for the RUN instructions during build (default "default") --no-cache Do not use cache when building the image -o, --output stringArray Output destination (format: type=local,dest=path) --platform stringArray Set target platform for build --progress string Set type of progress output (auto, plain, tty). Use plain to show container output (default "auto") --pull Always attempt to pull a newer version of the image --push Shorthand for --output=type=registry # -o type=registry 自动推送 --secret stringArray Secret file to expose to the build: id=mysecret,src=/local/secret --ssh stringArray SSH agent socket or keys to expose to the build (format: default|<id>[=<socket>|<key>[,<key>]]) -t, --tag stringArray Name and optionally a tag in the 'name:tag' format --target string Set the target build stage to build.
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
29docker buildx build
支持丰富的输出行为,通过--output=[PATH,-,type=TYPE[,KEY=VALUE]
选项可以指定构建结果的输出类型和路径等,常用的输出类型有以下几种:- local:构建结果将以文件系统格式写入
dest
指定的本地路径, 如--output type=local,dest=./output
。 - tar:构建结果将在打包后写入
dest
指定的本地路径。 - oci:构建结果以 OCI 标准镜像格式写入
dest
指定的本地路径。 - docker:构建结果以 Docker 标准镜像格式写入
dest
指定的本地路径或加载到docker
的镜像库中。同时指定多个目标平台时无法使用该选项。 - image:以镜像或者镜像列表输出,并支持
push=true
选项直接推送到远程仓库,同时指定多个目标平台时可使用该选项。 - registry:
type=image,push=true
的精简表示。
- local:构建结果将以文件系统格式写入
# buildx 构建实战
创建实例并启用
# 创建实例 $ docker buildx create --driver docker-container --platform linux/amd64 --name multi-builder # 查看实例 $ docker buildx ls $ docker buildx inspect --bootstrap multi-builder # 启用实例 $ docker buildx use multi-builder
1
2
3
4
5
6
7main.go
package main import ( "fmt" ) func main() { fmt.Println("Hello world!") }
1
2
3
4
5
6
7
8
9
10Dockerfile
FROM golang:1.14 as builder ARG TARGETARCH WORKDIR /app COPY main.go /app/main.go RUN GOOS=linux GOARCH=$TARGETARCH go build -a -o output/main main.go FROM alpine:latest WORKDIR /root COPY /app/output/main . CMD /root/main
1
2
3
4
5
6
7
8
9
10
11
12构建
docker buildx build --platform linux/amd64,linux/arm64,linux/arm -t 你的镜像名字 -o type=registry .
1