参考官方文档:
- Multi-stage
- Multi-platform
- Multi-platform images
方法
如果在 x86_64/amd64
的平台上,想构建适用于多个平台的镜像,例如 linux/amd64
、linux/arm64
,根据官方文档,有三种方法可以使用:
-
QEMU
使用 QEMU 模拟构建多平台映像是最简单的入门方法,但可能比本机构建慢得多,特别是对于编译、压缩或解压缩等计算量大的任务。因此如果条件允许的话,更推荐使用 Cross-compilation(交叉编译)。但因为使用起来最简单,所以我在x86_64平台上构建arm64镜像并运行容器时用的是这个方法。 -
Multiple native nodes
使用多个本机节点可以为 QEMU 无法处理的更复杂的情况提供更好的支持,并且通常具有更好的性能。 -
Cross-compilation
交叉编译使多平台构建速度更快、用途更广泛,但必须要有相对应的编译器。
Buildx 设置
在构建镜像时,是通过设置 --platform
参数来指定目标平台的。例如, linux/amd64
、 linux/arm64
或 darwin/amd64
。
默认的构建驱动程序不支持并发多平台构建,一次只能针对一个平台进行构建(例如 docker build --platform=linux/amd64
)。
如果想同时针对多个平台进行构建(例如 --platform=linux/amd64,linux/arm64
),则需要创建构建器(builder)。
要使用不同的驱动程序,需要使用 Docker Buildx。 Buildx 是下一代构建客户端,它提供与 docker build
命令类似的用户体验,同时支持其他功能。
例如创建一个使用docker-container作为驱动程序,名为container
的新构建器:
docker buildx create --driver=docker-container --name=container
可以使用 docker buildx ls
命令列出可用的构建器。*
标明了当前正在使用的构建器(在下面的示例中为default
):
❯ docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
container docker-container
container0 unix:///var/run/docker.sock inactive
default * docker
default default running v0.11.7+d3e6c1360f6e linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/386
从上面的输出中可以看到,container
后的BUILDKIT
和PLATFORMS
为空,那么在第一次使用container
构建镜像时,就会先下载相关文件,然后才会开始构建。
也可以提前安装并在创建完成后马上启用构建器。需要用到tonistiigi/binfmt,之后还会自动下载moby/buildkit镜像。
如果电脑重启后在/proc/sys/fs/binfmt_misc
中找不到qemu相关内容,那么还需要重新执行这条命令:
docker run --privileged --rm tonistiigi/binfmt --install all
docker buildx create --name mybuilder --bootstrap --use
结果如下:
❯ docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
container docker-container
container0 unix:///var/run/docker.sock inactive
mybuilder * docker-container
mybuilder0 unix:///var/run/docker.sock running v0.12.3 linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
default docker
default default running v0.11.7+d3e6c1360f6e 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
使用QEMU仿真
仿真构建时,需要指定构建器参数 --builder
,以及平台参数 --platform
。
编译文件
例如下面这条命令用于编译多平台二进制文件:
docker buildx build \
--target=binaries \
--output=bin \
--builder=container \
--platform=linux/amd64,linux/arm64,linux/arm/v7 .
示例Dockerfile详细内容见Github,需要下载整个仓库然后在仓库根目录执行该命令。
构建镜像
以下示例使用单个 Dockerfile 为多个平台构建了安装有 curl 的 Alpine 映像。
Dockerfile:
# syntax=docker/dockerfile:1
FROM alpine:3.16
RUN apk add curl
构建命令:
docker buildx build \
--builder=mybuilder \
--platform=linux/amd64,linux/arm64,linux/arm/v7 \
--tag=<username>/<image>:latest \
--push .
其中 --push
表示构建完毕后推送到仓库。
必须添加 --push
或 --load
参数,否则会得到警告WARNING: No output specified with docker-container driver. Build result will only remain in the build cache. To push result image into registry use --push or to load image into docker use --load
。意思是构建结果只保存在缓存中,使用 --push
可以将镜像推送到远程仓库,使用 --load
可以将镜像保存在本地。
需要注意的是,如果参数添加的是 --load
而不是 --push
,并且--platform
后面跟了多个平台,例如--platform=linux/amd64,linux/arm64,linux/arm/v7
,那么还是会得到报错ERROR: docker exporter does not currently support exporting manifest lists
,这是因为本地无法保存多个同名的镜像。所以如果要保存构建出的多个平台的镜像到本地,就得分多次执行命令,每次只在 --platform
后添加一个平台,并且每次的 --tag
后面的镜像名称都不同。
例如为三个平台构建了镜像,就得分三次执行命令:
docker buildx build \
--builder=mybuilder \
--platform=linux/amd64 \
--tag=<username>/<image>_amd64:latest \
--load .
docker buildx build \
--builder=mybuilder \
--platform=linux/arm64 \
--tag=<username>/<image>_arm64:latest \
--load .
docker buildx build \
--builder=mybuilder \
--platform=linux/arm/v7 \
--tag=<username>/<image>_arm_v7:latest \
--load .
可以使用 docker buildx imagetools
命令检查镜像,前提是镜像已推送到远程仓库。例如:
❯ docker buildx imagetools inspect <username>/<image>:latest
Name: docker.io/<username>/<image>:latest
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest: sha256:f3b552e65508d9203b46db507bb121f1b644e53a22f851185d8e53d873417c48
Manifests:
Name: docker.io/<username>/<image>:latest@sha256:71d7ecf3cd12d9a99e73ef448bf63ae12751fe3a436a007cb0969f0dc4184c8c
MediaType: application/vnd.docker.distribution.manifest.v2+json
Platform: linux/amd64
Name: docker.io/<username>/<image>:latest@sha256:5ba4ceea65579fdd1181dfa103cc437d8e19d87239683cf5040e633211387ccf
MediaType: application/vnd.docker.distribution.manifest.v2+json
Platform: linux/arm64
Name: docker.io/<username>/<image>:latest@sha256:29666fb23261b1f77ca284b69f9212d69fe5b517392dbdd4870391b7defcc116
MediaType: application/vnd.docker.distribution.manifest.v2+json
Platform: linux/arm/v7
如果是使用 --load
保存到了本地,使用 docker image inspect
命令查看镜像。例如:
docker image inspect <username>/<image>_arm_v7
使用交叉编译(cross-compilation)
https://docs.docker.com/build/guide/images/cross-compilation.png
编译文件
由于Go语言的编译器支持在编译时通过使用 GOOS
和 GOARCH
环境变量来进行交叉编译,因此可以通过Docker自动将 --platform
的参数解析为构建参数TARGETPLATFORM
、TARGETOS
、TARGETARCH
,并在Dockerfile中赋值给环境变量,来实现交叉编译。
示例Dockerfile详细内容见Github或官网文档,需要下载整个仓库然后在仓库根目录执行该命令。
构建镜像
Dockerfile示例:
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM golang:alpine AS build
ARG TARGETPLATFORM
ARG BUILDPLATFORM
RUN echo "I am running on $BUILDPLATFORM, building for $TARGETPLATFORM" > /log
FROM alpine
COPY --from=build /log /log
在x86_64上运行arm64容器
先执行这条命令,确保/proc/sys/fs/binfmt_misc
有qemu相关内容:
docker run --privileged --rm tonistiigi/binfmt --install all
接下来以运行arm64版本的ubuntu 18.04为例:
- 下载镜像
docker pull --platform=linux/arm64 ubuntu:18.04
- 运行
docker run --rm -it ubuntu:18.04
忽略警告WARNING: The requested image's platform (linux/arm64/v8) does not match the detected host platform (linux/amd64/v3) and no specific platform was requested
文章来源:https://www.toymoban.com/news/detail-806713.html
- 查看版本等相关信息
uname -a
hello-world镜像同理:文章来源地址https://www.toymoban.com/news/detail-806713.html
docker run --rm --platform=linux/arm64 hello-world
❯ docker run --rm --platform=linux/arm64 hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(arm64v8)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
到了这里,关于Docker编译多平台文件、构建多平台镜像并运行的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!