DEBUG.WIKI
V.PS:让项目靠近用户,亚太、欧洲、北美 KVM VPS
IPPeak:从目标地区访问网页,住宅代理、SEO 监测、广告验证
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国

依赖层摘要反复变化

相同 Boot JAR 的 dependencies 层摘要变化,可能是 tools extract 新建目录带了当时的 mtime。区分缓存复用和新层摘要,在受控提取阶段固定目录时间。

同一个可复现的 Spring Boot JAR,在没有热缓存的 CI 构建中,每次生成的 dependencies 层摘要仍不同。如果依赖 JAR 的字节与时间戳都相同,要继续比较层中目录的 mtime,尤其是层根目录和 lib/。

Boot 4.1.1 的 tools extract 会保留文件条目的时间,但创建目录时使用当时的时间。目录头同样进入层的 tar 内容,足以改变摘要;Docker 在查找构建缓存时忽略 mtime,不代表新生成的层也忽略它。

缓存命中会掩盖差异

先分清“步骤没有重新执行”和“步骤重新执行后产物仍相同”。两次构建都命中旧缓存,只能证明旧层被复用,不能验证一次全新的提取会得到相同层。

按层比较归档条目的内容和头部元数据。若文件字节、权限或基础镜像本身变化,先处理这些输入;不要只凭整体镜像摘要不同就认定目录时间戳是原因。整体镜像还可能受其他层和导出方式影响。

在提取阶段统一目录时间

原 JAR 已具备稳定文件时间、提取目录由这次构建独占时,可以在提取结束后给目录设置固定时间。下面是 Linux 构建阶段片段,要求 GNU touch 支持 -d,沿用项目现有基础镜像和后续 COPY:

RUN java -Djarmode=tools -jar app.jar extract --layers --destination layers \
    && find layers -type d -exec touch -d @315532800 {} +

315532800 是选定的固定 Unix 时间,不能每次换成当前时间。这段仅调整 layers 中的目录,不改已经稳定的依赖文件时间。不同平台的 touch 选项并不相同,不能把 Linux 构建片段直接放到 macOS 主机上执行。

目标必须是新的受控提取目录,不复用带有业务文件的目录,更不对源代码、宿主文件系统或线上数据卷批量改时间。原 extract 的布局和各层复制顺序仍需保留。

摘要稳定要按层确认

修正后,在同样输入、同样构建器与导出条件下比较两次独立的新构建,确认依赖层的条目元数据及摘要相同,再检查完整镜像能按原方式启动。为验收做一次受控的无缓存构建即可,不需要清空全局缓存。

这个处理不保证应用层也相同。展开后的应用 JAR 还可能带着源归档文件自身的时间;源文件时间不稳定时,需要单独处理构建输入。文件内容、权限和镜像其他元数据也不在“统一目录时间”的修复范围内。

截至 2026 年 10 月 14 日,目录时间规范化的改动仍在待合并的修复中,不能写成 Boot 4.1.1 已解决。若后续采用正式修复,也要核对它处理哪些新建目录,以及已有目标目录是否保留原时间。