上周构建镜像时 flask 是 3.0.3,今天同样的 Dockerfile 构建出来是 3.1.1,启动日志里 Werkzeug 也跟着变了。CI 里的提交记录什么都没改。第一次遇到会往复杂处想,其实漏掉的多是个小前提。

pip install pip-tools
pip-compile --generate-hashes -o requirements.txt requirements.in
pip install --require-hashes -r requirements.txt

requirements 只写包名,pip 每次都去索引里挑最新且满足约束的版本。上游一发版,解析结果就变,镜像虽然构建成功,内容和昨天已经不是同一份。这一点先确认清楚,后面就不用反复试。

「requirements 未锁版本」这个问题文档写得含糊,实际行为以当前版本为准,别照旧版本的结论套。新版本先放一台机器上跑一天再全量,问题一般在这段时间暴露。

备份不是备了就行,恢复一次才算数,很多备份文件打开才发现是空的。

具体做法是,用 pip freeze 导出当前可用的精确版本 作为基线;直接依赖写成 == 固定版本 间接依赖用 pip-compile 生成带 hash 的锁文件;构建时加 --require-hashes 让版本和包内容都被校验;每次升级单独提交锁文件 不要混在业务改动里。

改完照着核一遍,两条 requirements 里 flask 都带 == 和 sha256 换一台机器重建镜像 pip freeze 的输出完全一致。

作者 9823189