#layer #oci #task #builder #manifest #btrfs #linear

app stromatekt

基于 runc 和 btrfs 的并行化 OCI 构建工具

1 个不稳定版本

0.0.0 2023年9月28日

#24#btrfs

AGPL-3.0-or-later

165KB
3.5K SLoC

重新构想的 OCI 图像构建工具。

  • 利用文件系统的原生快照/差异/覆盖功能。在构建历史中便宜地计算多个更改集/层,使层更细粒度。
  • 基于数据流图的并行构建。
  • 根据当前构建任务,选择性地添加、删除、混合匹配任意基本层。不要使用混合图像来支持您的混合工具链,依次应用来自多个预构建图像的工具。
  • 定义自定义镜像清单。通过灵活的构建工具层解锁,清单文件通过任务的“只是另一个步骤”进行配置构建。使用您自己的代码逻辑选择层,跨平台构建图像,等等。

如何使用

  1. 您需要一个由当前用户挂载和拥有的新鲜 BTRFs 子卷。此外,应启用 unprivileged_userns_clone 并在支持 userns 的内核上编译内核。

    # mount -t btrfs -o rw,space_cache,user_subvol_rm_allowed,noacl,noatime,subvol=/stromatekt /dev/sdx /home/stromatekt
    btrfs filesystem df /home/stromatekt
    cat /proc/sys/kernel/unprivileged_userns_clone | grep 1
    cat /proc/config.gz  | gunzip -c | grep CONFIG_USER_NS=y
    
  2. 创建 ~/.config/stromatekt/config.json 并相应调整子卷挂载路径。它应该看起来像

    {
    	"btrfs_root": "/home/stromatekt"
    }
    
  3. 准备示例二进制文件

    pushd examples/prime && cargo build --release && popd
    
  4. 执行示例构建

    cargo run -- ./examples/parallel-dependency.json --no-dry-run
    

动机

docker build 很慢。Dockerfile 的结构只允许线性指令序列。此外,docker compose 甚至更慢。它会发送、解包、重新打包图像和本地文件系统的层,数量很多。这可能会花费大量时间。作者观察到,包含单个添加文件系统链接行的 Dockerfile 的构建需要 >4 分钟。这对于开发延迟来说是不可接受的。此外,由于线性序列逻辑,层的缓存非常糟糕。让我们解决这两个问题。

OCI 文件的结构

OCI 容器中的主要数据是层的有序集合。每个层基本上是上一个层的 diff,通常以 tar 归档的形式。 (由于一些令人惊讶的原因,删除被编码为具有特殊命名规则的头文件)。

在运行构建时,构建工具将检出基础容器的层,运行其命令,最后找到要编码到新层中的差异。如果我们可以利用文件系统的检查点和增量差异逻辑,那么两个高度昂贵的文件系统任务——检出和差异——可以更有效地实现。

此外,这项任务可能是I/O密集型的。这意味着我们应该尽可能地在并行中执行大部分任务。请注意,OCI镜像的层顺序不是交换律的。然而,只要任务定义本身通过提供规范的重组合顺序来选择加入,就不应该存在任何通过不同顺序创建层所带来的可重复性问题。

示例

  • A --(proc0)-> B0产生差异 C0
  • A --(proc1)-> B1产生差异 C1
  • => 将层导出为:[A, C0, C1]

实际上,我们甚至可以允许将A替换为完全无关的A*,只要构建清单明确指出这一点。例如,为了提供一个底层层的安全补丁。此外,proc0proc1可以使用完全不同的底层技术执行(即一个是x86进程,另一个是WASI可执行文件)。

计划扩展

  1. 用于构建依赖项和可维护性的库文件。在单独的文件中定义附加任务,然后将它们定义的具体变更集导入到另一个规范中,让数据流解析器找出解决方案。
  2. 通过散列进行可重复性断言,用于增量构建。

依赖项

~14-27MB
~407K SLoC