docker构建跨平台应用(x86,arm)

1.直接从官方仓库拉去指定平台的镜像

1
docker pull --platform=<plartform> <image-name>:<tag>

  例:

1
docker pull --platform=arm64 nginx:latest

2.打包指定平台的镜像

安装并使用 buildx

 

使用 builder 构建跨平台镜像

现在一些准备工作已经就绪,我们终于可以使用 builder 构建跨平台镜像了。

这里以一个 Go 程序为例,来演示如何构建跨平台镜像。

hello.go 程序如下:

package main import ( "fmt" "runtime" ) func main() { fmt.Printf("Hello, %s/%s!\n", runtime.GOOS, runtime.GOARCH) }

这个程序非常简单,执行后打印 Hello, 操作系统/CPU 架构

Go 程序还需要一个 go.mod 文件:

module hello go 1.20

编写 Dockerfile 内容如下:

FROM golang:1.20-alpine AS builder WORKDIR /app ADD . . RUN go build -o hello . FROM alpine:latest WORKDIR /app COPY --from=builder /app/hello . CMD ["./hello"]

这是一个普通的 Dockerfile 文件,为了减小镜像大小,使用了多阶段构建。它跟构建仅支持当前平台的镜像所使用的 Dockerfile 没什么两样。

$ ls Dockerfile go.mod hello.go

以上三个文件需要放在同一个目录下,然后就可以在这个目录下使用 docker buildx 来构建跨平台镜像了。

$ docker buildx build --platform linux/arm64,linux/amd64 -t jianghushinian/hello-go .

docker buildx build 语法跟 docker build 一样,--platform 参数表示构建镜像的目标平台,-t 表示镜像的 Tag,. 表示上下文为当前目录。

唯一不同的是对 --platform 参数的支持,docker build 的 --platform 参数只支持传递一个平台信息,如 --platform linux/arm64,也就是一次只能构建单个平台的镜像。

而使用 docker buildx build 构建镜像则支持同时传递多个平台信息,中间使用英文逗号分隔,这样就实现了只用一条命令便可以构建跨平台镜像的功能。

执行以上命令后,我们将会得到一条警告:

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

这条警告提示我们没有为 docker-container 驱动程序指定输出,生成结果将只会保留在构建缓存中,使用 --push 可以将镜像推送到 Docker Hub 远程仓库,使用 --load 可以将镜像保存在本地。

这是因为我们新创建的 mybuilder 是启动了一个容器来运行 BuildKit,它并不能直接将构建好的跨平台镜像输出到本机或推送到远程,必须要用户来手动指定输出位置。

我们可以尝试指定 --load 将镜像保存的本地主机。

$ docker buildx build --platform linux/arm64,linux/amd64 -t jianghushinian/hello-go . --load [+] Building 0.0s (0/0) ERROR: docker exporter does not currently support exporting manifest lists

结果会得到一条错误日志。看来它并不支持直接将跨平台镜像输出到本机,这其实是因为传递了多个 --platform 的关系,如果 --platform 只传递了一个平台,则可以使用 --load 将构建好的镜像输出到本机。

那么我们就只能通过 --push 参数将跨平台镜像推送到远程仓库了。不过在此之前需要确保使用 docker login 完成登录。

$ docker buildx build --platform linux/arm64,linux/amd64 -t jianghushinian/hello-go . --push

现在登录 Docker Hub 就可以看见推送上来的跨平台镜像了。

我们也可以使用 imagetools 来检查跨平台镜像的 manifest 信息。

$ docker buildx imagetools inspect jianghushinian/hello-go Name: docker.io/jianghushinian/hello-go:latest MediaType: application/vnd.docker.distribution.manifest.list.v2+json Digest: sha256:51199dadfc55b23d6ab5cfd2d67e38edd513a707273b1b8b554985ff562104db Manifests: Name: docker.io/jianghushinian/hello-go:latest@sha256:8032a6f23f3bd3050852e77b6e4a4d0a705dfd710fb63bc4c3dc9d5e01c8e9a6 MediaType: application/vnd.docker.distribution.manifest.v2+json Platform: linux/arm64 Name: docker.io/jianghushinian/hello-go:latest@sha256:fd46fd7e93c7deef5ad8496c2cf08c266bac42ac77f1e444e83d4f79d58441ba MediaType: application/vnd.docker.distribution.manifest.v2+json Platform: linux/amd64

可以看到,这个跨平台镜像包含了两个目标平台的镜像,分别是 linux/arm64 和 linux/amd64

我们分别在 Apple M2 芯片平台和 Linux x86 平台来启动这个 Docker 镜像看下输出结果。

$ docker run --rm jianghushinian/hello-go Hello, linux/arm64! $ docker run --rm jianghushinian/hello-go Hello, linux/amd64!

至此,我们使用 builder 完成了跨平台镜像的构建。

使用交叉编译

以上演示的构建跨平台镜像过程就是利用 QEMU 的能力,因为 Go 语言的交叉编译非常简单,所以我们再来演示一下如何使用交叉编译来构建跨平台镜像。

我们只需要对 Dockerfile 文件进行修改:

FROM --platform=$BUILDPLATFORM golang:1.20-alpine AS builder ARG TARGETOS ARG TARGETARCH WORKDIR /app ADD . . RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o hello . FROM --platform=$TARGETPLATFORM alpine:latest WORKDIR /app COPY --from=builder /app/hello . CMD ["./hello"]

其中 BUILDPLATFORMTARGETOSTARGETARCHTARGETPLATFORM 四个变量是 BuildKit 提供的全局变量,分别表示构建镜像所在平台、操作系统、架构、构建镜像的目标平台。

在构建镜像时,BuildKit 会将当前所在平台信息传递给 Dockerfile 中的 BUILDPLATFORM 参数(如 linux/arm64)。

通过 --platform 参数传递的 linux/arm64,linux/amd64 镜像目标平台列表会依次传递给 TARGETPLATFORM 变量。

而 TARGETOSTARGETARCH 两个变量在使用时则需要先通过 ARG 进行声明,BuildKit 会自动为其赋值。

在 Go 程序进行编译时,可以通过 GOOS 环境变量指定目标操作系统,通过 GOARCH 环境变量指定目标架构。

所以这个 Dockerfile 所表示的含义是:首先拉取当前构建镜像所在平台的 golang 镜像,然后使用交叉编译构建目标平台的 Go 程序,最后将构建好的 Go 程序复制到目标平台的 alpine 镜像。

最终我们会通过交叉编译得到一个跨平台镜像。

笔记:通过 FROM --platform=$BUILDPLATFORM image 可以拉取指定平台的镜像,由此我们可以知道,其实 golang 和 alpine 镜像都是支持跨平台的。

构建镜像命令不变:

$ docker buildx build --platform linux/arm64,linux/amd64 -t jianghushinian/hello-cross-go . --push

启动镜像后输出结果不变:

$ docker run --rm jianghushinian/hello-cross-go Hello, linux/arm64! $ docker run --rm jianghushinian/hello-cross-go Hello, linux/amd64!

至此,我们利用 Go 语言的交叉编译完成了跨平台镜像的构建。

平台相关的全局变量

关于上面提到的几个全局变量,BuildKit 后端预定义了一组 ARG 全局变量(共 8 个)可供使用,其定义和说明如下:

变量说明
TARGETPLATFORM 构建镜像的目标平台,如:linux/amd64,linux/arm/v7,windows/amd64。
TARGETOS TARGETPLATFORM 的操作系统,如:linux、windows。
TARGETARCH TARGETPLATFORM 的架构类型,如:amd64、arm。
TARGETVARIANT TARGETPLATFORM 的变体,如:v7。
BUILDPLATFORM 执行构建所在的节点平台。
BUILDOS BUILDPLATFORM 的操作系统。
BUILDARCH BUILDPLATFORM 的架构类型。
BUILDVARIANT BUILDPLATFORM 的变体。

使用示例如下:

# 这里可以直接使用 TARGETPLATFORM 变量 FROM --platform=$TARGETPLATFORM alpine # 稍后的 RUN 命令想要使用变量必须提前用 ARG 进行声明 ARG TARGETPLATFORM RUN echo "I'm building for $TARGETPLATFORM"

删除 builder

我们已经实现了使用 builder 构建跨平台镜像。如果现在你想要恢复环境,删除新建的 builder。则可以使用 docker buildx rm mybuilder 命令来完成。

$ docker buildx rm mybuilder mybuilder removed

跟随 mybuilder 启动的 buildx_buildkit_mybuilder0 容器也会随之被删除。

现在再使用 docker buildx ls 命令查看构建器列表,已经恢复成原来的样子了。

$ docker buildx ls NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS default * docker default default running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6 desktop-linux docker desktop-linux desktop-linux running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6

功能清单

除了前文介绍的几个 buildx 常用命令,更多功能可以通过 --help 参数进行查看。

$ docker buildx --help Usage: docker buildx [OPTIONS] COMMAND Extended build capabilities 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.

如 stoprm 可以管理 builder 的生命周期。每条子命令又可以使用 docker buildx COMMAND --help 方式查看使用帮助,感兴趣的同学可以自行学习。

https://mioto.me/posts/offline-docker-buildx-and-registry-for-multi-platform-image-building/


__EOF__

本文作者东峰叵.com
本文链接https://www.cnblogs.com/databank/p/17979533.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   东峰叵,com  阅读(2687)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤
点击右上角即可分享
微信分享提示