斯科特·罗西洛

斯科特·罗西洛

Inception 团队软件工程师

AWS 最近宣布了其新一代 Amazon EC2 M6g 实例的预览版,该实例搭载基于 64 位 ARM 的 AWS Graviton2 处理器。 与最新一代 AWS x86-64 实例相比,其预计的性能和价格优势令人印象深刻,不容忽视。

虽然我们可以简单地使用 ARM 上的标准 Docker 来为这些新的 AWS Graviton 处理器构建映像,但支持这两种架构而不是放弃 x86-64 架构有很多好处:

  1. 开发人员需要能够在本地运行其 CI/CD 生成的 Docker 镜像。 在可预见的未来,开发人员的机器将继续使用 x86–64 CPU。
  2. 在 x86–64 和 Graviton2 集群之间共享通用容器。
  3. 在 ARM 上运行暂存环境并在 x86–64 上运行生产环境,直到 Graviton2 结束预览。
  4. 一旦 Graviton2s 普遍可用,如果服务迁移到 ARM 导致任何问题,请快速切换回 x86–64。

构建多架构 Docker 镜像仍是一个实验性功能。 然而,托管多架构镜像已经得到了 Docker Registry 的良好支持,包括自托管和 hub.docker.com 上的镜像。 您的里程可能会因第三方 Docker 注册表实现而异

在本文中,我们将演示如何在 ARM Linux 主机上为 x86–64(AMD64)和 ARM64 构建和发布多架构 Docker 镜像,以便您可以在任一架构上从镜像运行 Docker 容器。

注意:如果您可以在 macOS 或 Windows 桌面上构建映像,则 Docker Desktop 开箱即用,支持构建多架构 Docker 映像。 但是,如果您运行 Linux,或者想要正确构建 Docker 镜像作为 CI/CD 管道的一部分,请继续阅读。

安装 Docker 19.03 或更高版本

首先,我们需要一个能够运行 Docker 19.03 或更高版本的 ARM64 Linux 主机。 您也可以使用 x86–64 主机。

但是,由于我们希望从 ARM 的成本节省中获益,因此我们将使用 Ubuntu 19.10 作为我们的构建服务器。 Ubuntu 是一个流行的 Linux 发行版,受到多种云服务的支持,但是其他较新的发行版也应该可以正常运行。 但是,您需要确保您运行的是 Linux 内核 5.x 或更高版本。 在 AWS 上,您可以使用 Ubuntu 19.10 AMI。

在 Ubuntu 上,安装docker.io作为 Ubuntu 的存储库。 我们还安装了binfmt-supportqemnu-user-static 。 QEMU 使单个主机能够为多种架构构建映像,而binfmt-support为 Linux 内核添加了多种二进制格式支持。 请注意binfmt-support版本 2.1.43 或更高版本是必需的。

将您的用户添加到 Docker 组以便从您的用户帐户运行命令。 请记住在运行后重新启动或注销并重新登录:

1. #!/bin/bash #安装Docker 和多架构依赖项
2.
 3. sudo apt-get install binfmt-support qemu-user-static
 4. sudo apt-get 安装 docker.io
 5. sudo usermod -aG docker $USERp
 6. sudo 重启

安装 Docker Buildx

接下来,我们需要安装Docker的buildx命令。 Buildx 处于技术预览阶段,并提供多架构构建等实验性构建功能。 如果您允许以您的用户身份运行 docker,您可以以普通用户身份(而不是 root 用户)安装它。

为 Docker 安装buildx命令行插件。 以下代码将安装 ARM 64 位的最新版本。

/bin/bash 复制代码
2.#安装 buildx for arm64 并启用 Docker CLI 插件
3.
 4. sudo apt-get 安装 jq
 5. mkdir -p ~/.docker/cli-plugins
 6. BUILDX_URL=$(curl https://api.github.com/repos/docker/buildx
/发布/最新|jq -r.assets[].browser_download_url | grep arm64
 7. wget $BUILDX_URL -O ~/.docker/cli-plugins/docker-build
 8. chmod + x ~/.docker/cli-plugins/docker-buildx

构建多架构图像

multi-architecture-images构建多架构镜像(Docker 的文档将其称为多平台镜像)需要由docker-container驱动程序支持的构建器,并支持两种构建跨平台镜像的策略:

  1. 在内核中使用 QEMU 仿真支持
  2. 由单个构建器协调在多个本机节点上构建

这里我们使用 QEMU 方法,因为它是两种选项中更便宜的一种,因为它只需要一个适用于所有目标架构的构建主机。 此外,Docker 在这里没有使用 QEMU 来创建功能齐全的虚拟机。 我们使用 QEMU 用户模式,因此只需要模拟系统调用。

随着您的 CI/CD 需求不断发展,您可能希望投资本机节点构建场以加快构建过程。

让我们创建一个引导构建器,你可以给它起任何你喜欢的名字:

1. $ docker buildx create --name mbuilder
 2. mbuilder
 3.
 4. $ docker buildx 使用 mbuilder
 5.
 6. $ docker buildx inspect --bootstrap
 7.名称:mbuilder
 8. 驱动:docker-container
 9.
 10. 节点:
 11. 名称:mbuilder0
 12.端点:unix:///var/run/docker.sock
 13. 状态:正在运行
14. 平台:linux/arm64、linux/amd64、linux/riscv64、linux/ppc64le、
 Linux/s390x、Linux/386、Linux/arm/v7、Linux/arm/v6

完美,我们现在有一个能够针对 linux/arm64 linux/amd64 和其他架构的构建器!

现在让我们从一个简单的 Dockerfile 构建一个可以在 Linux amd64 和 arm64 上运行的映像

请注意,您提取的图像也必须支持您计划针对的架构。 可以使用以下方法检查:

$ docker buildx imagetools 检查 alpine

Dockerfile:

来自阿尔卑斯山
运行 apk 添加 util-linux
 CMD [“lscpu”]

 $ docker buildx build --platform linux/amd64,linux/arm64 -t foo4u/demo-mutliarch:2 --push 。
[+] 建造 4.7s (9/9) 已完工
=> [内部] 从 Dockerfile 加载构建定义
=> => 正在传输 dockerfile:31B
 => [内部] 加载 .dockerignore
 => => 传输上下文:2B
 => [linux/amd64 internal] 为 docker.io/library/alpine:latest 加载元数据
 => [linux/arm64 internal] 为 docker.io/library/alpine:latest 加载元数据
 => [linux/amd64 1/2] 来自 docker.io/library/alpine@sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78
 => => 解析docker.io/library/alpine@sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78
 => 缓存 [linux/amd64 2/2] 运行 apk 添加 util-linux
 => [linux/arm64 1/2] 来自 docker.io/library/alpine@sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78
 => => 解析docker.io/library/alpine@sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78
 => 缓存 [linux/arm64 2/2] 运行 apk 添加 util-linux
 => 导出至图像
=> => 导出图层
=> => 导出清单 sha256:cb54200a7c04dded134ca9e3e6a0e434c2fdf851fb3a7226941d0983ad5bfb88
 => => 导出配置 sha256:307b885367f8ef4dc443dc35d6ed3298b9a3a48a846cf559a676c028a359731b
 => => 导出清单 sha256:6f4fe17def66ef5bc79279448e1cb77a1642d460ed58d5dc60d0e472c023e2eb
 => => 导出配置 sha256:26e6b092c7c1efffe51ce1d5f68e3359ab44152d33df39e5b85cd4ff6cfed3d4
 => => 导出清单列表 sha256:3b4e4135b92017e5214421543b813e83a77fcea759af8067c685b70a5d978497
 => => 推动层
=> => 推送 docker.io/foo4u/demo-mutliarch:2 的清单

这里有很多事情要做,让我们来分析一下:
 1. Docker 将构建上下文传输到我们的构建器容器
2.构建器使用 --platform 参数为我们请求的每种架构构建一个映像
3. 镜像被推送到 Docker Hub
 4. Buildx 生成清单 JSON 文件并将其作为镜像标签推送到 Docker Hub。

让我们使用imagetools检查生成的 Docker 镜像

1. $ docker buildx imagetools 检查 foo4u/demo-mutliarch:2
 2.名称:docker.io/foo4u/demo-mutliarch:2
3.媒体类型:application/vnd.docker.distribution.manifest.list.v2+json
 4.摘要:sha256:3b4e4135b92017e5214421543b813e83a77fcea759af8067c685b70a5d978497
 5.
 6.清单:
 7.名称:docker.io/foo4u/demo-mutliarch:2@sha256:cb54200a7c04dded134ca9e3e6a0e434c2fdf851fb3a7226941d0983ad5bfb88
8. 媒体类型:application/vnd.docker.distribution.manifest.v2+json
9.平台:linux/amd64
 10.
 11. 名称:docker.io/foo4u/demo-12。 多体系结构:2@sha256:6f4fe17def66ef5bc79279448e1cb77a1642d460ed58d5dc60d0e472c023e2eb
 12. 媒体类型:application/vnd.docker.distribution.manifest.v2+json
13. 平台:linux/arm64

在这里我们可以看到foo4u/demo-multiarch:2是一个 JSON 清单,指向我们在构建期间针对的每个平台的清单。 尽管该图像在注册表中作为单个图像出现,但它实际上是包含指向平台特定图像的链接的清单。 Buildx 为每个架构构建并发布了一个图像,然后生成了一个将它们链接在一起的清单。

Docker 在拉取镜像时使用此信息来下载适合机器运行时架构的镜像。

让我们在 x86–64 / amd64 上运行该映像:

$ docker run --rm foo4u/demo-mutliarch:2
无法在本地找到图像“foo4u/demo-mutliarch:2”
 2:从 foo4u/demo-mutliarch 拉取
e6b0cf9c0882:已存在
状态:已为 foo4u/demo-mutliarch:2 下载较新的图像
架构:x86_64

现在让我们在 arm64 上运行该图像:

$ docker run --rm foo4u/demo-mutliarch:2
无法在本地找到图像“foo4u/demo-mutliarch:2”
 2:从 foo4u/demo-mutliarch 拉取
状态:已为 foo4u/demo-mutliarch:2 下载较新的图像
架构:aarch64

就是这样! 现在我们有一个功能齐全的 Docker 映像,可以在我们现有的 x86-64 服务器或全新的 ARM 64 服务器上运行!

总之,在 Linux 上开始使用多架构 Docker 镜像并不是那么难。 我们甚至可以使用 ARM 服务器来构建图像,从而有可能节省我们的 CI/CD 服务器以及暂存和生产基础设施的成本。

额外好处:如果您使用的语言具有良好的多架构支持(例如 Java 或 Go),您可以进一步优化您的 Docker 构建。 例如,你可以构建一个具有单一平台编译的 Spring Boot 应用程序

1. FROM --platform=$BUILDPLATFORM amazoncorretto:11 作为构建者
2.
 3. 复制。 /srv/
 4. WORKDIR /srv
 5. 运行 ./mvnw -DskipTests = true 包 spring-boot:重新打包
6.
 7. 来自 amazoncorretto:11
 8.
 9. 复制 --from=builder /srv/target/my-service-0.0.1-SNAPSHOT.jar /srv/
 10.
 11. 曝光 8080
 12.
 13. 入口点 ["java", "-jar", "/srv/my-service-0.0.1-SNAPSHOT.jar"]

标签: API 云翻译 集成

立即体验更智能的翻译

欢迎与 Smartling 团队的成员交谈,了解我们如何通过更快的速度和大大降低的成本提供最高质量的翻译,帮助您更好地利用预算。
Cta-Card-Side-Image