多架构镜像三部曲(二)构建

文章目录

  • 多架构镜像构建(multi-architecture)
    • 镜像、manifests 与 manifests list
    • 多架构镜像构建方法
    • 基于目标架构机器的镜像构建结果组合方式
      • 构建 amd64 镜像
      • 构建 arm64 镜像
      • 基于 manifest 的方式组合多平台架构镜像
      • 基于 Buildx 的方式组合多平台架构镜像
    • 基于交叉编译的镜像构建方式
      • 多架构镜像的 Dockerfile
      • 多架构镜像构建并推送
      • 查看多架构镜像信息
      • docker hub 效果
    • 多架构镜像验证
  • 结语&思考

大家好,我是温玉。今天给大家分享的内容是 “多架构镜像构建” 专题,希望给有在不同架构平台上交付应用需求的同学提供一些帮助。

  • 多架构镜像三部曲(一)组合
  • 多架构镜像三部曲(二)构建

多架构镜像构建(multi-architecture)

在计算机的发展过程中冯诺依曼计算机体系结构是现代计算机组成的基础,在此基础上各组件都有诞生许多优秀的硬件,而计算机硬件的核心之一就是 CPU。计算机由于 CPU 指令集的不同,可以分为精简指令集计算机(RISC)和复杂指令集计算机(CISC),软件在不同的指令集硬件上运行需要编译成对应的可执行文件。典型的有英国 Acorn 公司设计 ARM 精简指令集架构处理器(如 arm64)和 美国 AMD 公司设计的 AMD 复杂指令集架构处理器(如 amd64/x86_64)。

目前常见的精简指令集 CPU 包括 DEC Alpha、ARC(英语:ARC (processor))、ARM、AVR、MIPS、PA-RISC、Power ISA(包括PowerPC、PowerXCell)、RISC-V 和 SPARC等。属于复杂指令集的处理器有 CDC 6600、System/360、VAX、PDP-11、Motorola 68000家族、x86、AMD Opteron等[1]。

计算机软件是一系列按照特定顺序组织的电脑数据和指令,是电脑中的非有形部分。软件类型可以分为编程语言软件、操作系统软件和应用软件;操作系统软件就是最基础的软件,由操作系统来统一管理计算机相关硬件,使其能够协同工作为上层应用软件提供运行环境。操作系统软件目前主流的有 Linux、Window、Unix 以及一些特殊的大型机等特殊设备的操作系统等,其他发行版本大都是基于这些系统衍生而来。

应用软件是运行在计算机硬件和操作系统之上的,为满足用户不同领域、不同问题的应用需求而提供的那部分软件。由于低层的硬件和操作系统的不同,应用软件在不同架构平台上需要重新编译才能执行;容器服务也是应用,在不同的平台运行容器需要编译打包制作成不同类型的镜像,这也是本文核心讲诉的内容。

镜像、manifests 与 manifests list

说到镜像,就离不开对其含义的理解,特别是在多架构场景下有多出了 manifests 和 manifests list 的概念。

镜像是由一组元数据信息(镜像的架构、默认配置、构建镜像的容器配置、所有镜像层layer 等)和 rootfs 组成的只读的文件归档,该归档能够作为容器运行的只读环境基础,结合可读写层提供容器运行环境。

与镜像不同,manifests 是镜像的描述清单,是在镜像的上层的又一种抽象,这个清单文件中也包含了有关于镜像的信息,如 layer 层、大小和摘要信息。而 manifests list 就是在这个描述清单中有多种类型的 manifest 镜像描述信息,这个描述清单列表可以通过镜像 TAG 关联访问。

可以简单的理解一个 manifests list 就是用一个 TAG 来关联相同功能的多个不同架构平台的镜像,就是常说的多架构镜像。这里的多架构一般是指不同种类的 CPU (如 amd64,arm64)和 操作系统(如:linux、windows)。

manifests lists 可以在本地组合创建然后 push 推送到远程 Registry 仓库,也可以直接在远程 Registry 仓库中组合创建,但他不可以直接被作为容器运行的镜像。实际上在 docker pulldocker run 在拉取容器镜像时,客户端会自动根据当前机器的 CPU 和 操作系统从 manifests list 中下载自己需要的相关文件,即只下载符合本机器运行的容器镜像,而不是下载 manifests lists 中所有的内容。

本文中的描述涉及多架构镜像manifests lists时,他们两者的概念时等价的。

多架构镜像构建方法

对于多平台架构镜像的发布主要有两类方式,使用基于目标架构机器的镜像构建结果组合方式和基于交叉编译的镜像构建方式两种方法

  • 基于目标架构机器的镜像构建结果组合方式

如果我们有并且可以访问目标架构机器,同时该机器操作系统支持运行构建所需的各种环境和工具,那么就可以直接分别在目标架构机器上编译应用程序,进行镜像的构建,然后通过拼接组合的方式来发布一个多架构镜像的 manifests list

例如分别构建后组合成多架构镜像:

  • 在 ARM 的服务器上构建 arm64 镜像 : harbor.example-domain.com/library/myapp:v1-arm64
  • 在 AMD 的服务器上构建 amd64 镜像: harbor.example-domain.com/library/myapp:v1-amd64
  • 将 arm64 和 amd64 的镜像组合成多平台架构镜像: harbor.example-domain.com/library/myapp:v1-multi

需要多少种类型的应用,就分别在该类型的机器上编译打包镜像,然后通过一定的方式或工具就可以将多种类型的镜像组合成多架构镜像。

这种方式的优点是不需要特殊改造升级就可以支持;缺点也比较明显,多个不同平台的环境管理维护复杂。

  • 基于交叉编译的镜像构建方式

交叉编译是在一个平台上生成另一个平台上的可执行代码。将交叉编译的可执行代码打包成镜像就是想要的目标架构镜像了,但容器的交叉编译构建镜像依赖 QEMU 的虚拟化技术。

使用 QEMU 虚拟化技术可以虚拟化出服务器相关的硬件设备,常用来在单台高性能物理服务器上虚拟化出多台虚拟机场景,例如 VirtalBox、Vmware、KVM 等虚拟化工具。对于多架构镜像也是可以选择这种方式创建出不同架构平台的虚拟机,然后使用 基于目标架构机器的镜像构建结果组合方式 来发布多架构镜像;但是这种方式除了管理复杂外,虚拟化本身也会有较多的资源损耗浪费。

QEMU 是一种虚拟化技术,传统的 KVM 虚拟机技术就是基于 QEMU 技术,QEMU 支持虚拟化出许多常见的 CPU 架构,包括 ARM、Power-PC 和 RISC-V 等。

目前技术上已经支持在宿主机系统内核支持虚拟化的情况下,可以直接基于目标架构指令的方式来构建镜像。该方式不需要事先虚拟化出各种平台的硬件环境,也不需要安装各种操作系统环境等复杂的操作,同时也不会有大量的虚拟化本身的资源损耗,通过内核支持在编译时直接编译成对应架构的可执行文件,然后构建出目标架构的容器镜像。

这种方式的优点是构建便捷,资源利用率高;缺点是对操作系统内核版本有一定的要求。

基于目标架构机器的镜像构建结果组合方式

本文示例是使用一份 go 代码 get-cpu-os.go 来进行说明,这段代码的功能就是运行时输出当前运行机器的 CPU 架构和操作系统,以此场景来构建和验证多架构镜像的创建过程和使用流程。

代码内容如下:

package main

import (
   "fmt"
   "runtime"
)

func main() {
   fmt.Println("CPU Arch: ", runtime.GOARCH)
   fmt.Println("Operating System:", runtime.GOOS)
}

将源代码编译过程和打包过程放在一个 Dockerfile 中,使用 Dockerfile 的多阶段构建的方式来一次编译和构建镜像。当然,也可以分成两个独立的 Dockerfile,先编译出对应的二进制文件,然后再使用二进制文件构建容器镜像。

构建使用的 Dockerfile 内容如下:

FROM golang AS builder
WORKDIR /gobuild
COPY get-cpu-os.go  .
RUN go build get-cpu-os.go

FROM golang
WORKDIR /gorun
COPY --from=builder /gobuild/get-cpu-os .
CMD ["./get-cpu-os"]

有了源码代码和 Dockerfile ,在构建节点就可以来执行命令构建容器镜像。

构建 amd64 镜像

选择一台 AMD64 机器作为镜像构建机器,来构建可在 AMD64 架构机器上运行的容器镜像。

Intel 的 X86_64 架构 CPU 使用的是 AMD 的技术,因此在大多数情况下 X86_64 架构和 AMD64 架构是等价的。

可以通过 lscpu 命令查看机器的 CPU 硬件相关系信息,如下 CPU 信息表明其是 Architecture: x86_64 架构的机器。

相关的 CPU 和操作系统内核相关信息:

# lscpu 
Architecture:        x86_64
CPU op-mode(s):      32-bit, 64-bit
Byte Order:          Little Endian
CPU(s):              16
On-line CPU(s) list: 0-15
Thread(s) per core:  1
Core(s) per socket:  1
Socket(s):           16
NUMA node(s):        1
Vendor ID:           GenuineIntel
CPU family:          6
Model:               61
Model name:          Intel Core Processor (Broadwell)
Stepping:            2
CPU MHz:             2394.456
BogoMIPS:            4788.91
Hypervisor vendor:   KVM
Virtualization type: full
L1d cache:           32K
L1i cache:           32K
L2 cache:            4096K
L3 cache:            16384K
NUMA node0 CPU(s):   0-15
Flags:               fpu vme de pse tsc......

除了 CPU ,还需要确认其操作系统类型。在 Unix 以及 类 Unix 等系统中,可以通过 uname -a 命令来查看内核相关的信息。

如示例中可看出这是一台 GNU/Linux 的系统,其内核版本是 4.18.0-80

# uname -a
Linux localhost 4.18.0-80.el8.x86_64 #1 SMP Tue Jun 4 09:19:46 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

在该机器上通过 docker build 工具来构建镜像

# docker build --no-cache  -t zhaowenyu/get-cpu-os:latest-amd64 .

该命令是构建一个容器镜像,参数说明:

  • --no-cache: 配置在构建过程中不使用缓存,所有步骤都重新构建。
  • -t zhaowenyu/get-cpu-os:latest-amd64: 配置构建的目标镜像的 TAG 名称。
  • .: 这里的点是构建的上下文的初始位置,发送给 Docker Damon 的相关文件都是以此为相对初始路径。

镜像构建过程详细输出

# docker build --no-cache  -t zhaowenyu/get-cpu-os:latest-amd64 .
Sending build context to Docker daemon  6.656kB
Step 1/8 : FROM golang AS builder
 ---> 7d1902a99d63
Step 2/8 : WORKDIR /gobuild
 ---> Running in fb4f6d53c372
Removing intermediate container fb4f6d53c372
 ---> ad6d09ac6b9a
Step 3/8 : COPY  get-cpu-os.go  .
 ---> cb0fc4f43012
Step 4/8 : RUN go build get-cpu-os.go
 ---> Running in 2a623a44a760
Removing intermediate container 2a623a44a760
 ---> a8b499ec1a66
Step 5/8 : FROM golang
 ---> 7d1902a99d63
Step 6/8 : WORKDIR /gorun
 ---> Running in c5f0571f23a2
Removing intermediate container c5f0571f23a2
 ---> ff55b5c620eb
Step 7/8 : COPY --from=builder /gobuild/get-cpu-os .
 ---> d2eb316ce2d8
Step 8/8 : CMD ["./get-cpu-os"]
 ---> Running in 509518ac6084
Removing intermediate container 509518ac6084
 ---> bc682938a232
Successfully built bc682938a232
Successfully tagged zhaowenyu/get-cpu-os:latest-amd64

镜像构建完成后,一般会使用 docker push 推送到远程镜像仓库,便于在不同环境节点上都能快速拉取。

构建 arm64 镜像

选择一台 ARM64 机器作为镜像构建机器,来构建可在 ARM64 架构机器上运行的容器镜像。

可以通过 lscpu 命令查看机器的 CPU 硬件相关系信息,如下 CPU 信息表明其是 Architecture: aarch64 架构的机器。

AArch64 是 ARMv8 架构的一种执行状态,arm64 已经与 aarch64 合并,因为 aarch64 和 arm64 指的是同一件事。

相关的 CPU 和操作系统内核相关信息:

# lscpu 
Architecture:          aarch64
Byte Order:            Little Endian
CPU(s):                96
On-line CPU(s) list:   0-95
Thread(s) per core:    1
Core(s) per socket:    48
座:                 2
NUMA 节点:         4
型号:              0
CPU max MHz:           2600.0000
CPU min MHz:           200.0000
BogoMIPS:            200.00
L1d 缓存:          64K
L1i 缓存:          64K
L2 缓存:           512K
L3 缓存:           49152K
NUMA 节点0 CPU:    0-23
NUMA 节点1 CPU:    24-47
NUMA 节点2 CPU:    48-71
NUMA 节点3 CPU:    72-95
Flags:             fp asimd evtstrm aes......

查看操作系统内核信息。如下说明该构建机器是 GNU/Linux ,内核版本是 4.18.0-80.7.2,也可以看出是 aarch64 的架构信息。

# uname  -a
Linux arm-k8s1 4.18.0-80.7.2.el7.aarch64 #1 SMP Thu Sep 12 16:13:20 UTC 2019 aarch64 aarch64 aarch64 GNU/Linux

在该机器上通过 docker build 工具来构建镜像

# docker build -t zhaowenyu/get-cpu-os:latest-arm64 .
Sending build context to Docker daemon  6.656kB
Step 1/8 : FROM golang AS builder
latest: Pulling from library/golang
3a36574378e6: Pull complete 
a61d3345afba: Pull complete 
3e267d6aa58f: Pull complete 
f647907d26b8: Pull complete 
c64921c44c8b: Pull complete 
4d35a8839961: Pull complete 
fdcf0c916203: Pull complete 
Digest: sha256:02c05351ed076c581854c554fa65cb2eca47b4389fb79a1fc36f21b8df59c24f
Status: Downloaded newer image for golang:latest
 ---> 2c818329d3a1
Step 2/8 : WORKDIR /gobuild
 ---> Running in e5d478535d09
Removing intermediate container e5d478535d09
 ---> c8cebf89db0f
Step 3/8 : COPY  get-cpu-os.go  .
 ---> d3b30edcb2c0
Step 4/8 : RUN go build get-cpu-os.go
 ---> Running in df6fcd85d673
Removing intermediate container df6fcd85d673
 ---> 6475b747c8f7
Step 5/8 : FROM golang
 ---> 2c818329d3a1
Step 6/8 : WORKDIR /gorun
 ---> Running in 31f8988f9347
Removing intermediate container 31f8988f9347
 ---> 976793f65db3
Step 7/8 : COPY --from=builder /gobuild/get-cpu-os .
 ---> 1b7db0788762
Step 8/8 : CMD ["./get-cpu-os"]
 ---> Running in c733d419c425
Removing intermediate container c733d419c425
 ---> 4d2bd0767a4a
Successfully built 4d2bd0767a4a
Successfully tagged zhaowenyu/get-cpu-os:latest-arm64

基于 manifest 的方式组合多平台架构镜像

在 多架构镜像三部曲(一)组合 文章中对该方法已经有过介绍说明,这里根据 demo 场景再进行一次描述,如果了解可跳过该部分内容。

现在已经使用同一份代码构建出来两个不同平台的容器镜像。

由于多架构镜像核心是维护清单列表(manifest lists),并不是维护具体的镜像 overlay 层等信息,要求在构建多架构镜像前需要镜像推送到远程仓库中,即要求镜像在远程 Registry 镜像仓库中已经存在。

如上文构建的两个 ARM64 和 AMD64 的镜像

  • zhaowenyu/get-cpu-os:latest-amd64
  • zhaowenyu/get-cpu-os:latest-arm64

使用 docker manifest create 命令可以组合一个本地的多架构镜像清单列表

# docker manifest create zhaowenyu/get-cpu-os:latest zhaowenyu/get-cpu-os:latest-arm64 zhaowenyu/get-cpu-os:latest-amd64
Created manifest list docker.io/zhaowenyu/get-cpu-os:latest

在 create 时,传入的参数有顺序要求,如下是帮助信息的 Usage

Usage:  docker manifest create MANIFEST_LIST MANIFEST [MANIFEST...]

第一参数 MANIFEST_LIST 就是目标构建的多架构镜像的清单列表的关联 tag,后续参数可以添加任意多个同功能不同架构类型的镜像。

组合完成后,可以使用 docker manifest inspect 查看多架构镜像信息

# docker manifest inspect zhaowenyu/get-cpu-os:latest
{
   "schemaVersion": 2,
   "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
   "manifests": [
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 2214,
         "digest": "sha256:48c2fece37628701d3471dc91a4a9e8cc5e590bc784df6b752dc093c3b386875",
         "platform": {
            "architecture": "amd64",
            "os": "linux"
         }
      },
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 2213,
         "digest": "sha256:6d3c73aa46e39dbae03dd429e1d34a24656cdec60ec23ad2322758901e1954d4",
         "platform": {
            "architecture": "arm64",
            "os": "linux"
         }
      }
   ]
}

可以看到在这个 manifests list 中存在了两个不同架构的 manifests。

如果需要修改或添加 manifests list 中的信息,可以通过 docker manifest annotate 来操作

例如,修改多架构镜像中 amd64 镜像的操作系统信息

# docker manifest annotate  --os-version "centos8"  zhaowenyu/get-cpu-os:latest zhaowenyu/get-cpu-os:latest-amd64

# docker manifest inspect zhaowenyu/get-cpu-os:latest
{
   "schemaVersion": 2,
   "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
   "manifests": [
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 2214,
         "digest": "sha256:48c2fece37628701d3471dc91a4a9e8cc5e590bc784df6b752dc093c3b386875",
         "platform": {
            "architecture": "amd64",
            "os": "linux",
            "os.version": "centos8"
         }
      },
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 2213,
         "digest": "sha256:6d3c73aa46e39dbae03dd429e1d34a24656cdec60ec23ad2322758901e1954d4",
         "platform": {
            "architecture": "arm64",
            "os": "linux"
         }
      }
   ]
}

命令参数需要先指定多架构镜像 TAG,然后再指定多架构镜像中某个具体需要修改的镜像 TAG。

在修改完成在查看,会看到多出 "os.version": "centos8" 的注释信息

使用 docker manifest create 创建 manifests list 清单列表还是保存在本地的,使用前需要通过 docker manifest push 推送到远程仓库。

# docker manifest push zhaowenyu/get-cpu-os:latest
sha256:2a737be3ac1f8db101c81341be02184949b4bec9d76ef3f79dadc6952317aac0

删除本地 manifests list

在不需要时,可以通过 docker manifest rm 删除本地的 manifest list

# docker manifest rm zhaowenyu/get-cpu-os:latest

自动识别拉取

在 AMD64 的服务器上执行 docker pulldocker run 等镜像拉取命令时,docker 客户端会根据当前客户端机器信息自动拉取对应架构镜像层等数据。

#  docker version -f '{{json .Client.Os}}'
"linux"
#  docker version -f '{{json .Client.Arch}}' 
"amd64"

正常拉取 amd64 相关的镜像信息执行,并返回当前节点运行的结果。

# docker run -it --rm zhaowenyu/get-cpu-os:latest
CPU Arch:  amd64
Operating System: linux

在 ARM64 服务器上运行验证构建的镜像

在 arm64 的服务器上执行 docker pulldocker run 等镜像拉取命令时,docker 客户端会根据当前客户端机器信息自动拉取对应架构镜像层等数据。

# docker version -f '{{json .Client.Os}}'
"linux"
# docker version -f '{{json .Client.Arch}}'
"arm64"

正常拉取 arm64 相关的镜像信息执行,并返回当前节点运行的结果。

# docker run -it --rm zhaowenyu/get-cpu-os:latest
Unable to find image 'zhaowenyu/get-cpu-os:latest' locally
latest: Pulling from zhaowenyu/get-cpu-os
Digest: sha256:2a737be3ac1f8db101c81341be02184949b4bec9d76ef3f79dadc6952317aac0
Status: Downloaded newer image for zhaowenyu/get-cpu-os:latest
CPU Arch:  arm64
Operating System: linux

基于 Buildx 的方式组合多平台架构镜像

Buildx 是一个 Docker CLI 插件,它扩展了 docker build 命令的镜像构建功能,完整的支持 Moby BuildKit builder 工具包提供的特性。也提供了与 docker build 相似的操作体验,并提供了许多新构建特性,比如多架构镜像构建,以及并发构建等。

Buildx 是基于 BuildKit 的 Docker 扩展插件项目。Buildx 默认使用 BuildKit 引擎进行构建,本质上调用了 Buildkit 的 API,镜像构建过程是在 Buildkit 的环境中进行的。

Buildx 工具提供 docker buildx imagetools 工具来提供和 docker manifest 类似的命令,同时 buildx 支持在新镜像创建时,源镜像可以是单个平台的镜像,也可以是多平台架构的镜像,即可以在一个已经存在的多平台架构镜像中继续添加新的平台架构镜像;例如,可以在已经支持 amd64 和 x86 的多架构镜像中继续添加 arm64 平台的镜像层。同样这些镜像也必须在 registry 中已经存在才能组合。

# docker buildx imagetools create -t zhaowenyu/get-cpu-os:v2  zhaowenyu/get-cpu-os:latest-amd64 zhaowenyu/get-cpu-os:latest-arm64
docker.io/zhaowenyu/get-cpu-os:v2

docker manifest 在本地构建出 manifests list 后 push 到远程 Registry 仓库的方式不同,docker buildx imagetools 是直接在远程 Registry 仓库中构建,构建过程并不保存在本地。

buildx 也提供了 docker buildx imagetools inspect 命令来查看远程 Registry 仓库中 manifests list 的信息。

# docker buildx imagetools inspect zhaowenyu/get-cpu-os:v2
Name:      docker.io/zhaowenyu/get-cpu-os:v2
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest:    sha256:b373bd13219a3f46d6f74691fee2c2de19393955c21bc1552218692784f5dab1
           
Manifests: 
  Name:      docker.io/zhaowenyu/get-cpu-os:v2@sha256:48c2fece37628701d3471dc91a4a9e8cc5e590bc784df6b752dc093c3b386875
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/amd64
             
  Name:      docker.io/zhaowenyu/get-cpu-os:v2@sha256:6d3c73aa46e39dbae03dd429e1d34a24656cdec60ec23ad2322758901e1954d4
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm64

运行验证

与上文验证方式方式相同,分别在 amd64 和 arm64 上运行,能正常执行输出运行的机器 CPU 和 系统信息说明符合期望

  • 在 amd64 节点运行
# docker run --rm -it zhaowenyu/get-cpu-os:v2
CPU Arch:  amd64
Operating System: linux
  • 在 arm64 节点运行
# docker run --rm -it zhaowenyu/get-cpu-os:v2
CPU Arch:  arm64
Operating System: linux

基于交叉编译的镜像构建方式

除了使用 docker manifestdocker buildx imagetools 将分别构建的镜像组合成多平台架构镜像外,Buildx 支持直接构建出多个不同类型的平台架构镜像。

但是,使用 Buildx 的多架构镜像构建功能时有一定的限制:

Buildx 限制和应对:

  • Docker 版本限制。使用 buildx 作为 docker CLI 插件需要使用 Docker 19.03 或更高的版本才能支持。旧版本的 Docker 也可以单独安装调用二进制文件作为插件,可以支持部分功能。对于 Docker 版本大于 19.03 的版本,可以直接调用 buildx 二进制来访问 docker buildx 子命令。
  • Linux 内核版本限制。要求 Linux kernel >= 4.8,因为自该 Linux 内核版本 binfmt_misc 才支持 fix-binary (F) flag。fix_binary 标志允许内核在容器或 chroot 内使用 binfmt_misc 注册的二进制格式处理程序,即使该处理程序二进制文件不是该容器或 chroot 内可见的文件系统的一部分。即可以支持编译打包不同架构平台的镜像。

大于 Docker 19.03 版本的安装可以通过软件源或官方下载页面获取更高版本的安装包,而对于宿主机需要将内核升级到 4.8 以上或者安装高版本的操作系统发行版本。

需要注意的是,即便内核版本大于 Linux kernel >= 4.8,也有可能还没有开启内核相关的特性支持,可以通过如下方法来快速配置:

$ docker run --privileged --rm tonistiigi/binfmt --install all
Unable to find image 'tonistiigi/binfmt:latest' locally
latest: Pulling from tonistiigi/binfmt
2b4d0e08bd75: Pull complete 
c331be51c382: Pull complete 
Digest: sha256:5bf63a53ad6222538112b5ced0f1afb8509132773ea6dd3991a197464962854e
Status: Downloaded newer image for tonistiigi/binfmt:latest
installing: arm64 OK
installing: s390x OK
installing: riscv64 OK
installing: arm OK
installing: ppc64le OK
installing: mips64le OK
installing: mips64 OK
{
  "supported": [
    "linux/amd64",
    "linux/ppc64le",
    "linux/s390x",
    "linux/386",
    "linux/arm/v7",
    "linux/arm/v6"
  ],
  "emulators": [
    "qemu-aarch64",
    "qemu-arm",
    "qemu-mips64",
    "qemu-mips64el",
    "qemu-ppc64le",
    "qemu-riscv64",
    "qemu-s390x"
  ]
}

builder 构建器实例:

Buildx 在构建镜像时,实际上会将构建的任务传递给具体的执行服务,这个执行服务就是 builder 构建器。builder 构建器是一个或一组后端提供镜像构建的服务器实例,能够提供集群规模的并发构建。

Buildx 具有灵活的特性,builder 支持配置驱动的方式来运行在不同的场景,目前支持三种驱动方式,以后会计划支持更多的驱动。

  • 其一,支持 docker 驱动,将 BuildKit 库绑定到 Docker Daemon 守护进程中,直接使用 dockerd 服务的构建能力。
  • 其二,支持 docker-container 驱动,会自动在 Docker 容器中启动 BuildKit 以提供镜像构建环境。
  • 其三,支持 kubernetes 驱动,它会自动启动带有定义的 BuildKit 容器镜像的 pod,以提供镜像构建环境。

用户即使选择的驱动不同,在使用 buildx 时的操作方式也基本一样。

默认情况下 buildx 最初会使用 docker 驱动,提供一个非常类似于原生 docker 构建的用户体验,但这需要使用本地共享守护进程来构建应用程序。和传统的 docker build 客户端镜像构建过程一致,只是换成了新的 docker buildx build 客户端。

但有些特性目前 docker 驱动还不支持,因为绑定到 docker daemon 守护进程方式与 BuildKit 库目前使用了不同的存储组件,因此在使用 docker 驱动时只能构建 docker daemon 运行节点平台架构的镜像,不支持多架构镜像构建。同时,所有使用 docker 驱动构建的镜像默认会自动添加到 docker images 视图中;而使用其他驱动时,需要使用 --output 选择输出镜像的方法。

Buildx 可以创建独立的 builder 实例,使用 docker buildx create 命令创建新的 builder 实例。您可以使用一组远程节点来创建新实例,形成构建集群,并在多个 builder 之间快速切换。对于 docker 驱动这特性可以用于给 CI 构建提供一个不影响系统共享 docker daemon 守护进程状态的环境,或者用于隔离不同项目的构建。

Docker 还有一个 docker context 命令,可以通过名称来访问远程 Docker API 的 endpoits 实例列表。Buildx 集成了 docker 上下文,这样所有的上下文都会自动获得一个默认的构建器实例。在创建新的构建器实例或向其添加节点时,还可以将上下文名称作为设置目标。

要使用远程节点,您可以在创建新的构建器时指定 DOCKER_HOST 或远程上下文名称。创建一个新实例后,你可以使用 docker buildx inspectdocker buildx stopdocker buildx rm 命令来管理它的生命周期。要列出所有可用的构建器,请使用 docker buildx ls。创建新构建器后,还可以使用向其添加新节点来提升构建集群的构建能力。

要在不同的构建器之间切换,使用 docker buildx use 来切换默认的构建器,运行此命令后,构建命令将自动使用此构建器。否则需要在执行相关命令时使用 --builder 选项人为指定目标构建器。

builder 构建器是否支持多架构,取决于 Buildkit 的环境。 如果内核支持 Buildkit 可以直接支持多架构构建。 如果内核不支持,也可以通过 builder 关联不同架构的机器来进行构建。

多架构镜像的 Dockerfile

  • 修改dockerfile

在构建多架构镜像时,想要构建出不同的架构平台镜像,就需要在构建时获取到对应架构的基础镜像。在使用 docker buildx build 时通过 --platform 参数指定想要构建的目标平台,在 Dockerfile 中通过 --platform=$TARGETPLATFORM 来获取对应参数信息,下载对应架构的基础镜像。

在上文的 Dockerfile 基础上,修改后的 Dockerfile 内容如下:

FROM  --platform=$TARGETPLATFORM golang AS builder
ARG TARGETPLATFORM
ARG BUILDPLATFORM
WORKDIR /gobuild
COPY  get-cpu-os.go  .
RUN go build get-cpu-os.go

FROM --platform=$TARGETPLATFORM golang
ARG TARGETPLATFORM
ARG BUILDPLATFORM
WORKDIR /gorun
COPY --from=builder /gobuild/get-cpu-os .
CMD ["./get-cpu-os"]

Buildx 在构建时支持向 Dockerfile 传入的参数变量如下:

  • TARGETPLATFORM 构建镜像的目标平台,例如 linux/amd64, linux/arm/v7, windows/amd64。
  • TARGETOS TARGETPLATFORM 的 OS 类型,例如 linux, windows
  • TARGETARCH TARGETPLATFORM 的架构类型,例如 amd64, arm
  • TARGETVARIANT TARGETPLATFORM 的变种,该变量可能为空,例如 v7
  • BUILDPLATFORM 构建镜像主机平台,例如 linux/amd64
  • BUILDOS BUILDPLATFORM 的 OS 类型,例如 linux
  • BUILDARCH BUILDPLATFORM 的架构类型,例如 amd64
  • BUILDVARIANT BUILDPLATFORM 的变种,该变量可能为空,例如 v7

多架构镜像构建并推送

按照 buildx 的依赖准备高版本的 docker 和 Linux 内核后,在构建多架构镜像前需先创建一个 builder 构建器实例。

例如通过 docker buildx create 命令创建一个 mybuilder 的构建器实例

# docker buildx create --name=mybuilder --driver docker-container  --platform linux/amd64,linux/386,linux/riscv64,linux/arm/v7,linux/arm/v6,linux/s390x,linux/ppc64le,linux/arm64
mybuilder

该构建的参数

  • --name=mybuilder: 给构建器指定一个名称,便于人来查看和管理
  • --driver docker-container: 指定构建器的驱动类型
  • --platform linux/amd64,...: 指定该构建器支持构建的架构类型

在构建器创建成功后,当前 docker 节点上 builder 实例列表可以通过 docker buildx ls 来查看

# docker buildx ls
NAME/NODE    DRIVER/ENDPOINT             STATUS   PLATFORMS
mybuilder    docker-container                     
  mybuilder0 unix:///var/run/docker.sock inactive linux/amd64*, linux/386*, linux/riscv64*, linux/arm/v7*, linux/arm/v6*, linux/s390x*, linux/ppc64le*, linux/arm64*

在镜像构建时如果没有通过 --builder 指定明确的构建器,那么 buildx 会使用默认的构建器。

默认构建器 builder 名称后以 * 标记,可以通过 docker buildx use 来切换默认的构建器

# docker buildx use mybuilder
# docker buildx ls
NAME/NODE    DRIVER/ENDPOINT             STATUS   PLATFORMS
mybuilder *  docker-container                     
  mybuilder0 unix:///var/run/docker.sock inactive linux/amd64*, linux/386*, linux/riscv64*, linux/arm/v7*, linux/arm/v6*, linux/s390x*, linux/ppc64le*, linux/arm64*
default      docker                               
  default    default                     running  linux/amd64,  linux/386, linux/arm/v7, linux/arm/v6, linux/ppc64le

通过 docker buildx inspect 来单独查看某一个指定的 builder 构建器的详细信息

# docker buildx inspect mybuilder
Name:   mybuilder
Driver: docker-container

Nodes:
Name:      mybuilder0
Endpoint:  unix:///var/run/docker.sock
Status:    inactive
Platforms: linux/amd64*, linux/386*, linux/riscv64*, linux/arm/v7*, linux/arm/v6*, linux/s390x*, linux/ppc64le*, linux/arm64*

构建器在创建成功后状态是 Status: inactive, 需要通过 docker buildx inspect 添加 --bootstrap 参数来启动构建器后才能正常使用该构建器构建镜像。

启动 mybuilder 构建器

# docker buildx inspect --bootstrap --builder mybuilder
[+] Building 17.6s (1/1) FINISHED                                                                                                                             
 => [internal] booting buildkit                                                                                                                         17.6s
 => => pulling image moby/buildkit:buildx-stable-1                                                                                                      12.4s
 => => creating container buildx_buildkit_mybuilder0                                                                                                     5.1s
Name:   mybuilder
Driver: docker-container

Nodes:
Name:      mybuilder0
Endpoint:  unix:///var/run/docker.sock
Status:    running
Platforms: linux/amd64*, linux/386*, linux/riscv64*, linux/arm/v7*, linux/arm/v6*, linux/s390x*, linux/ppc64le*, linux/arm64*, linux/amd64/v2, linux/amd64/v3, linux/mips64le, linux/mips64

开始构建多架构镜像

在一切准备就绪后,就可以通过 docker buildx build 来构建多架构镜像。

docker buildx build --builder mybuilder \
-t zhaowenyu/get-cpu-os:v4 \
--platform linux/amd64,linux/386,linux/arm/v7,linux/arm/v6,linux/s390x,linux/ppc64le,linux/arm64 \
-f Dockerfile-multi \
--push .

在构建多架构镜像时需要注意的参数说明

  • --builder mybuilder: 是指定使用哪个构建器,mybuilder 就是在前置步骤中创建出来的构建器。如果使用了 docker buildx use mybuilder 切换了当前默认构建器,那么这个 --builder mybuilder 也可以省略。
  • -t zhaowenyu/get-cpu-os:v4: 和 docker build 一样给构建的镜像指定的 TAG,这也是多架构镜像的核心入口,他是个 manifests list,即在一个 TAG 中可描述多个平台的镜像相关信息。
  • --platform linux/amd64,linux/386,linux/arm/v7,linux/arm/v6,linux/s390x,linux/ppc64le,linux/arm64: 指定构建的镜像目标架构列表列表,目前只有 docker-container 和 kubernetes 驱动支持。
  • -f Dockerfile-multi: 和 docker build 指定 Dockerfile 一样,这里只是为了便于和普通的 Dockerfile 区分添加了后缀,如果在上下文目录中只有 Dockerfile 文件,该参数也可以省略。
  • --push: 这里的 --push--output=type=registry 的简写,指定了输出的类型和位置,registry 就是输出到远程镜像仓库,那就是 push 的意思了。
  • .: 注意,这里还有一个点,它和 docker build 的含义一样,是指 上下文 的概念,将代码或文件发送到 builder 构建器时的相对初始位置。

以下是构建的日志输出:

# docker buildx build --builder mybuilder -t zhaowenyu/get-cpu-os:v4 --platform linux/amd64,linux/386,linux/arm/v7,linux/arm/v6,linux/s390x,linux/ppc64le,linux/arm64 -f Dockerfile-multi --push .
[+] Building 27.1s (16/52)                                                                                                                                    
 => => transferring context: 2B                                                                                                                          0.0s
[+] Building 27.3s (16/52)                                                                                                                                    
 => => transferring context: 2B                                                                                                                          0.0s
[+] Building 27.4s (16/52)                                                                                                                                    
 => => transferring context: 2B                                                                                                                          0.0s
[+] Building 27.6s (16/52)                                                                                                                                    
 => [linux/arm64 internal] load metadata for docker.io/library/golang:latest                                                                             5.7s
[+] Building 255.5s (54/54) FINISHED                                                                                                                          
 => [internal] load .dockerignore                                                                                                                        0.0s
 => => transferring context: 2B                                                                                                                          0.0s
 => [internal] load build definition from Dockerfile-multi                                                                                               0.0s
 => => transferring dockerfile: 355B                                                                                                                     0.0s
 => [linux/arm64 internal] load metadata for docker.io/library/golang:latest                                                                             5.7s
 => [linux/amd64 internal] load metadata for docker.io/library/golang:latest                                                                             5.2s
 => [linux/arm/v7 internal] load metadata for docker.io/library/golang:latest                                                                            5.1s
 => [linux/386 internal] load metadata for docker.io/library/golang:latest                                                                               5.1s
 => [linux/s390x internal] load metadata for docker.io/library/golang:latest                                                                             5.2s
 => [linux/ppc64le internal] load metadata for docker.io/library/golang:latest                                                                           5.2s
 => [linux/arm/v6 internal] load metadata for docker.io/library/golang:latest                                                                            5.2s
 => [linux/amd64 builder 1/4] FROM docker.io/library/golang@sha256:02c05351ed076c581854c554fa65cb2eca47b4389fb79a1fc36f21b8df59c24f                      0.1s
 => => resolve docker.io/library/golang@sha256:02c05351ed076c581854c554fa65cb2eca47b4389fb79a1fc36f21b8df59c24f                                          0.1s
 => [internal] load build context                                                                                                                        0.1s
 => => transferring context: 35B                                                                                                                         0.0s
 => [linux/arm/v7 builder 1/4] FROM docker.io/library/golang@sha256:02c05351ed076c581854c554fa65cb2eca47b4389fb79a1fc36f21b8df59c24f                     0.0s
 => => resolve docker.io/library/golang@sha256:02c05351ed076c581854c554fa65cb2eca47b4389fb79a1fc36f21b8df59c24f                                          0.1s
 => => sha256:110d446101c6cc14507d2bdb8d57bba3f29603afee72e24aaf4b49fd594e177f 156B / 156B                                                               0.6s
 => => sha256:0194bab7cdf2143b4fb29d670862add2eb52568ec00950895991d685168322a6 110.04MB / 110.04MB                                                      41.5s
 => => sha256:4f2684ae1c60ffa462dc3c94e2843e9deb57bb53b9532317930d9f1e3ba961b8 64.81MB / 64.81MB                                                        20.8s
 => => sha256:c410c75a05c2df4ed485cda22fd35206e0ea4b9fbc9f096b11ed5adc6f83fa1c 50.33MB / 50.33MB                                                        15.8s
 => => sha256:dd8f92194faa0a66e5bd160b229941428f0b0387c6e313e4f1f903c678fbb17e 10.22MB / 10.22MB                                                         5.2s
 => => sha256:f71423015d7b4f718e54ff1561cc06bb4c8357baedc23b49d25fe99cd4b0ae41 4.92MB / 4.92MB                                                           2.9s
 => => sha256:ba38f9a6c66968e207a7ada348a2110e3be0ff117e621d9e10ddd7c4becc0d2a 50.13MB / 50.13MB                                                        16.1s
 => => extracting sha256:ba38f9a6c66968e207a7ada348a2110e3be0ff117e621d9e10ddd7c4becc0d2a                                                                1.4s
 => => extracting sha256:f71423015d7b4f718e54ff1561cc06bb4c8357baedc23b49d25fe99cd4b0ae41                                                                0.2s
 => => extracting sha256:dd8f92194faa0a66e5bd160b229941428f0b0387c6e313e4f1f903c678fbb17e                                                                0.2s
 => => extracting sha256:c410c75a05c2df4ed485cda22fd35206e0ea4b9fbc9f096b11ed5adc6f83fa1c                                                                1.6s
 => => extracting sha256:4f2684ae1c60ffa462dc3c94e2843e9deb57bb53b9532317930d9f1e3ba961b8                                                                1.3s
 => => extracting sha256:0194bab7cdf2143b4fb29d670862add2eb52568ec00950895991d685168322a6                                                                3.8s
 => => extracting sha256:110d446101c6cc14507d2bdb8d57bba3f29603afee72e24aaf4b49fd594e177f                                                                0.0s
 => [linux/arm/v6 builder 1/4] FROM docker.io/library/golang@sha256:02c05351ed076c581854c554fa65cb2eca47b4389fb79a1fc36f21b8df59c24f                     0.0s
 => => resolve docker.io/library/golang@sha256:02c05351ed076c581854c554fa65cb2eca47b4389fb79a1fc36f21b8df59c24f                                          0.1s
 => => sha256:39555a4ffde23105be228c1f01e04c26654a76b10a1bd933c515ddfa89bb01a1 156B / 156B                                                               2.1s
 => => sha256:714016f0e72e60e4b263ec4c814a24b248f054f6567d0f4083e06d0767a1fdc5 112.19MB / 112.19MB                                                      37.7s
 => => sha256:0dfe350586b0ee030975727112d877ff8407b1b4279c4e05283698f75b7ce560 68.78MB / 68.78MB                                                        19.5s
 => => sha256:10bfe50f7f2db6acb117a778b84c53664ce16ba884ae8de0447fbea2a07acea5 52.32MB / 52.32MB                                                        19.1s 
 => => sha256:01aff9f1fe546a28b9bdb7a85b87eaaa7c9c039d0e60a7372cdcc31f58842e25 10.57MB / 10.57MB                                                         4.7s 
 => => sha256:0e8d2e3c89e648f74d8cba2be942f53fbcdf53c845d8180c2c93199322a0573f 5.07MB / 5.07MB                                                           2.5s
 => => sha256:0ca4fabca59ca0d617061b776745ff41fdc3968ce90dd2b9198717e0bae91d98 52.48MB / 52.48MB                                                        16.0s
 => => extracting sha256:0ca4fabca59ca0d617061b776745ff41fdc3968ce90dd2b9198717e0bae91d98                                                                1.5s
 => => extracting sha256:0e8d2e3c89e648f74d8cba2be942f53fbcdf53c845d8180c2c93199322a0573f                                                                0.2s
 => => extracting sha256:01aff9f1fe546a28b9bdb7a85b87eaaa7c9c039d0e60a7372cdcc31f58842e25                                                                0.2s
 => => extracting sha256:10bfe50f7f2db6acb117a778b84c53664ce16ba884ae8de0447fbea2a07acea5                                                                1.6s
 => => extracting sha256:0dfe350586b0ee030975727112d877ff8407b1b4279c4e05283698f75b7ce560                                                                2.9s
 => => extracting sha256:714016f0e72e60e4b263ec4c814a24b248f054f6567d0f4083e06d0767a1fdc5                                                                4.0s
 => => extracting sha256:39555a4ffde23105be228c1f01e04c26654a76b10a1bd933c515ddfa89bb01a1                                                                0.0s
 => [linux/386 builder 1/4] FROM docker.io/library/golang@sha256:02c05351ed076c581854c554fa65cb2eca47b4389fb79a1fc36f21b8df59c24f                        0.9s
 => => resolve docker.io/library/golang@sha256:02c05351ed076c581854c554fa65cb2eca47b4389fb79a1fc36f21b8df59c24f                                          0.1s
 => => sha256:394b1cdeae57880f2fa270f6d12d84a70633e9513711e137550db3367f1d8080 126B / 126B                                                               0.6s
 => => sha256:b61f118c4285ecaed0eb8ac8352076b3e32077984674a109a1a760561f39f469 112.87MB / 112.87MB                                                      34.2s
 => => sha256:f8d7e1d16d764a12a206e2c8e9a01ee1699c4a3ca9bcd82f454156ec4761b8cc 87.08MB / 87.08MB                                                        28.3s
 => => sha256:1a5333a48696af9b52c4219f20b87c5cf9b05764b7c58cd19880e6c5730d1b75 55.91MB / 55.91MB                                                        19.7s
 => => sha256:66dba083f619f2a2c8cfef4a4e844cf6819c306e225029e62cf7c31c17b0d344 11.03MB / 11.03MB                                                         4.3s
 => => sha256:026e99ab0e4b1d3aec936d04cdf9c04ddc8074f2917b86c02e66d88fcae1e42f 5.08MB / 5.08MB                                                           3.0s
 => => sha256:5ad4f92623738998bc77103ff64344255f842f6e5fe4a846df656351b3c4852f 55.94MB / 55.94MB                                                        18.7s
 => => extracting sha256:5ad4f92623738998bc77103ff64344255f842f6e5fe4a846df656351b3c4852f                                                                1.6s
 => => extracting sha256:026e99ab0e4b1d3aec936d04cdf9c04ddc8074f2917b86c02e66d88fcae1e42f                                                                0.2s
 => => extracting sha256:66dba083f619f2a2c8cfef4a4e844cf6819c306e225029e62cf7c31c17b0d344                                                                0.2s
 => => extracting sha256:1a5333a48696af9b52c4219f20b87c5cf9b05764b7c58cd19880e6c5730d1b75                                                                1.6s
 => => extracting sha256:f8d7e1d16d764a12a206e2c8e9a01ee1699c4a3ca9bcd82f454156ec4761b8cc                                                                2.6s
 => => extracting sha256:b61f118c4285ecaed0eb8ac8352076b3e32077984674a109a1a760561f39f469                                                                6.6s
 => => extracting sha256:394b1cdeae57880f2fa270f6d12d84a70633e9513711e137550db3367f1d8080                                                                0.9s
 => [linux/arm64 builder 1/4] FROM docker.io/library/golang@sha256:02c05351ed076c581854c554fa65cb2eca47b4389fb79a1fc36f21b8df59c24f                      0.0s
 => => resolve docker.io/library/golang@sha256:02c05351ed076c581854c554fa65cb2eca47b4389fb79a1fc36f21b8df59c24f                                          0.1s
 => => sha256:fdcf0c9162039d8f9f073991c3f17b0bd401d5c6bf2cba3bd2e70e55fc617971 126B / 126B                                                               1.2s
 => => sha256:4d35a8839961a2084ed852b5cf2acb4eb26fa23a8f5eaa1d3d926b7a5239799d 108.86MB / 108.86MB                                                      30.7s
 => => sha256:c64921c44c8b8e3bbab616d9ea7740c81562749239ad36db6017db3decdc6ec3 81.07MB / 81.07MB                                                        24.3s
 => => sha256:f647907d26b879e0d43f6f4f0807f01e4dbdc034edcecbc988f6033cf401becf 54.67MB / 54.67MB                                                        16.3s
 => => sha256:3e267d6aa58f93a513352a3b46c7addbf9335d7d43bfa4f1df4026d21785181c 10.66MB / 10.66MB                                                         5.6s
 => => sha256:a61d3345afba43846f3e638752cce2f0d1d47b21cc667ba08b00db10767a4702 4.94MB / 4.94MB                                                           3.7s
 => => sha256:3a36574378e6cece2dd3a839e1c0220eaccc4063b61d7481d1a19d3990c1f2c2 53.63MB / 53.63MB                                                        18.8s
 => => extracting sha256:3a36574378e6cece2dd3a839e1c0220eaccc4063b61d7481d1a19d3990c1f2c2                                                                1.9s
 => => extracting sha256:a61d3345afba43846f3e638752cce2f0d1d47b21cc667ba08b00db10767a4702                                                                1.5s
 => => extracting sha256:3e267d6aa58f93a513352a3b46c7addbf9335d7d43bfa4f1df4026d21785181c                                                                0.4s
 => => extracting sha256:f647907d26b879e0d43f6f4f0807f01e4dbdc034edcecbc988f6033cf401becf                                                                1.8s
 => => extracting sha256:c64921c44c8b8e3bbab616d9ea7740c81562749239ad36db6017db3decdc6ec3                                                                1.7s
 => => extracting sha256:4d35a8839961a2084ed852b5cf2acb4eb26fa23a8f5eaa1d3d926b7a5239799d                                                                3.6s
 => => extracting sha256:fdcf0c9162039d8f9f073991c3f17b0bd401d5c6bf2cba3bd2e70e55fc617971                                                                0.0s
 => [linux/ppc64le builder 1/4] FROM docker.io/library/golang@sha256:02c05351ed076c581854c554fa65cb2eca47b4389fb79a1fc36f21b8df59c24f                    0.0s
 => => resolve docker.io/library/golang@sha256:02c05351ed076c581854c554fa65cb2eca47b4389fb79a1fc36f21b8df59c24f                                          0.1s
 => => sha256:71e5b9bbc90dd0a84de3e3a327d0203291dadff4dc5e862ecaa9a00db90925a4 157B / 157B                                                               1.9s
 => => sha256:04d7a145a3b5b3f9a190d808986bcc607d7851c046fdc00474d5bc9953983b50 108.91MB / 108.91MB                                                      34.8s
 => => sha256:074bac4dde40b172d2bd91ae166ffab07f0773f6389a4ee81f37e67cd100fe89 80.34MB / 80.34MB                                                        20.7s
 => => sha256:093f433f2609e3f4f5695cf59234918a3e0d13ac7eedbe9323cdcd2acfb1ce52 58.86MB / 58.86MB                                                        18.9s
 => => sha256:b8d47d2b8f433338bdfaa5388d0c010792ba3e0bc820e40cd2d316a1b0b6aab1 11.63MB / 11.63MB                                                         4.9s
 => => sha256:aab8b0050e0adc77a432c7431bddb52ffd7a7f6133ffec0b7f2766c951614fc6 5.41MB / 5.41MB                                                           3.0s
 => => sha256:8ad85695cd2aa86dcc7fc175edbdd1c94dbfa061000f3770d4e6f795df7d74c9 58.84MB / 58.84MB                                                        16.1s
 => => extracting sha256:8ad85695cd2aa86dcc7fc175edbdd1c94dbfa061000f3770d4e6f795df7d74c9                                                                2.7s
 => => extracting sha256:aab8b0050e0adc77a432c7431bddb52ffd7a7f6133ffec0b7f2766c951614fc6                                                                0.3s
 => => extracting sha256:b8d47d2b8f433338bdfaa5388d0c010792ba3e0bc820e40cd2d316a1b0b6aab1                                                                0.2s
 => => extracting sha256:093f433f2609e3f4f5695cf59234918a3e0d13ac7eedbe9323cdcd2acfb1ce52                                                                1.9s
 => => extracting sha256:074bac4dde40b172d2bd91ae166ffab07f0773f6389a4ee81f37e67cd100fe89                                                                1.8s
 => => extracting sha256:04d7a145a3b5b3f9a190d808986bcc607d7851c046fdc00474d5bc9953983b50                                                                3.6s
 => => extracting sha256:71e5b9bbc90dd0a84de3e3a327d0203291dadff4dc5e862ecaa9a00db90925a4                                                                0.0s
 => [linux/s390x builder 1/4] FROM docker.io/library/golang@sha256:02c05351ed076c581854c554fa65cb2eca47b4389fb79a1fc36f21b8df59c24f                      0.0s
 => => resolve docker.io/library/golang@sha256:02c05351ed076c581854c554fa65cb2eca47b4389fb79a1fc36f21b8df59c24f                                          0.1s
 => => sha256:2518bdd3e17b88eac94a399f725f8ff97997bfaa293e8bf423ddc4cd31837d19 156B / 156B                                                               1.6s
 => => sha256:35be216d5bcf0c177b4f25c7a7fb7373871322a368dedd31e166a9e3fcacc4ff 111.59MB / 111.59MB                                                      30.1s
 => => sha256:9b5734b8ff861febbe327f7de09a9a36402c2f0b9991d7cbfa1ba9f425d13844 65.58MB / 65.58MB                                                        18.2s
 => => sha256:c36704bf1413eb96906c58893a7d4c74f7d88490eed870be03fe531302614745 54.05MB / 54.05MB                                                        16.0s
 => => sha256:33ef0d35554dad3cfdd15fa175311fb6c20c545c9b04632039378e90a1666435 10.77MB / 10.77MB                                                         6.2s
 => => sha256:c99502d0a4c52d58c73f967ad2c52204db08f01c6512da3a6dfd8d8ea18b3ae6 5.14MB / 5.14MB                                                           5.1s
 => => sha256:f8313f715dc1cdd9f8a3da73eafca06dcb30dff4c078bee35a162247cae99c4d 53.21MB / 53.21MB                                                        19.8s
 => => extracting sha256:f8313f715dc1cdd9f8a3da73eafca06dcb30dff4c078bee35a162247cae99c4d                                                                1.6s
 => => extracting sha256:c99502d0a4c52d58c73f967ad2c52204db08f01c6512da3a6dfd8d8ea18b3ae6                                                                0.2s
 => => extracting sha256:33ef0d35554dad3cfdd15fa175311fb6c20c545c9b04632039378e90a1666435                                                                0.2s
 => => extracting sha256:c36704bf1413eb96906c58893a7d4c74f7d88490eed870be03fe531302614745                                                                1.7s
 => => extracting sha256:9b5734b8ff861febbe327f7de09a9a36402c2f0b9991d7cbfa1ba9f425d13844                                                                1.5s
 => => extracting sha256:35be216d5bcf0c177b4f25c7a7fb7373871322a368dedd31e166a9e3fcacc4ff                                                                3.6s
 => => extracting sha256:2518bdd3e17b88eac94a399f725f8ff97997bfaa293e8bf423ddc4cd31837d19                                                                0.0s
 => CACHED [linux/amd64 builder 2/4] WORKDIR /gobuild                                                                                                    0.0s
 => CACHED [linux/amd64 builder 3/4] COPY  get-cpu-os.go  .                                                                                              0.0s
 => CACHED [linux/amd64 builder 4/4] RUN go build get-cpu-os.go                                                                                          0.0s
 => CACHED [linux/amd64 stage-1 2/3] WORKDIR /gorun                                                                                                      0.0s
 => CACHED [linux/amd64 stage-1 3/3] COPY --from=builder /gobuild/get-cpu-os .                                                                           0.2s
 => [linux/arm/v7 builder 2/4] WORKDIR /gobuild                                                                                                          8.4s
 => [linux/arm/v7 stage-1 2/3] WORKDIR /gorun                                                                                                            8.4s
 => [linux/arm/v7 builder 3/4] COPY  get-cpu-os.go  .                                                                                                    0.1s
 => [linux/arm/v7 builder 4/4] RUN go build get-cpu-os.go                                                                                               13.7s
 => [linux/arm/v7 stage-1 3/3] COPY --from=builder /gobuild/get-cpu-os .                                                                                 0.3s
 => [linux/arm64 stage-1 2/3] WORKDIR /gorun                                                                                                             5.9s
 => [linux/arm64 builder 2/4] WORKDIR /gobuild                                                                                                           5.9s
 => [linux/arm64 builder 3/4] COPY  get-cpu-os.go  .                                                                                                     0.1s
 => [linux/arm64 builder 4/4] RUN go build get-cpu-os.go                                                                                                 5.8s
 => [linux/arm64 stage-1 3/3] COPY --from=builder /gobuild/get-cpu-os .                                                                                  0.2s
 => [linux/ppc64le stage-1 2/3] WORKDIR /gorun                                                                                                           8.0s
 => [linux/ppc64le builder 2/4] WORKDIR /gobuild                                                                                                         8.0s
 => [linux/ppc64le builder 3/4] COPY  get-cpu-os.go  .                                                                                                   0.1s
 => [linux/ppc64le builder 4/4] RUN go build get-cpu-os.go                                                                                               4.2s
 => [linux/ppc64le stage-1 3/3] COPY --from=builder /gobuild/get-cpu-os .                                                                                0.1s
 => [linux/386 stage-1 2/3] WORKDIR /gorun                                                                                                               0.8s
 => [linux/386 builder 2/4] WORKDIR /gobuild                                                                                                             0.8s
 => [linux/386 builder 3/4] COPY  get-cpu-os.go  .                                                                                                       0.1s
 => [linux/386 builder 4/4] RUN go build get-cpu-os.go                                                                                                   0.6s
 => [linux/386 stage-1 3/3] COPY --from=builder /gobuild/get-cpu-os .                                                                                    0.1s
 => [linux/arm/v6 stage-1 2/3] WORKDIR /gorun                                                                                                            4.6s
 => [linux/arm/v6 builder 2/4] WORKDIR /gobuild                                                                                                          4.6s
 => [linux/arm/v6 builder 3/4] COPY  get-cpu-os.go  .                                                                                                    0.1s
 => [linux/arm/v6 builder 4/4] RUN go build get-cpu-os.go                                                                                               10.2s
 => [linux/arm/v6 stage-1 3/3] COPY --from=builder /gobuild/get-cpu-os .                                                                                 0.1s
 => [linux/s390x stage-1 2/3] WORKDIR /gorun                                                                                                             7.7s
 => [linux/s390x builder 2/4] WORKDIR /gobuild                                                                                                           7.7s
 => [linux/s390x builder 3/4] COPY  get-cpu-os.go  .                                                                                                     0.1s
 => [linux/s390x builder 4/4] RUN go build get-cpu-os.go                                                                                                 3.1s
 => [linux/s390x stage-1 3/3] COPY --from=builder /gobuild/get-cpu-os .                                                                                  0.1s
 => exporting to image                                                                                                                                  62.4s
 => => exporting layers                                                                                                                                  0.9s
 => => exporting manifest sha256:bfcfb180369341a1b883540e84f32861b4e4f4466e0a08269d948df4635f036c                                                        0.0s
 => => exporting config sha256:8913aab54b812964db84dc8de6bc8bcb1dde8d64f75945f777edc32467d00e1b                                                          0.0s
 => => exporting manifest sha256:b29b83066f066ddfa0d2fbedd43610aa710823756d60d251b32c41874351c2f0                                                        0.0s
 => => exporting config sha256:211cfd813da891125e84c52cc891b721e29645860abd9f19013ac46ed8ce711d                                                          0.0s
 => => exporting manifest sha256:a7e93352271879e99cc22d46be60a517e83370e21be767fb653929a39ff0ba0b                                                        0.0s
 => => exporting config sha256:2deb48c234ef01f988841e6e301c0a00c2f119c409ed9345dd7a735f25a4ec87                                                          0.0s
 => => exporting manifest sha256:1a5e6635918f0edfe5afee7ca1b7f81792ebdf06b9236285470fdbf4d2934e59                                                        0.0s
 => => exporting config sha256:06e959c2cae12986b8e8bd037b14353116d79a91a34bb6a27e032296b9819dc6                                                          0.0s
 => => exporting manifest sha256:f4e550d7bca25e86f6860dc718b1058310ba28518cff4ae2c3359dd9df7a949c                                                        0.0s
 => => exporting config sha256:69382a36b8ea567e2feab50742a54a007e108f4262ed47005bdc530652a4fcf9                                                          0.0s
 => => exporting manifest sha256:8ee606ae0c7922ca3a2e58272d6882e68aad1405eaf1b53dffb143288fea8a1c                                                        0.0s
 => => exporting config sha256:7e8d15de78f47ce24f633ab5a8e95872c198c4a290167347d33a25455cf212bd                                                          0.0s
 => => exporting manifest sha256:9151f45c1a166fef190e33763bbe1f577d902590ff9a5e89f562ed9df37a61e4                                                        0.0s
 => => exporting config sha256:24e6bdb91e4082d27b5af2bc71a4e5263849fc0e116f1b192b1a845042998051                                                          0.0s
 => => exporting manifest list sha256:e334c9e6c462d9434143bbe7b92a438f10ed8ac279f7a60ed2617548ca647c8a                                                   0.0s
 => => pushing layers                                                                                                                                   56.4s
 => => pushing manifest for docker.io/zhaowenyu/get-cpu-os:v4@sha256:e334c9e6c462d9434143bbe7b92a438f10ed8ac279f7a60ed2617548ca647c8a                    4.9s
 => [auth] zhaowenyu/get-cpu-os:pull,push token for registry-1.docker.io                                                                                 0.0s

查看多架构镜像信息

使用 buildx 提供的 imagetools inspect 工具可以查看远程仓库中的清单列表信息,当然也可以使用 docker manifest inspect 结果是一样。

#  docker buildx imagetools inspect zhaowenyu/get-cpu-os:v4
Name:      docker.io/zhaowenyu/get-cpu-os:v4
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest:    sha256:e334c9e6c462d9434143bbe7b92a438f10ed8ac279f7a60ed2617548ca647c8a
           
Manifests: 
  Name:      docker.io/zhaowenyu/get-cpu-os:v4@sha256:bfcfb180369341a1b883540e84f32861b4e4f4466e0a08269d948df4635f036c
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/amd64
             
  Name:      docker.io/zhaowenyu/get-cpu-os:v4@sha256:b29b83066f066ddfa0d2fbedd43610aa710823756d60d251b32c41874351c2f0
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/386
             
  Name:      docker.io/zhaowenyu/get-cpu-os:v4@sha256:a7e93352271879e99cc22d46be60a517e83370e21be767fb653929a39ff0ba0b
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm/v7
             
  Name:      docker.io/zhaowenyu/get-cpu-os:v4@sha256:1a5e6635918f0edfe5afee7ca1b7f81792ebdf06b9236285470fdbf4d2934e59
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm/v6
             
  Name:      docker.io/zhaowenyu/get-cpu-os:v4@sha256:f4e550d7bca25e86f6860dc718b1058310ba28518cff4ae2c3359dd9df7a949c
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/s390x
             
  Name:      docker.io/zhaowenyu/get-cpu-os:v4@sha256:8ee606ae0c7922ca3a2e58272d6882e68aad1405eaf1b53dffb143288fea8a1c
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/ppc64le
             
  Name:      docker.io/zhaowenyu/get-cpu-os:v4@sha256:9151f45c1a166fef190e33763bbe1f577d902590ff9a5e89f562ed9df37a61e4
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm64

docker hub 效果

除了使用命令行查看,也可以通过访问 hub.docker.com 远程镜像仓库来查看构建的多架构镜像信息

多架构镜像三部曲(二)构建_第1张图片

多架构镜像验证

在 AMD64 服务器上运行验证构建的镜像

在 AMD64 的服务器上验证,镜像正常拉取执行,并返回当前运行的结果。

# docker run -it --rm zhaowenyu/get-cpu-os:v3
CPU Arch:  amd64
Operating System: linux

在 ARM64 服务器上运行验证构建的镜像

在 arm64 的服务器镜像正常拉取执行,并返回当前运行的结果,在此可以看到我们在 X86_64(amd64)机器上可以编译构建出 ARM64 机器运行的可执行文件和镜像。

#  docker run -it --rm zhaowenyu/get-cpu-os:v4
CPU Arch:  arm64
Operating System: linux

结语&思考

到这里基于 docker manifest 和 Buildx 的多架构镜像的介绍已经基本完成了,相信按照文章中的内容你也可以快速构建出符合业务需求多架构应用镜像。

那么这里有个问题可以思考一下,除了 Docker 相关的工具外,是否还知道其他的工具或方法将源码构建成目标容器镜像? 欢迎在评论区写下你的思考和答案,我们一起讨论,共同学习进步。如果你觉得这篇文章对你有所帮助,欢迎你把文章分享给你朋友。

你可能感兴趣的:(cncfstack,架构,cncfstack,docker,云原生)