构建确定性是什么
消除构建中的非确定性来源,让「同输入同输出」变得可测量:时间戳固定(SOURCE_DATE_EPOCH 被众多工具链识别)、归档排序稳定、路径规范化、属主固定。复现验证的方法是先做双次构建比对——看两次产物哈希是否一致,再逐项定位差异来源、逐项消除。可复现是渐进目标,先从打包环节做起。
基本信息
| 时间戳 | export SOURCE_DATE_EPOCH=$(git log -1 --format=%ct) |
|---|---|
| 归档 | tar --sort=name --mtime 固定,gzip -n 去掉名称与时间 |
| 路径 | 构建目录固定,或在产物中剔除绝对路径 |
| 验证 | 双次构建比对产物哈希 |
| 范围 | 工具链、文件顺序、元数据都要覆盖 |
典型使用场景
- 验证构建:两次构建同哈希,证明流程没有随机来源
- 归档交付:发布包含固定时间戳,便于逐位比对
- 供应链信任:可复现构建支撑源码与产物的对账
- 差异定位:哈希不一致时按文件粒度缩小范围
- 跨机器验证:不同构建机产出一致才算真的可复现
- 历史脚本回填:逐步补齐固定项,逼近可复现
可复现打包
可复现打包
export SOURCE_DATE_EPOCH=$(git log -1 --format=%ct) # 时间基准用提交时间
tar --sort=name --mtime="@${SOURCE_DATE_EPOCH}" \
--owner=0 --group=0 -cf app.tar dist/ # 固定排序与属主
gzip -n app.tar # -n 去掉 gzip 自身的名称与时间戳
sha256sum app.tar.gz # 双次构建比对同一个哈希非确定来源清单
| 来源 | 表现 | 处理 |
|---|---|---|
| 时间戳 | 产物内含构建时间 | 用 SOURCE_DATE_EPOCH 固定 |
| 文件顺序 | 归档清单顺序漂移 | 打包时显式排序 |
| 路径信息 | 产物嵌入绝对路径 | 固定构建目录或剔除 |
| 并行顺序 | 输出写入顺序随机 | 结果显式排序后再写 |
先做双次构建比对:两次产物哈希是否一致,逐项定位差异再逐项消除。
SOURCE_DATE_EPOCH 要全链路传递:子进程与容器内都要可见,否则深处工具仍用当前时间。
时间基准用最近提交时间而不是构建时刻:同一提交任何时候构建结果才能一致。