「本地能跑,服务器跑不了」这个问题,九成是依赖版本不一致。虚拟环境是基础操作,但细节没做好照样出问题。
建环境
python3 -m venv .venv
source .venv/bin/activate # Linux/macOS
.venv\Scripts\activate # Windows
不要用 virtualenv 了,标准库的 venv 够用。目录名用 .venv,多数工具(VSCode、PyCharm)会自动识别。
装依赖
pip install -r requirements.txt
关键是 requirements.txt 怎么来。三种做法差别很大:
做法一:手写顶层依赖
requests>=2.28
fastapi
干净,但下次装可能拿到不同的次版本,出问题不好复现。
做法二:pip freeze
pip freeze > requirements.txt
记录所有包(含间接依赖)的精确版本,可复现。缺点是分不清哪些是直接依赖,升级时不知道该动哪个。
做法三:分层
# requirements.in(手写)
fastapi
requests
# 生成 requirements.txt
pip install pip-tools
pip-compile requirements.in
pip-compile 生成的文件带注释,标明每个包是谁引入的。改依赖改 .in,重新编译。这是我最推荐的方式。
系统和项目分开装
Ubuntu 上 pip install 到系统环境,迟早会遇到 error: externally-managed-environment。Python 3.11 之后 PEP 668 强制了这一点。
正确做法就是 venv,别用 --break-system-packages 绕过去。
服务器上的路径
宝塔这类面板自带的 Python 环境和系统的、项目的都不一样。部署脚本里一定要写绝对路径:
/www/blog-ai/.venv/bin/python app/serve.py
systemd 的 ExecStart 同理,不要依赖 PATH。
编译依赖
mysqlclient、lxml、Pillow 这些要编译,需要系统装开发包:
apt-get install -y python3-dev default-libmysqlclient-dev build-essential libxml2-dev libjpeg-dev
少一个就会报 fatal error: xxx.h: No such file or directory。用 slim 镜像时尤其容易漏。
版本不一致的排查
python -c "import sys; print(sys.executable, sys.version)"
pip list | head -20
先确认用的是哪个 Python。which python 在激活 venv 之后应该是 .venv/bin/python,如果不是,说明激活失败或者 shell 缓存了路径(hash -r 清一下)。
锁文件的意义
requirements.txt 是约定,锁文件是保证。有 pip-compile 生成的 hash 校验,才敢说「装出来的包一定一样」。生产环境部署前,先在一个干净容器里装一遍,能装成功再上。
一句话
虚拟环境隔离的是「包」,锁文件保证的是「版本」。两个都做好,才不会再遇到「本地能跑线上不行」。
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:https://mi-blog.cn/archives/701
共有 0 条评论