交叉编译多架构容器

Cross-compile multi-arch containers

我正在尝试构建一个 ARM (arm32v7) 容器,但使用 x86_64 主机。虽然我知道有一些非常酷的东西,比如 Resin using Qemu shenanigans, and Multiarch 用于通用容器的交叉构建,但我有一个小问题:我尝试构建的容器开始时是多架构的,所以 Docker 总是选择FROM 指令中的 x86 图像。

我想在 x86 主机上从 Multi-arch Rust image 构建一个 ARM 容器。问题是,我找不到任何文档明确说明我想从 ARM 容器开始并从中构建,而不是 x86 容器。此外,图像上的标签不会消除歧义,所以我不能将它们用于 select 起始容器。

我尝试编辑 /etc/docker/daemon.json 文件以包含:

{
    "labels": [ "os=linux", "arch=arm32v7" ],
    "experimental": true
}

但这根本没有帮助。 docker pull 仍然检索 x86 图像。所有这一切的目的是最终 运行 在 Raspberry Pi 上提高容器的编译时间;就目前而言,编译时间非常慢。

有什么方法可以明确说明我想从 ARM 映像开始构建?

可以为另一个架构("cross-compile")构建简单的 Docker 容器,方法是使用适合该架构的基础映像。简单来说,我的意思是不需要在 Docker 文件中使用 RUN 命令来构建图像。这是因为 Docker 没有能力在另一个架构的容器中实际 运行 命令。虽然这听起来有限制,但与 multi-stage builds 到 cross-compile 代码结合使用时会非常强大。

让我们来看看这个 step-by-step。首先,让我们为 Docker 客户端启用实验模式,通过将以下选项添加到 ~/.docker/config.json:

来启用 docker manifest
{
    "experimental": "enabled"
}

然后我们可以使用 docker manifest inspect debian:stretch 来显示 fat manifest that contains a digest for the image in the architecture we want to build for. For example, the arm32v7 image has "architecture": "arm" and "variant": "v7" specified under the platform key. Using jq,我们可以通过编程方式提取此图像的摘要:

docker manifest inspect debian:stretch | jq -r '.manifests[] | select(.platform.architecture == "arm" and .platform.variant == "v7") | .digest'`

此摘要随后可用于 Docker 文件中的 FROM 命令:

FROM debian@sha256:d01d682bdbacb520a434490018bfd86d76521c740af8d8dbd02397c3415759b1

然后可以 COPY cross-compiled 二进制到图像中。该二进制文件可能来自您机器上的 cross-compiler 或 multi-stage 构建中的另一个容器。要删除 Docker 文件的 FROM 行中的 hard-coded 摘要,可以通过 Docker build argument (ARG).

将其外部化