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。
工作原理¶
后台启动一个 buildkitd 守护进程,通过 http 通信的方式执行构建。
- gRPC API: 使用 Google RPC 协议高效通信
- Go client library: 基于 Go 的客户端方便调用
- rootless execution: buildctl 不需要 root 权限就可以执行
- OpenTracing: 支持镜像 layer 的逐层溯源
- multi-worker model:支持多种 worker(runC 和 containerd),可扩展
特点¶
构建步骤优化¶
Docker 本身提供的构建经常会让人感到沮丧的一个原因是 Dockerfile 指令执行构建步骤的顺序性。引入多阶段构建之后,便可以将同一 Dockerfile 中的构建步骤按逻辑分组进行。
有时,这些构建彼此完全独立,这意味着它们可以并行执行-或根本不需要执行。不幸的是,传统的 Docker 镜像构建无法满足这种灵活性,有时会在不需要时执行构建步骤。这意味着构建时间通常会更长。
相反,BuildKit 会创建一个构建步骤之间的依赖关系图,并使用它来决定构建中的哪些步骤省略,哪些可以并行执行;哪些需要顺序执行。这提供了更有效的构建执过程,这对于迭代其应用程序进行镜像构建的开发人员来说是有价值的。
高效灵活的缓存¶
尽管在旧版 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
构建制品¶
使用旧版 Docker 构建器构建时,将生成的镜像添加到 Docker 守护程序管理的本地镜像缓存中。需要单独的 docker push
将镜像上载到远程镜像仓库。
新型镜像构建工具允许你在构建调用时指定镜像推送,从而增强了体验。 BuildKit 也不例外,它还允许以几种不同格式输出镜像。本地目录中的文件,本地 tarball,本地 OCI 镜像 tarball,Docker 镜像 tarball,存储在本地缓存中的 Docker 镜像以及推送到镜像仓库的Docker镜像。格式很多!
扩展语法¶
对于 Docker 构建体验而言,往复出现的众多功能性请求之一就是安全的处理镜像构建过程。 Moby 项目多年来一直抵制此呼吁。但是,借助 BuildKit 灵活的“前端”定义,实验性的扩展了 Dockerfile 语法。扩展语法为 RUN Dockerfile 指令提供了新的功能,其中包括安全功能。
引用实验性前端的 Dockerfile 可以临时为 RUN 指令添加 secret 参数。secret 使用 docker build 的 --secret
标志实现。同样,使用 SSH 挂载可启用 SSH 代理连接的转发,以进行安全的 SSH 身份验证。
能够以这种方式扩展 Dockerfile 的语法是 BuildKit 独有的功能。
运行 BuildKit¶
独立运行¶
- 非系统 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
作为 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
使用 Kubernetes POD 运行¶
参考¶
- https://www.duyidong.com/2019/05/19/build-image-in-container-via-buildkit/
- https://github.com/moby/buildkit
- https://hub.docker.com/r/moby/buildkit
- https://www.giantswarm.io/blog/container-image-building-with-buildkit
Docker生态:BuildKit¶
概述¶
BuildKit 是 Docker 生态系统中的一个现代化构建工具,旨在提供更高效、更灵活的镜像构建能力。与传统的 Docker 构建方式相比,BuildKit 支持并行构建、缓存优化、多阶段构建等高级特性,显著提升了构建性能。本章节将深入探讨 BuildKit 的核心功能、架构设计及其在 Docker 生态中的独特价值。
核心功能¶
1. 并行构建机制¶
BuildKit 通过并行化构建步骤,显著缩短了镜像构建时间。它能够智能地分析 Dockerfile 中的依赖关系,将无依赖关系的步骤并行执行,从而最大化利用系统资源。
- 依赖分析:BuildKit 自动解析 Dockerfile 中的指令依赖,确保并行构建的正确性。
- 资源优化:通过并行化,充分利用多核 CPU 的性能,提升构建效率。
2. 缓存分层优化¶
BuildKit 引入了更高效的缓存机制,支持细粒度的缓存分层管理。它能够识别 Dockerfile 中未更改的部分,并复用缓存,避免重复构建。
- 缓存复用:通过哈希算法识别未更改的构建步骤,直接复用缓存。
- 增量构建:仅构建发生变化的部分,减少构建时间和资源消耗。
3. 多阶段构建支持¶
BuildKit 深度支持多阶段构建,允许在单个 Dockerfile 中定义多个构建阶段,并仅将最终所需的文件复制到最终镜像中。这种方式显著减少了镜像体积。
- 阶段隔离:每个构建阶段独立运行,避免污染最终镜像。
- 精简镜像:仅复制必要的文件,减少镜像大小。
4. 多架构镜像构建¶
BuildKit 支持构建多架构镜像(如 ARM、x86 等),并能够将多个架构的镜像打包为单个 Manifest List。这对于跨平台部署尤为重要。
- 跨平台支持:通过 QEMU 模拟器,在单一平台上构建多架构镜像。
- Manifest List:将多个架构的镜像打包为单个 Manifest,简化分发流程。
5. 与 Dockerfile 的深度集成¶
BuildKit 完全兼容 Dockerfile 语法,并在此基础上扩展了更多高级功能,如内联缓存、秘密管理(Secrets Management)等。
- 内联缓存:通过
--cache-from
和--cache-to
参数,实现构建缓存的共享和复用。 - 秘密管理:支持在构建过程中安全地传递敏感信息(如 API 密钥)。
架构设计¶
BuildKit 的架构设计基于客户端-服务器模型,核心组件包括:
- BuildKit Daemon:负责实际的构建任务,支持分布式构建和缓存共享。
- Frontend:解析 Dockerfile 或其他构建描述文件,生成中间表示(LLB)。
- LLB(Low-Level Build):一种中间表示语言,用于描述构建步骤和依赖关系。
- Worker:执行具体的构建任务,支持多种后端(如 Docker、Kubernetes)。
与传统 Docker 构建工具的对比¶
特性 | BuildKit | 传统 Docker 构建工具 |
---|---|---|
并行构建 | 支持 | 不支持 |
缓存优化 | 细粒度缓存分层 | 粗粒度缓存 |
多阶段构建 | 深度支持 | 支持但效率较低 |
多架构构建 | 支持 | 不支持 |
秘密管理 | 支持 | 不支持 |
性能 | 显著提升 | 较低 |
在 CI/CD 中的应用¶
BuildKit 的高效构建能力使其成为 CI/CD 流水线中的理想选择。通过以下方式,可以显著提升流水线的效率:
- 并行构建:缩短构建时间,加快交付速度。
- 缓存复用:减少重复构建,节省计算资源。
- 多阶段构建:生成更小的镜像,加快部署速度。
- 多架构支持:简化跨平台部署流程。
使用示例¶
启用 BuildKit¶
在 Docker 18.09 及以上版本中,可以通过以下方式启用 BuildKit:
多阶段构建示例¶
# 阶段 1:构建应用
FROM golang:1.19 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp .
# 阶段 2:生成最终镜像
FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/myapp .
CMD ["./myapp"]
多架构构建示例¶
docker buildx create --use
docker buildx build --platform linux/amd64,linux/arm64 -t my-image:multi-arch .
总结¶
BuildKit 作为 Docker 生态系统中的现代化构建工具,通过并行构建、缓存优化、多阶段构建等特性,显著提升了镜像构建的效率和灵活性。它不仅适用于本地开发环境,还能在 CI/CD 流水线中发挥重要作用。通过深入理解 BuildKit 的核心功能和架构设计,开发者可以更好地利用其优势,优化容器化应用的构建和部署流程。
参考资料: - Docker 官方文档 - BuildKit - BuildKit GitHub 仓库