关于 Python 环境可复现性请教

21 天前
 xgq89757
公司 toB 项目 python 三方依赖有 150+,有没有比较优雅的方式能严格按照 requirements.txt (可能存在版本冲突)复现依赖环境,pip install -r requirements.txt 有个问题就是没准过段时间构建出来的环境就和 requirements.txt 中的不一致了

目前的做法是将环境做成了基础镜像,每次交付都基于这个镜像打包。不同版本有增量依赖或版本调整时在 Dockerfile 中单独 pip install ,但这也存在基础镜像管理和基础镜像复现的问题。
3153 次点击
所在节点    Python
56 条回复
dzdh
21 天前
用 uv 。lock 版本。
JoeJoeJoe
21 天前
可以给项目加个虚拟环境, python 应该有很多这样的库, pyenv, venv 之类的.

参考链接:
1. https://www.cnblogs.com/doublexi/p/15783355.html
2. https://www.cnblogs.com/doublexi/p/15786911.html
blackshadow
21 天前
venv + requirement ,还有约定指定的 python 版本。 当然,即使这样,python 构建出的成果也有可能有问题。 我曾经在不同的电脑完全一模一样 venv ,依赖版本一样的环境,用 pyinstaller 打包的结果,不一样。😂
xgq89757
21 天前
@JoeJoeJoe 虚拟环境是有的,目前用的 miniforge ,主要是环境复现的问题,最近在尝试 pixi
iorilu
21 天前
复杂的项目直接打包部署镜像是最好的
JoeJoeJoe
21 天前
@xgq89757 环境复现是个啥场景啊, requirements.txt 指定版本号的话, install 下来的每次不应该都是相同的吗😂 没太理解
Cooky
21 天前
@JoeJoeJoe 除了 pip 包剩下的应该就是依赖的二进制库了,二进制库都要一直那就得上 docker 了
xgq89757
21 天前
@dzdh 用 ai 对比了 uv 和 pixi ,ai 指出 uv 对需要二进制编译的包支持不太友好,项目中算法和机器学习库不少,最近在尝试 pixi ,仍遇到安装环境出现版本冲突的问题,可能 toml 没有编排好的问题。后边准备尝试下 uv ,验证下 ai 的结论。
xgq89757
21 天前
@JoeJoeJoe 没准过几个月 pip install -r 下来发现有些包就不一样了😂
xgq89757
21 天前
@blackshadow 还有就是项目是在某些版本冲突下稳定运行的,-r 构建就会报错退出,只能先注释掉冲突的包,最后在单独 install
JoeJoeJoe
21 天前
@xgq89757 #9 还有这种情况呢? 我倒是一直没注意过, 我一直是能跑就行.

ps: 要是怕这个的话, 直接把三方依赖的包放到共享文件夹吧, 指定一下 python 包路径
xgq89757
21 天前
@JoeJoeJoe 所以暂时的方法是打成了基础镜像。
killva4624
21 天前
@xgq89757 #9 pip install -r 为啥不会一样,没指定版本号吗?
maocat
21 天前
合理怀疑 requirements.txt 里面没有吧对应的的包的关联依赖包拉进来, 试一试 pip freeze 全量输出
xgq89757
21 天前
@killva4624 全指定了版本号的,清单是从当前稳定运行的环境中 pip list --format=freeze 拉下来的,
后续就是想通过这个清单复现环境,但是有些包会出现版本冲突或者构建下来的环境和清单不一致。
xgq89757
21 天前
@iorilu 目前就是这样的,运行环境打包成基础镜像,交付打包时再将混淆的工程打包进镜像。但是遇到不允许容器化部署的客户就比较麻烦了,要根据客户的环境做离线包,客户是金融、银行之类的基本都没有公网。
blackshadow
21 天前
@xgq89757 感觉最好的办法就是你上面的了,一是容器化部署;二是全部的依赖包都本地保存离线版,环境里全部离线安装。 感觉你这个要求和我们之前很像,我们之前给客户装环境完全内网,rpm 服务都是自己搭建,找个大硬盘里面装了所有需要的离线包。
Mithril
21 天前
虽说也推荐你用 uv ,但你这个环境和要求,光靠 uv 是没法彻底解决的。你要考虑的是依赖的可信与供应链管理,而不简单的一个 lock 。

正常做法是,内网搭建 pip 的镜像服务,并且配置多个 pip 仓库。至少三个,dev ,integration ,release 。只有 dev 是联通外网的 mirror ,其他两个是本地库。

然后你开发的时候 pip 指向 dev 库,发版的时候,QA 和测试用 integration 库。这时候把你需要的指定版本的所有依赖从 dev 提升复制到 integration 库内。

当 QA 和测试完成,再次把这些依赖到 release 库内。作为最终 release 的二进制依赖,同时对依赖进行漏洞检查和制做 SBOM 。

当然你可以根据你们的要求自己调整一下,可能也用不到这么严格的流程。但本质上为了避免 FOSS 的供应链风险,你应该自己保留所有依赖的二进制及其代码以供审查,并且可以完全从本地构建你的产品。

别忘了之前 npm 下毒的事。
xgq89757
21 天前
@JoeJoeJoe 默认行为:pip 会安装满足条件的最新版本,比如某个三方依赖的子依赖要求是> 1.0 ,这个子依赖当时的最新版本是 1.5 ,当时安装的会是 1.5 ,过一段时间这个子依赖的版本迭代到到了 1.7 ,在这时它会安装 1.7 ,这个好解决,在 requirements.txt 中强制子依赖==1.5 ,但因为项目迭代比较久了,后续有人增加或修改了某些依赖,这个操作是直接在环境中单独安装的(这时候不会暴露冲突问题),然后归档依赖版本到 requirements.txt ,但是项目就是在这样的冲突下稳定运行的,时间久了你想在其他服务器复现环境再通过 requirements.txt 构建的时候就会发现有的包有版本冲突,这时候冲突的依赖只能单独安装,然后刷一遍版本。
momocraft
21 天前
pip freeze 却不能重现有点怪

涉及到全局安装的包,或者嵌套的 venv 吗?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1152582

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX