多平台Docker镜像构建教程

简介: Adrian Mouat被誉为Docker Captain,他是Container Solutions 公司的首席科学家。目前,他正开发 Trow,这是一个容器镜像注册中心,用于安全管理 Kubernetes 集群中的镜像流。

云栖号资讯:【点击查看更多行业资讯
在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来!

22CA1FAD_6919_451d_B8DF_7E925147EA9D

Adrian Mouat被誉为Docker Captain,他是Container Solutions 公司的首席科学家。目前,他正开发 Trow,这是一个容器镜像注册中心,用于安全管理 Kubernetes 集群中的镜像流。

当前,Docker 镜像已经成为测试和部署新的第三方软件的标准工具。Adrian 是开源 Trow 注册中心的主要开发者,而Docker 镜像则是人们安装该工具的主要方式。如果他不提供镜像,其他人最终也会推出他们自己的镜像,这样会导致重复"造轮子”,并产生维护问题。

默认情况下,我们创建的Docker 镜像运行在 linux/amd64 平台上。它适用于大多数的开发机器和云提供商,但却忽略其他平台的用户。这个群体很庞大——想想基于树莓派的家庭实验室、生产物联网设备的公司、运行在 IBM 大型机上的组织以及使用低功耗 arm64 芯片的云。

一般来说,这些平台的用户通常会构建自己的镜像或寻找其他解决方案。

那么,你该如何为这些平台构建镜像?最明显的方法是在目标平台上构建镜像。这适用于很多情况。但是如果你的目标是 s390x,我希望你有可以使用的 IBM 大型机。更常见的平台,比如树莓派、物联网设备通常电量有限,速度慢或无法构建镜像。

我们该怎么做?有两个选项:1. 目标平台仿真,2. 交叉编译。有趣的是,我发现有种方法可以将这两个选项结合的效果最好。

1.仿真

让我们从第一个选项——仿真开始。有一个很不错的项目叫 QEMU,它可以模拟很多平台。随着最近 buildx 的预览,将 QEMU 用于 Docker 变得更加容易。

https://www.qemu.org/

https://github.com/docker/buildx

QEMU 集成依赖于一个 Linux 内核特性,该特性有个稍显神秘的名字 binfmt_misc handler。当 Linux 遇到其无法识别的可执行文件格式(例如,一个用于不同体系结构的文件格式)时,它将使用该处理程序检查是否配置了什么“用户空间应用程序”来处理该格式(例如,模拟器或 VM)。如果有,它将把可执行文件传递给该应用程序。

为实现这一点,我们需要在内核中注册我们关注的平台。如果你正在使用 Docker Desktop,那么对于大多数常见平台,你就无需做这项工作。如果你正使用 Linux,你可以通过运行最新的docker/binfmt镜像,以与 Docker Desktop 相同的方式注册处理程序,例如:

docker run --privileged --rm docker/binfmt:a7996909642ee92942dcd6cff44b9b95f08dad64

完成此操作后,你可能需要重启 Docker。如果你想要对自己想注册的平台有更多控制或想使用更高深莫测的平台(例如 PowerPC),请查看 qus 项目。

https://github.com/dbhi/qus

Buildx 有两种不同的用法,但最简单的方法可能是在 Docker CLI 上启用实验性特性(如果你还没有这样做的话),编辑~/.docker/config.json文件,使其包含以下内容:

{
    ...
     "experimental": “enabled”
}

你现在应该能运行docker buildx ls,并得到类似以下的输出:

$ docker buildx ls
NAME/NODE     DRIVER/ENDPOINT             STATUS   PLATFORMS
default       docker                               
  default     default                     running  linux/amd64, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6

让我们为另一个平台构建一个镜像,从 Dockerfile 开始:

FROM debian:buster
CMD uname -m

如果我们正常构建,运行以下命令:

$ docker buildx build -t local-build .
…
$ docker run --rm local-build
x86_64

但是,如果我们显式指定构建针对的平台,则执行以下命令:

$ docker buildx build --platform linux/arm/v7 -t arm-build .
…
$ docker run --rm arm-build
armv7l

成功!我们已经成功地在 x86_64 笔记本上构建和运行了 armv7 镜像,并且只做了很少工作。这种技术很有效,但对于更复杂的构建,你可能会发现它运行太慢,或者遇到 QEMU 中的 Bug。在这些情况下,有必要研究一下是否可以交叉编译你的镜像。

2.交叉编译

一些编译器能为 foreign platforms 生成二进制代码,最著名的包括 Go 和 Rust。通过 Trow 注册中心项目,我们发现,交叉编译是为其他平台创建镜像最快、最可靠的方法。例如,这里是 Trow armv7 镜像的 Dockerfile。

https://github.com/ContainerSolutions/trow/blob/master/docker/Dockerfile.armv7

最重要的一行是:

RUN cargo build --target armv7-unknown-linux-gnueabihf -Z unstable-options --out-dir ./out

它明确告诉 Rust,我们希望二进制文件在哪个平台上运行。然后,我们可以使用多级构建将这个二进制文件复制到目标体系结构的基本镜像中(如果是静态编译,也能使用 scratch),这样就完成了。然而,对于 Trow 注册中心,我想在最终的镜像中设置更多东西,所以最后阶段实际上开始于:

FROM --platform=linux/arm/v7 debian:stable-slim

因此,我实际上混合使用了仿真和交叉编译——交叉编译用来创建二进制文件,仿真用来运行和配置最终的镜像。

3.清单列表

在上面关于仿真的建议中,你可能已经注意到:我们使用--platform参数来设置构建平台,但是我们在 FROM 行中将镜像指定为 debian:buster。这看起来似乎没有意义——平台当然依赖于基本镜像以及它是如何构建的,而不是用户之后的决定。

这样做是因为 Docker 使用了一种叫做清单列表的东西。对于给定镜像,这些列表包含指向不同体系结构镜像的指针。因为官方的 debian 镜像有一个定义好的清单列表,当我在笔记本上拉取这个镜像时,我会自动获得 amd64 镜像,当我在树莓派上拉取它时,我将得到 armv7 镜像。

为了让用户满意,我们可以为自己的镜像创建清单。如果我们回到前面的例子,首先我们需要重新构建并将镜像推送到一个镜像库:

$ docker buildx build --platform linux/arm/v7 -t amouat/arch-test:armv7 .
…
$ docker push amouat/arch-test:armv7
…
$ docker buildx build -t amouat/arch-test:amd64 .
…
$ docker push amouat/arch-test:amd64

接下来,我们创建一个清单列表指向这两个单独的镜像,并推送它们:

$ docker manifest create amouat/arch-test:blog amouat/arch-test:amd64 amouat/arch-test:armv7
Created manifest list docker.io/amouat/arch-test:blog
$ docker manifest push amouat/arch-test:blog
sha256:039dd768fc0758fbe82e3296d40b45f71fd69768f21bb9e0da02d0fb28c67648

现在,Docker 将拉取并运行适合当前平台的镜像:

$ docker run amouat/arch-test:blog
Unable to find image 'amouat/arch-test:blog' locally
blog: Pulling from amouat/arch-test
Digest: sha256:039dd768fc0758fbe82e3296d40b45f71fd69768f21bb9e0da02d0fb28c67648
Status: Downloaded newer image for amouat/arch-test:blog
x86_64

有树莓派的读者可以试着运行这个镜像,并确认它确实能在那个平台上工作!回顾一下:并不是 Docker 镜像的所有用户都运行 amd64。使用 buildx 和 QEMU,只需额外少量工作就可以为这些用户提供支持。

【云栖号在线课堂】每天都有产品技术专家分享!
课程地址:https://yqh.aliyun.com/live

立即加入社群,与专家面对面,及时了解课程最新动态!
【云栖号在线课堂 社群】https://c.tb.cn/F3.Z8gvnK

原文发布时间:2020-04-14
本文作者:Adrian Mouat
本文来自:“InfoQ 微信公众号”,了解相关信息可以关注“InfoQ

相关文章
|
2月前
|
Java Linux C语言
《docker基础篇:2.Docker安装》包括前提说明、Docker的基本组成、Docker平台架构图解(架构版)、安装步骤、阿里云镜像加速、永远的HelloWorld、底层原理
《docker基础篇:2.Docker安装》包括前提说明、Docker的基本组成、Docker平台架构图解(架构版)、安装步骤、阿里云镜像加速、永远的HelloWorld、底层原理
496 90
|
4天前
|
存储 虚拟化 Docker
Docker Desktop 4.38 安装与配置全流程指南(Windows平台)
Docker Desktop 是容器化应用开发与部署的一体化工具,支持本地创建、管理和运行 Docker 容器。4.38 版本新增 GPU 加速、WSL 2 性能优化和 Kubernetes 1.28 集群管理功能,适用于微服务开发和 CI/CD 流水线搭建。安装要求为 Windows 10 2004 及以上(64 位),需启用 Hyper-V 或 WSL 2。硬件最低配置为 4GB 内存、20GB 存储和虚拟化技术支持的 CPU。安装步骤包括启用系统功能、下载并运行安装程序,完成后配置镜像加速并验证功能。常见问题涵盖 WSL 2 安装不完整、磁盘空间清理及容器外网访问等。
564 11
|
2月前
|
弹性计算 Ubuntu Linux
阿里云服务器一键安装Docker社区版教程,基于系统运维管理OOS
阿里云服务器一键安装Docker社区版教程,基于系统运维管理OOS自动化部署。支持Ubuntu 22.04/20.04、CentOS 7.7-7.9及Alibaba Cloud Linux 3.2104 LTS。前提条件:ECS实例需运行中且有公网。步骤:选择Docker扩展并安装,验证成功通过命令`docker -v`查看版本号。
342 79
|
10天前
|
存储 运维 应用服务中间件
Docker Image即Docker镜像
Docker 镜像是 Docker 容器的基础,包含了运行应用程序所需的一切。通过 Dockerfile 可以方便地创建自定义镜像,并且利用 Docker 提供的命令可以轻松管理和使用这些镜像。掌握 Docker 镜像的创建、管理和使用,是进行容器化应用开发和部署的基础技能。希望本文能帮助读者更好地理解 Docker 镜像的概念和操作,提高开发和运维效率。
67 13
|
23天前
|
消息中间件 Kafka 流计算
docker环境安装kafka/Flink/clickhouse镜像
通过上述步骤和示例,您可以系统地了解如何使用Docker Compose安装和配置Kafka、Flink和ClickHouse,并进行基本的验证操作。希望这些内容对您的学习和工作有所帮助。
140 28
|
2月前
|
Ubuntu NoSQL 开发工具
《docker基础篇:4.Docker镜像》包括是什么、分层的镜像、UnionFS(联合文件系统)、docker镜像的加载原理、为什么docker镜像要采用这种分层结构呢、docker镜像commit
《docker基础篇:4.Docker镜像》包括是什么、分层的镜像、UnionFS(联合文件系统)、docker镜像的加载原理、为什么docker镜像要采用这种分层结构呢、docker镜像commit
247 70
|
10天前
|
JavaScript Shell C#
多种脚本批量下载 Docker 镜像:Shell、PowerShell、Node.js 和 C#
本项目提供多种脚本(Shell、PowerShell、Node.js 和 C#)用于批量下载 Docker 镜像。配置文件 `docker-images.txt` 列出需要下载的镜像及其标签。各脚本首先检查 Docker 是否安装,接着读取配置文件并逐行处理,跳过空行和注释行,提取镜像名称和标签,调用 `docker pull` 命令下载镜像,并输出下载结果。使用时需创建配置文件并运行相应脚本。C# 版本需安装 .NET 8 runtime。
77 1
|
26天前
|
监控 Linux PHP
【02】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-2月12日优雅草简化Centos stream8安装zabbix7教程-本搭建教程非docker搭建教程-优雅草solution
【02】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-2月12日优雅草简化Centos stream8安装zabbix7教程-本搭建教程非docker搭建教程-优雅草solution
75 20
|
3月前
|
NoSQL Java Linux
《docker高级篇(大厂进阶):2.DockerFile解析》包括:是什么、DockerFile构建过程解析、DockerFile常用保留字指令、案例、小总结
《docker高级篇(大厂进阶):2.DockerFile解析》包括:是什么、DockerFile构建过程解析、DockerFile常用保留字指令、案例、小总结
303 76
|
3月前
|
NoSQL 关系型数据库 MySQL
《docker高级篇(大厂进阶):4.Docker网络》包括:是什么、常用基本命令、能干嘛、网络模式、docker平台架构图解
《docker高级篇(大厂进阶):4.Docker网络》包括:是什么、常用基本命令、能干嘛、网络模式、docker平台架构图解
214 56
《docker高级篇(大厂进阶):4.Docker网络》包括:是什么、常用基本命令、能干嘛、网络模式、docker平台架构图解