高品质的音视频能力是怎样的? | Qcon 全球软件开发大会·上海站邀请函 了解详情
写点什么

多平台 Docker 镜像构建教程

  • 2020-04-09
  • 本文字数:2690 字

    阅读完需:约 9 分钟

多平台Docker镜像构建教程


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


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


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


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


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


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


仿真

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


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


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


docker run --privileged --rm docker/binfmt:a7996909642ee92942dcd6cff44b9b95f08dad64
复制代码


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


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


{    ...     "experimental": “enabled”}
复制代码


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


$ docker buildx lsNAME/NODE     DRIVER/ENDPOINT             STATUS   PLATFORMSdefault       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:busterCMD uname -m
复制代码


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


$ docker buildx build -t local-build .$ docker run --rm local-buildx86_64
复制代码


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


$ docker buildx build --platform linux/arm/v7 -t arm-build .$ docker run --rm arm-buildarmv7l
复制代码


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


交叉编译

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


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 
复制代码


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


清单列表

在上面关于仿真的建议中,你可能已经注意到:我们使用--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:armv7Created manifest list docker.io/amouat/arch-test:blog$ docker manifest push amouat/arch-test:blogsha256:039dd768fc0758fbe82e3296d40b45f71fd69768f21bb9e0da02d0fb28c67648
复制代码


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


$ docker run amouat/arch-test:blogUnable to find image 'amouat/arch-test:blog' locallyblog: Pulling from amouat/arch-testDigest: sha256:039dd768fc0758fbe82e3296d40b45f71fd69768f21bb9e0da02d0fb28c67648Status: Downloaded newer image for amouat/arch-test:blogx86_64
复制代码


有树莓派的读者可以试着运行这个镜像,并确认它确实能在那个平台上工作!


回顾一下:并不是 Docker 镜像的所有用户都运行 amd64。使用 buildx 和 QEMU,只需额外少量工作就可以为这些用户提供支持。


英文原文:


Multi-Platform Docker Builds


2020-04-09 14:2712629
用户头像

发布了 534 篇内容, 共 243.5 次阅读, 收获喜欢 1278 次。

关注

评论

发布
暂无评论
发现更多内容

百度智能云发布云智一体的AI开发全栈模式

百度大脑

百度智能云

2021年Android面经分享,赶紧收藏!

欢喜学安卓

android 程序员 面试 移动开发

程序员面试指北:如何更高效的准备面试

邴越

Java 面试 求职 招聘

Hexo + Material + Github 搭建博客

U+2647

博客 4月日更

Spark查询优化之谓词下推

小舰

4月日更

清明节特辑 |记忆存储、声音还原、性格模仿……AI可以让人类永生吗?

华为云开发者联盟

AI 语音合成 清明节 对话机器人 VR/AR

在npm发布自己的组件

空城机

JavaScript 大前端 npm 4月日更 自定义组件

Netty HashedWheelTimer 时间轮源码详解

Yano

Java 架构 Netty

Kubernetes 稳定性保障手册 -- 可观测性专题

阿里巴巴云原生

Serverless 容器 云原生 k8s 存储

NAC公链主打应用而生的NA(Nirvana)公链有什么过人之处?

区块链第一资讯

自己搭建一个语音聊天室

anyRTC开发者

ios android 音视频 WebRTC RTC

MySql数据库列表数据分页查询、全文检索API零代码实现

crudapi

全文检索 API crud crudapi 列表查询

定义边缘计算架构需考虑的三个方面

浪潮云

边缘计算

飞桨与龙芯完成兼容性认证

百度大脑

飞桨

Python OpenCV 之图像乘除与像素的逻辑运算,图像处理取经之旅第 17 天

梦想橡皮擦

Python OpenCV 4月日更

OpenTelemetry 简析

阿里巴巴云原生

容器 开发者 云原生 k8s 监控

uni-app对接金山文档在线预览服务

薛定喵君

ElasticSearch读写模型&数据复制模型

yhh

elasticsearch 数据复制模型

CMS前世今生

叫练

CMS JVM 垃圾收集

今天是个开心的日子

return

Hi Array!~~~你所经常遇见的TA!

Chalk

JavaScript 大前端 数组 array 4月日更

Rust从0到1-所有权-引用和借用

rust 引用 所有权 借用

【leetcode题目】2. 两数相加

程序员架构进阶

LeetCode 28天写作 算法解析 4月日更

2021年Android工作或更难找,原理+实战+视频+源码

欢喜学安卓

android 程序员 面试 移动开发

树莓派与边缘计算

IT蜗壳-Tango

树莓派 IT蜗壳 4月日更 OpenVINO

搭建Gogs服务器

尧二水丶

git flow 4月日更

Python基础之:Python中的类

程序那些事

Python Python3 程序那些事

【LeetCode】直方图的水量Java题解

Albert

算法 LeetCode 4月日更

实时数据仓库的发展、架构和趋势

网易数帆

数据仓库 实时计算 实时数仓 iceberg 批流一体

如何实现微信8.0爆炸和烟花表情特效

梅芳姑

短视频编辑:基于ExoPlayer可实时交互的播放器

梅芳姑

多平台Docker镜像构建教程_容器_Adrian Mouat_InfoQ精选文章