Docker作为近几年来最通用和流行的容器管理技术,被广泛推广使用的同时也暴露了不少问题。在一个容器镜像需要植入大量依赖或者工具软件的时候,缓慢的构建速度一直被人所诟病,尤其是在4月份mutli-stage build构建支持推出之后,漫长的构建过程通常会影响开发工作效率。
长久以来,Docker的存储方式建立在层的概念上,这对于依赖在其他基础镜像的工程构建来说非常友好,特别体现在更新镜像的操作上,然而在构建方面,尤其是Dockerfile的自定义复杂构建时,Docker缓存通常会忽略那些依赖或者工具的安装。修改一行代码就需要重新下载安装整个依赖,从表面上看是极其不合理的设计,之前一般的处理方式通常是:
- 将LTS的依赖打包成单独的基础镜像,并在最终的Dockerfile里引用它。
- 将依赖包Mount到本地,并在构建的时候COPY到镜像中使用。
对于个人开发者来说,在一定情况下很好用。但是对于构建管理项目或者提供构建流程管理的Devops项目而言却是个灾难--本地存储结构不能对用户开放,它们也不能干扰用户本身的构建流程。所幸的是,Moby umbrella的开发团队注意到了这一点,他们希望通过重构存储管理和容器快照来解决一部分问题,于是BuildKit诞生了。尽管截止目前BuildKit还处于开发阶段,其浏览版本已经可以测试使用,也可以使用Docker容器版本。
- 并行构建
从性能方面来看,BuildKit提供了一个新的并发构建图解算器。它可以在尽可能的情况下并行运行构建步骤,并优化不会对最终结果产生影响的命令。同时,BuildKit还优化了对本地源文件的访问,通过跟踪重复构建调用之间文件所做的更新,并无需等待本地文件在工作开始之前被读取或上传。
![一个buildkit命令下的Docker构建](https://img-blog.csdnimg.cn/20181210153803363.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTExNjYyMjU=,size_16,color_FFFFFF,t_70)
- LLB
BuildKit的核心是一种名为LLB(低级构建器)的新的低级构建定义格式。这是一种中间二进制格式,不对用户公开,但允许在BuildKit之上进行轻松构建。LLB定义了一个内容可寻址的依赖图,可用于将非常复杂的构建定义组合在一起。
![](https://img-blog.csdnimg.cn/20181210154121394.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTExNjYyMjU=,size_16,color_FFFFFF,t_70)
关于构建的执行和缓存的所有内容都在LLB中定义。与传统的Dockerfile构建器相比,BuildKit完全重写了缓存模型。它可以直接跟踪构建图的校验,并安装对应的内容到特定操作,而不是通过启发式来比较图像。这使它更快,更精确和便携。构建缓存甚至可以导出到注册表,在任何主机上的后续调用都可以按需提取它。
- Dockerfile 前端实验语法
frontend experimental syntaxes,目前还处于实验期的内容,在测试的使用中不尽人意。但是从文档中看出,这种新的Dockerfile mount语法,支持将上下文的目录,构建过程中特殊步骤的缓存导入或者导出,并直接访问安全文件。一个官方给出的缓存apt工具安装的示例如下:
# syntax = docker/dockerfile:experimental
FROM ubuntu
RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache
RUN --mount=type=cache,target=/var/cache/apt --mount=type=cache,target=/var/lib/apt \
apt update && apt install -y gcc
这意味着BuildKit将支持自定义的缓存管理和更灵活的挂载方式。
参考文档:
Dockerfile frontend experimental syntaxes