跳到主要内容
  1. 所有文章/

构建支持多种 CPU 架构的 Docker 镜像

·1430 字·约 3 分钟

前言 #

最近甲骨文首尔 ARM 免费服务器大量放货,我也开了一台 4C 24GB 的机器。这么大内存的机器,我想要在上面托管一些项目,由于一些项目的 Docker 镜像未提供 ARM 架构的支持,所以我了解了一下使用 Docker Buildx 来构建支持多架构的 Docker 镜像。

Docker Buildx 是 Docker CLI 的一个插件,它是默认 Docker Build 命令的拓展,完全支持 Moby BuildKit 构建器的特性并提供与 Docker Build 一致的体验,它带来的新特性之一就是支持构建多架构镜像,更多信息可以查看 Docker 文档 - Docker Buildx

在构建机器上构建与本机 CPU 架构不同的 Docker 镜像会用到 QEMU 的用户空间 (userspace) 仿真和虚拟化,由于虚拟化和模拟有一定性能损失,所以整个构建过程会花费更多时间。

本文不讨论 Dockerfile 的写法,我们以 book-searcher 项目为例,在甲骨文 ARM 服务器 1 上构建支持 AMD64, ARM/V7, ARM64 的 Docker 镜像并推送到 Docker Hub

uname -a
Linux instance-oracle-arm 5.10.0-20-arm64 #1 SMP Debian 5.10.158-2 (2022-12-13) aarch64 GNU/Linux

准备 #

Docker Buildx 在 Docker 19.03 以上版本默认支持,在开始前,建议将构建机器上的 Docker 升级到最新版本

# 查看 buildx 版本信息
sudo docker buildx version
github.com/docker/buildx v0.10.0-docker 876462897612d36679153c3414f7689626251501

# 命令帮助
sudo docker buildx

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.

tonistiigi/binfmt 是一使用 Docker 镜像分发的跨平台仿真模拟器集合,在 Windows/macOS 上的 Docker Desktop 一般默认已经安装了

# 安装所有 CPU 架构模拟器
sudo docker run --privileged --rm tonistiigi/binfmt --install all

# 安装指定 CPU 架构模拟器
sudo docker run --privileged --rm tonistiigi/binfmt --install arm64,riscv64,arm

在 Linux 机器上安装

sudo docker run --privileged --rm tonistiigi/binfmt --install all
Unable to find image 'tonistiigi/binfmt:latest' locally
latest: Pulling from tonistiigi/binfmt
6dda554f4baf: Pull complete
2b0720d7a501: Pull complete
Digest: sha256:66e11bea77a5ea9d6f0fe79b57cd2b189b5d15b93a2bdb925be22949232e4e55
Status: Downloaded newer image for tonistiigi/binfmt:latest
{
  "supported": [
    "linux/arm64",
    "linux/amd64",
    "linux/riscv64",
    "linux/ppc64le",
    "linux/s390x",
    "linux/386",
    "linux/mips64le",
    "linux/mips64",
    "linux/arm/v7",
    "linux/arm/v6"
  ],
  "emulators": [
    "qemu-i386",
    "qemu-mips64",
    "qemu-mips64el",
    "qemu-ppc64le",
    "qemu-riscv64",
    "qemu-s390x",
    "qemu-x86_64"
  ]
}

前面也提到这个构建过程一般会花费更多时间,我们可以使用 screen 来保证会话不会中断 2

# Debian/Ubuntu 安装
sudo apt install -y screen

# 新建一个名为 build 的会话
screen -S build

# 列出开启的 screen 会话
screen -ls

# 恢复某个 screen 会话(比如,上面的 build)
screen -r build

在 Docker Hub 创建一个仓库,创建一个登录令牌用于登录

sudo docker login -u [username]
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

创建一个名称为 multiarch 的 buildx 构建实例并立即使用

sudo docker buildx create --name multiarch --use

列出所有的 buildx 构建实例状态,可以看到这个新的 buildx 构建实例还未启动

sudo docker buildx ls
NAME/NODE    DRIVER/ENDPOINT             STATUS   BUILDKIT PLATFORMS
multiarch *  docker-container
  multiarch0 unix:///var/run/docker.sock inactive
default      docker
  default    default                     running  20.10.22 linux/arm64, linux/arm/v7, linux/arm/v6, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386

我们可以立即启动这个构建实例(不是必须的)

sudo docker buildx inspect --bootstrap
Name:   multiarch
Driver: docker-container

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

再次查看所有 buildx 构建实例状态,可以看到已经在运行了

sudo docker buildx ls
NAME/NODE    DRIVER/ENDPOINT             STATUS  BUILDKIT PLATFORMS
multiarch *  docker-container
  multiarch0 unix:///var/run/docker.sock running v0.11.0  linux/arm64, linux/amd64, linux/amd64/v2, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
default      docker
  default    default                     running 20.10.22 linux/arm64, linux/arm/v7, linux/arm/v6, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386

开始 #

现在可以开始构建多架构的 Docker 镜像了,以 book-searcher 为例

# 拉取 book-searcher 源码
git clone https://github.com/book-searcher-org/book-searcher.git
cd book-searcher

# 开始构建并推送到 Docker Hub 仓库(注意替换 dejavumoe/book-searcher:0.8.3)
sudo docker buildx build -t dejavumoe/book-searcher:0.8.3 --platform=linux/arm/v7,linux/arm64,linux/amd64 . --push

开始构建过程

Buildx
Buildx

构建成功后,镜像会推送到 Docker Hub,比如文中示例的 book-searcher

清理 #

镜像构建并推送完成后,如果没有特殊需求,可以删除构建缓存

# 查看 buildx 构建缓存
sudo docker buildx du
ID						RECLAIMABLE	SIZE		LAST ACCESSED
no7ihggdz0dg9w916xfqdgpo4*              	true 		1.649GB   	19 hours ago
zfsooeun4nk9wuuhzkbs13bvg*              	true 		1.631GB   	19 hours ago
17luobonj5ah02zvbvvjemxhr               	true 		981.7MB   	19 hours ago
...
9kdh9ldirubp6ulj6h5anjsrn*              	true 		8.192kB   	19 hours ago
Reclaimable:	14.79GB
Total:		14.79GB

# 删除 buildx 构建缓存
sudo docker buildx prune

也可以删除 buildx 实例

sudo docker buildx ls
NAME/NODE    DRIVER/ENDPOINT             STATUS  BUILDKIT PLATFORMS
multiarch *  docker-container
  multiarch0 unix:///var/run/docker.sock running v0.11.0  linux/arm64, linux/amd64, linux/amd64/v2, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
default      docker
  default    default                     running 20.10.22 linux/arm64, linux/arm/v7, linux/arm/v6, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386
  
# 停止 buildx 实例
sudo docker buildx stop multiarch

# 删除 buildx 实例
sudo docker buildx rm multiarch

如果构建 Dockerfile 中的基础镜像不支持某些特定的 CPU 架构、某些项目缺少特定的的链接库……等原因会导致镜像构建失败,这就不在本文讨论范畴之内了 😂。

参考信息


  1. 在 AMD64 架构计算机上构建支持 ARM 或其他架构的 Docker 镜像也一样 ↩︎

  2. 进入某个 screen 会话后,输入 exit 会直接退出并关闭这个会话 ↩︎

Dejavu Moe
作者
Dejavu Moe
Not for success, just for growing.