使用BuildKit构建容器镜像


在本系列有关容器镜像构建的最后一篇文章中,我们回到Docker的Moby项目,该项目有个名为BuildKit的子项目。

BuildKit是源自Docker的Moby项目的第二代镜像构建工具,自Docker CE 18.09起可用。正如我们在之前的文章中使用Img所看到的那样,BuildKit不限于仅与Docker一起使用。这是一种通用的镜像构建工具,可以作为独立的二进制文件(以守护程序或无守护程序模式使用)也可以作为库来使用。实际上,它可以将构建步骤转换成其低级构建器(LLB)表示形式,BuildKit可用于构建任何工件(artifact)而不仅仅是容器镜像。我们主要在这里关注容器镜像的构建,因此让我们来看看BuildKit能给我们带来些什么。

构建步骤优化

Docker本身提供的构建经常会让人感到沮丧的一个原因是Dockerfile指令执行构建步骤的顺序性。引入多阶段构建之后,便可以将同一Dockerfile中的构建步骤按逻辑分组进行。

有时,这些构建彼此完全独立,这意味着它们可以并行执行-或根本不需要执行。不幸的是,传统的Docker镜像构建无法满足这种灵活性,有时会在不需要时执行构建步骤。这意味着构建时间通常会更长。

相反,BuildKit会创建一个构建步骤之间的依赖关系图,并使用它来决定构建中的哪些步骤省略,哪些可以并行执行;哪些需要顺序执行。这提供了更有效的构建执过程,这对于迭代其应用程序进行镜像构建的开发人员来说是有价值的。

高效灵活的缓存

尽管在旧版Docker镜像构建中对构建步骤进行缓存非常有用,但效率却不如预期。通过对构建后端的重写,BuildKit进行了改进,并提供了更快,更准确的缓存机制。它使用为镜像构建生成的依赖关系图,并且基于指令定义和构建步骤内容。

BuildKit提供的另一个巨大优势来自构建缓存导入和导出的形式。正如Kaniko和Makisu允许将构建缓存推送到远程镜像仓库一样,BuildKit也是如此。但是,BuildKit使你可以灵活地将缓存嵌入到镜像中(内联)并将它们一起推送(尽管并非每个镜像仓库都支持),或者可以将它们单独推送。缓存也可以导出到本地目录以供以后使用。

当从零开始建立构建环境而没有先前的构建历史可受益时,导入构建缓存的功能将发挥作用。导入可以让缓存“热身”,这对于临时CI/CD环境特别有用。

Build Artifacts

使用旧版Docker构建器构建时,将生成的镜像添加到Docker守护程序管理的本地镜像缓存中。需要单独的docker push将镜像上载到远程镜像仓库。新型镜像构建工具允许你在构建调用时指定镜像推送,从而增强了体验。 BuildKit也不例外,它还允许以几种不同格式输出镜像。本地目录中的文件,本地tarball,本地OCI镜像tarball,Docker镜像tarball,存储在本地缓存中的Docker镜像以及推送到镜像仓库的Docker镜像。格式很多!

扩展语法

对于Docker构建体验而言,往复出现的众多功能性请求之一就是安全的处理镜像构建过程。 Moby项目多年来一直抵制此呼吁。但是,借助BuildKit灵活的“前端”定义,实验性的扩展了Dockerfile语法。扩展语法为RUN Dockerfile指令提供了新的功能,其中包括安全功能。
RUN --mount=type=secret,id=top-secret-passwd my_command

引用实验性前端的Dockerfile可以临时为RUN指令添加secret参数。secret使用docker build的--secret标志实现。同样,使用SSH挂载可启用SSH代理连接的转发,以进行安全的SSH身份验证。

能够以这种方式扩展Dockerfile的语法是BuildKit独有的功能。

Consuming BuildKit

BuildKit具有许多其他功能,这些功能大大改善了构建容器镜像的技术。如果它是适用于许多不同环境的通用工具,那么如何使用它呢?

根据工作环境的不同,这个问题的答案也有所不同。我们来看一下。

Docker

鉴于BuildKit是Moby项目,因此可以将它用作Docker(v18.09 +)的首选构建后端不足为奇了。但它不是默认的后端,因为Windows平台不支持它,而在Linux上构建镜像时很方便使用。

只需设置环境变量(DOCKER_BUILDKIT = 1)即可完成此工作,或将以下键/值对添加到守护程序的配置文件中以永久使用; “features”:{“ buildkit”:true}。

由于Docker守护进程中的某些限制,Docker并未充分发挥BuildKit的全部功能。因此,对Docker客户端CLI进行了扩展以提供插件框架,该框架允许使用插件来扩展可用的CLI功能。一个名为Buildx的实验性插件会绕过守护程序中的旧版构建函数,它使用BuildKit后端进行所有构建。该工具提供了所有熟悉的镜像构建命令和功能,但通过一些特定于BuildKit的附加功能对其进行了扩充。

BuildKit(通过Buildx扩展)支持多个构建器实例。这是一项重要功能,其他镜像构建工具中没有类似功能。它实际上意味着可以出于构建目的共享一组构建器实例。也可能为一个项目分配了一组构建器实例,而另一个项目则分配了另一组。
$ docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS  PLATFORMS
default * docker                  
default default         running linux/amd64, linux/386

默认情况下,Buildx插件以Docker驱动程序为目标,该驱动程序使用Docker守护程序提供的BuildKit库,但存在其固有的局限性。另一个驱动程序是docker-container,它透明地在容器内启动BuildKit来执行构建。它可以提供BuildKit全部功能。第三个用于Kubernetes的驱动程序可以让BuildKit实例以Pod的方式在Kubernetes中运行。这特别有趣,因为它可以启动在Kubernetes中运行的BuildKit的构建——全部来自Docker CLI。这是否是理想的工作流程,这完全取决于个人或公司的选择。

Kubernetes

组织越来越多地在临时基础结构之上实现其应用程序工作流,其中包括Kubernetes,通常会在CI/CD工作流程中看到在容器中生成容器镜像。在Kubernetes中运行BuildKit实例时,有许多不同的配置可用。每种部署策略都有其优点和缺点,并且每种适合不同的目的。
1.png

除了使用Docker CLI为BuildKit启动的面向开发人员的构建之外,构建还可以由多种CI/CD工具触发。例如,使用BuildKit镜像构建可以由Tekton Pipeline Task执行。

结论

本文没有足够的篇幅介绍BuildKit提供的其他功能,例如多平台镜像和无管理员权限构建。但是,这篇文章介绍了BuildKit在容器镜像构建方面带来的许多重要改进。

尽管许多新一代的构建工具都在寻求解决传统构建过程的弊端,但是BuildKit则试图走得更远并且进行创新。

当然,BuildKit尚处于起步阶段,一些功能需要随着在社区的普及而成熟和发展。受制于足够长但不完善的容器镜像构建经验已有很长时间,面对当今可用的选择,这可能会有些令人困惑。有些人将不可避免地基于从属关系做出选择。适用于Red Hat的Buildah,适用于Google的Kaniko或适用于Docker的BuildKit。但是,可以肯定地说,通过当今可用的各种选项,容器镜像的构建工作将变得更加容易。

构建愉快!

原文链接:Container Image Building with BuildKit(翻译:吴世曦)

0 个评论

要回复文章请先登录注册