Docker镜像如何做到一次构建,到处

北京那所医院治疗白癜风最好 http://www.mvdtj.com/m/

在每个黑客的职业生涯中总有这么一个时刻需要为另一种CPU架构编译应用程序。这种场景可能出现在为树莓派项目编译应用程序,为嵌入式设备创建自定义镜像,或者让自己的软件支持不同平台。亦或是,我们只是想知道这个过程是怎么样的,或者好奇最终汇编代码和桌面电脑上无处不在的x86-64/amd64架构汇编有何区别。

不论是哪种原因,通常我们都需要整理好行装进行一段朝圣之旅。但是这个旅程不是登上孤独的山顶,而是通向地狱深渊,是一段从开发应用程序的阳光平原走向计算机体系结构的黑暗洞穴之旅:底层系统和嵌入式变化带来的难以捉摸的世界。介于这次跋涉的前景堪忧,大部分黑客最终通过Ctrl+Z结束了旅程,回到了地面,一边喘气一边警告同伴交叉编译、QEMU和chroot的恐怖之处。

好了,我可能有点夸张了。但是真相是为其他CPU架构构建应用程序没有那么直截了当。多亏了Docker19.03带来实验性的插件,让多架构构建比以往要方便很多。

为了理解Docker对多架构构建支持的重要性,首先我们需要了解如何为陌生架构构建应用程序。

背景:为陌生架构编译应用的方法

注:读者如果对本节概念已经了解,或者只是想知道如何构建镜像,可以跳过本节。

让我们快速了解下当前对于为陌生架构编译应用程序的方法。

方法1:直接在目标硬件上构建

如果我们可以访问目标架构硬件,同时操作系统上有我们所需的所有构建数据,那么就可以直接在硬件上编译应用程序。

例如,对我们特定场景下构建多架构Docker镜像,可以在树莓派上安装Docker运行时环境,然后和在开发机上一样,直接在上面通过应用程序的Dockerfile构建镜像。该方法是可行的,因为树莓派的官方操作系统Raspbian支持本地安装Docker。

但是,如果我们没法办法方便的访问目标硬件呢?我们可以在开发机器上直接构建非本地架构的应用程序吗?

方法2:模拟目标硬件

还记得和16位任天堂游戏机一起的快乐时光吗?当时我只是一个小孩子,但是当我长大一点之后,我发现对诸如《超级玛丽》和《时空之轮》等经典游戏非常怀念。不过我没有机会拥有一台超级任天堂游戏机,但是多亏了像ZSNES这样的模拟器,让我能回到过去,在32位个人电脑上体验这些经典游戏带来的乐趣。

通过模拟器,我们不仅能够玩电子游戏,还能够构建非本地二进制文件。当然这里不是使用ZSNES,而是使用更加强大更灵活的模拟器:QEMU。QEMU是一个自由且开源的模拟器,支持许多通用架构,包括:ARM、Power-PC和RISC-V。通过运行一个全功能模拟器,我们可以启动一个可以运行Linux操作系统的通用ARM虚拟机,然后在虚拟机中设置开发环境,编译应用程序。

但是,如果仔细思考下,一个全功能虚拟机有一些浪费资源。在该模式下,QEMU会模拟整个系统,包括诸如定时器、内存控制器、SPI和I2C总线控制器等硬件。但是大部分情况下,我们编译应用程序不会关心以上所提到的硬件特性。还能更好么?

方法3:通过binfmt_misc模拟目标架构的用户空间

在Linux系统上,QEMU有另外一种操作模式,可以通过用户模式模拟器来运行非本地架构的二进制程序。该模式下,QEMU会跳过方法2中描述的对整个目标系统硬件的模拟,取而代之的是通过binfmt_misc在Linux内核注册一个二进制格式处理程序,将陌生二进制代码拦截并转换后再执行,同时将系统调用按需从目标系统转换成当前系统。最终对于用户来说,他们会发现可以在本机运行这些异构二进制程序。

通过用户态模拟器和QEMU,我们可以通过轻量级虚拟化(chroot或者容器)来安装其他Linux发行版,并像在本地一样编译我们需要的异构二进制程序。

下面我们会看到这将会是构建多架构Docker镜像的可选方式。

方法4:使用交叉编译器

最后,我们还有一种在嵌入式系统社区标准的做法:交叉编译。

交叉编译器是一个特殊的编译器,它运行在主机架构上,但是可以为不同的目标架构生成的二进制程序。例如,我们可以有一个amd64架构的C++交叉编译器,目标架构是一个aarch64(64位ARM)的嵌入式设备(例如一个智能手机或者其他东西)。基于这种方式的一个现实中的例子是,世界上数十亿安卓设备都使用这种方式来构建软件。

从性能上考虑,这种方式有和直接在目标硬件上构建(方法1)相同的效率,因为它没有运行在模拟器上。但是交叉编译的变数取决于使用的编程语言,如果是Go语言就非常方便。

搞糊涂了吗?对于Docker镜像来说会更复杂……

注意前面提到的所有编译方式都只是生成单一的应用程序二进制文件。对于现代容器来说,当我们引入Docker镜像的时候,不仅仅是关于构建单独的二进制文件,而是构建一整个异构容器镜像!这比之前说的要更加麻烦。

如果所有这些听上去很痛苦,不要难过,因为构建非本地平台二进制程序本来就很痛苦。在此之上增加Docker带来的复杂度,看起来应该留给专家来处理。

感谢最新版本Docker运行时环境带来的实验性扩展,构建多架构镜像现在比以前方便多了。

构建多架构Docker镜像

为了能够更方便的构建多架构Docker镜像,我们可以使用最近发布的Docker扩展:buildx。buildx是下一代标准dockerbuild命令的前端,既我们熟悉的用于构建Docker镜像的命令。通过借助BuildKit的所有功能,buildx扩展了表中dockerbuild命令的功能,成为Docker构建系统的新后端。

让我们花几分钟看下如何使用buildx来构建多架构镜像。

步骤1:开启buildx

要使用buildx,首先要确认我们的Docker运行时环境已经是最新版本19.03。新版本中,buildx事实上已经默认和Docker捆绑在一起,但是需要通过设置环境变量DOCKER_CLI_EXPERIMENTAL来开启。让我们在当前命令行会话中开启:

exportDOCKER_CLI_EXPERIMENTAL=enabled

通过检查版本来验证目前我们已经可以使用buildx:

dockerbuildxversiongithub.


转载请注明:http://www.aierlanlan.com/rzgz/7544.html

  • 上一篇文章:
  •   
  • 下一篇文章: