1 个不稳定版本
0.0.0 | 2023年9月28日 |
---|
#24 在 #btrfs
165KB
3.5K SLoC
重新构想的 OCI 图像构建工具。
- 利用文件系统的原生快照/差异/覆盖功能。在构建历史中便宜地计算多个更改集/层,使层更细粒度。
- 基于数据流图的并行构建。
- 根据当前构建任务,选择性地添加、删除、混合匹配任意基本层。不要使用混合图像来支持您的混合工具链,依次应用来自多个预构建图像的工具。
- 定义自定义镜像清单。通过灵活的构建工具层解锁,清单文件通过任务的“只是另一个步骤”进行配置构建。使用您自己的代码逻辑选择层,跨平台构建图像,等等。
如何使用
-
您需要一个由当前用户挂载和拥有的新鲜 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
-
创建
~/.config/stromatekt/config.json
并相应调整子卷挂载路径。它应该看起来像{ "btrfs_root": "/home/stromatekt" }
-
准备示例二进制文件
pushd examples/prime && cargo build --release && popd
-
执行示例构建
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*
,只要构建清单明确指出这一点。例如,为了提供一个底层层的安全补丁。此外,proc0
和proc1
可以使用完全不同的底层技术执行(即一个是x86进程,另一个是WASI可执行文件)。
计划扩展
- 用于构建依赖项和可维护性的库文件。在单独的文件中定义附加任务,然后将它们定义的具体变更集导入到另一个规范中,让数据流解析器找出解决方案。
- 通过散列进行可重复性断言,用于增量构建。
依赖项
~14-27MB
~407K SLoC