「Docker」- 构建“跨平台”镜像的多种方法(Multi-Arch Images)

  CREATED BY JENKINSBOT

问题描述

就目前(11/20/2020)的镜像而言,是不能“跨平台”的(这里的“平台”是指处理器架构)。因为镜像里面包含二进制文件,这些二进制文件是平台相关的。

但是,我们观察到一个现象,当我们从 DockerHub 拉取镜像时,即使使用相同的地址,也会自动获得对应平台的镜像。以拉取 Nginx 镜像为例:
1)在 ARM64 上,执行 docker pull nginx 将返回 ARM64 平台的镜像;
2)在 AMD64 上,执行 docker pull nginx 将返回 AMD64 平台的镜像;

这是个很有用的特性,比如,对于不同平台,我们可以使用同个 docker-compose.yml 文件,而无需针对不同平台使用不同的镜像地址。

该笔记将记录:如何在 Docker Hub 上创建镜像,以实现「相同的 docker pull 命令,在不同平台上执行,获取该平台的镜像」,实现这种“多架构”镜像。

解决方案

目前(11/20/2020),有以下几种方法可以解决该问题:
1)使用 docker manifest 方法,将多个镜像“合并”到同个镜像地址中(这也是该笔记将演示的方法)
2)使用 docker buildx 创建,方便快捷(我们推荐的方法,但是属于实验性质的功能)

方法一、通过 docker manifest 命令

该方法通过创建 manifest list 来包含多个平台镜像的 manifest 信息。解释:

1)每个 Docker 镜像都有自己的 Manifest 信息,可以通过 docker manifest inspect “<Image Name>” 命令查看。

2)而 Manifest List 则是创建这样一个“List”其中包含多个镜像的 Manifest 信息,然后推送到 Docker Hub 仓库,相当与一个“逻辑镜像”。这个“逻辑镜像”中包含所有关联到它的镜像,以及镜像适用的平台。可以执行
docker manifest inspect nginx:latest 命令查看 Nginx 镜像的 Manifest List 信息,里面包含镜像层、系统、架构等等信息,这个信息是直接从 Docker Hub 拉取的(即使本地存在 Nginx 镜像)。

第一步、启用 experimental 特性,修改 ~/.docker/config.json 配置:

{
...
    "experimental": "enabled",
...
}

第二步、执行如下命令,以创建镜像标签:

# docker manifest create k4nz/manifest-example:0.1.3 \
    k4nz/manifest-example:0.1.3-amd64 k4nz/manifest-example:0.1.3-aarch64

第三步、推送我们的“逻辑镜像”:

# docker manifest push --purge k4nz/manifest-example:0.1.3

注意事项:该方法要求 k4nz/manifest-example:0.1.3-amd64 与 k4nz/manifest-example:0.1.3-aarch64 镜像存在于 DockerHub 中(镜像名可以不同),因此这也是比较麻烦的地方,即我们需要先将镜像推送到仓库,然后再创建“逻辑镜像”,导致在仓库中存在大量无用的镜像(标签)。

方法二、使用 docker buildx build 命令(推荐)

参考 buildx 笔记,我们推荐该方法,一气呵成,非常简便。但是该方法属于实验性质,是否使用请参照自己的实际情况。

参考文献

Create multi-arch Docker images for Docker | cstan.io
Multi-arch build and images, the simple way – Docker Blog