1. BuildKit
Buildkit 是一款高效、Docekrfile 无关、更契合 “云原生应用” 的新一代镜像构建工具。
BuildKit 是源自 Docker 的 Moby 项目的第二代镜像构建工具。BuildKit 不限于仅与 Docker 一起使用。这是一种通用的镜像构建工具,可以作为独立的二进制文件(以守护程序或无守护程序模式使用)也可以作为库来使用。实际上,它可以将构建步骤转换成其低级构建器(LLB)表示形式,BuildKit 可用于构建任何制品(artifact)而不仅仅是容器镜像。我们主要在这里关注容器镜像的构建。
相比于 Docker Daemon build,BuildKit 具有以下优势:
- 更高效:支持并行的多阶段构建、更好的缓存管理;
- 更安全:支持 secret mount,无需 root priviliege;
- 更易于扩展:使用自定义中间语言 LLB,完全兼容 Dockerfile,也可支持第三方语言(目前仅有 Buildpacks),后台目前可支持 runC 和 containerd 两种 worker。
目前社区除了 moby/docker-ce 外,还在使用 buildkit 的项目有 genuinetools/img, openFaaS Cloud, containerbuilding/cbi。
1.1. 工作原理
后台启动一个 buildkitd 守护进程,通过 http 通信的方式执行构建。
- gRPC API: 使用 Google RPC 协议高效通信
- Go client library: 基于 Go 的客户端方便调用
- rootless execution: buildctl 不需要 root 权限就可以执行
- OpenTracing: 支持镜像 layer 的逐层溯源
- multi-worker model:支持多种 worker(runC 和 containerd),可扩展
1.2. 特点
1.2.1. 构建步骤优化
Docker 本身提供的构建经常会让人感到沮丧的一个原因是 Dockerfile 指令执行构建步骤的顺序性。引入多阶段构建之后,便可以将同一 Dockerfile 中的构建步骤按逻辑分组进行。
有时,这些构建彼此完全独立,这意味着它们可以并行执行-或根本不需要执行。不幸的是,传统的 Docker 镜像构建无法满足这种灵活性,有时会在不需要时执行构建步骤。这意味着构建时间通常会更长。
相反,BuildKit 会创建一个构建步骤之间的依赖关系图,并使用它来决定构建中的哪些步骤省略,哪些可以并行执行;哪些需要顺序执行。这提供了更有效的构建执过程,这对于迭代其应用程序进行镜像构建的开发人员来说是有价值的。
1.2.2. 高效灵活的缓存
尽管在旧版 Docker 镜像构建中对构建步骤进行缓存非常有用,但效率却不如预期。通过对构建后端的重写,BuildKit 进行了改进,并提供了更快,更准确的缓存机制。它使用为镜像构建生成的依赖关系图,并且基于指令定义和构建步骤内容。
BuildKit 提供的另一个巨大优势来自构建缓存导入和导出的形式。正如 Kaniko 和 Makisu 允许将构建缓存推送到远程镜像仓库一样, BuildKit 也是如此。但是,BuildKit 使你可以灵活地将缓存嵌入到镜像中(内联)并将它们一起推送(尽管并非每个镜像仓库都支持),或者可以将它们单独推送。缓存也可以导出到本地目录以供以后使用。
当从零开始建立构建环境而没有先前的构建历史可受益时,导入构建缓存的功能将发挥作用。导入可以让缓存“热身”,这对于临时CI/CD环境特别有用。
Buildkit 支持 layer 级别缓存,可指定缓存 export/import 路径。
可以使用 registry 缓存:https://github.com/moby/buildkit#exportingimporting-build-cache-not-image-itself
1.2.3. 构建制品
使用旧版 Docker 构建器构建时,将生成的镜像添加到 Docker 守护程序管理的本地镜像缓存中。需要单独的 docker push
将镜像上载到远程镜像仓库。
新型镜像构建工具允许你在构建调用时指定镜像推送,从而增强了体验。 BuildKit 也不例外,它还允许以几种不同格式输出镜像。本地目录中的文件,本地 tarball,本地 OCI 镜像 tarball,Docker 镜像 tarball,存储在本地缓存中的 Docker 镜像以及推送到镜像仓库的Docker镜像。格式很多!
1.2.4. 扩展语法
对于 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 独有的功能。
1.3. 运行 BuildKit
1.3.1. 独立运行
- 非系统 Daemon 模式
在单个容器中运行客户端和临时守护进程
docker run \
-it \
--rm \
--privileged \
-v /path/to/dir:/tmp/work \
--entrypoint buildctl-daemonless.sh \
moby/buildkit:master \
build \
--frontend dockerfile.v0 \
--local context=/tmp/work \
--local dockerfile=/tmp/work
使用非 ROOT 模式:
docker run \
-it \
--rm \
--security-opt seccomp=unconfined \
--security-opt apparmor=unconfined \
-e BUILDKITD_FLAGS=--oci-worker-no-process-sandbox \
-v /path/to/dir:/tmp/work \
--entrypoint buildctl-daemonless.sh \
moby/buildkit:master-rootless \
build \
--frontend \
dockerfile.v0 \
--local context=/tmp/work \
--local dockerfile=/tmp/work
1.3.2. 作为 Docker 插件运行
2018 年 7 月 BuildKit 正式内置于 Docker-ce 18.06.0 的 Docker daemon ,Mac 和 Linux 可以使用环境变量 DOCKER_BUILDKIT=1 开启,同年 10 月发布社区版本。
默认情况下,Buildx 插件以 Docker 驱动程序为目标,该驱动程序使用 Docker 守护程序提供的 BuildKit 库,但存在其固有的局限性。另一个驱动程序是 docker-container,它透明地在容器内启动 BuildKit 来执行构建。它可以提供 BuildKit 全部功能。
# docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS PLATFORMS
remote-builder docker-container
remote-builder0 unix:///var/run/docker.sock inactive linux/amd64*, linux/arm64*
default * docker
default default running linux/amd64, linux/386