news 2026/10/29 6:27:20

Python实现项目打包部署Linux服务器运行方式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python实现项目打包部署Linux服务器运行方式

前言


把 Python 项目部署到 Linux 服务器上,最容易混淆的是两个词:「打包」和「部署」。打包指的是把项目变成一个可分发、可安装的产物(源码包或 wheel);部署指的是在目标机器上把它跑起来并维持运行。前者由pyproject.toml和构建后端负责,后者由虚拟环境、进程管理器和反向代理负责。这两件事用的工具完全不同,混在一起讲就会变成一锅粥。


第二个要澄清的是setup.py和pyproject.toml的关系。它们不是同一代东西的两种写法:setup.py是「执行一段代码来告诉 setuptools 怎么构建」的老方式,pyproject.toml是 PEP 518 引入的静态配置文件,PEP 517 又在它里面加了build-backend键来指定构建后端。今天pyproject.toml是推荐入口,setup.py只在没有pyproject.toml、或者pyproject.toml里没写build-backend时,才作为「旧行为」被工具回退执行。


第三个必须点明的版本事实:distutils已在 Python 3.12 中从标准库移除(PEP 632),由第三方包 setuptools 继续提供;而且从 Python 3.12 起,venv创建虚拟环境时不再预装 setuptools,需要用的时候得自己pip install setuptools。Python 2.7 已于 2020 年 1 月 1 日停止维护,本文不使用任何 Python 2 写法。


一、pyproject.toml:PEP 518 与 PEP 517 各管什么


两个 PEP 分工明确:




PEP做了什么在文件里的体现



PEP 518引入pyproject.toml这个配置文件,规定[build-system]表requires键(该表唯一的必填键)

PEP 517定义构建后端接口,给[build-system]加一个键build-backend键



PEP 518 说得很直白:[build-system]表最初只有requires一个键是有效的,而且是必填的,值是一串 PEP 508 依赖,表示执行构建系统需要哪些包。绝大多数依赖 setuptools 的项目,文件就这么几行:


[build-system]
requires = ["setuptools>=61"]
build-backend = "setuptools.build_meta"

PEP 517 补充的规则是:如果pyproject.toml不存在,或者文件里没有build-backend键,那么这个源码树就不算使用本规范,工具应当回退到「直接运行setup.py」的旧行为(或者隐式调用setuptools.build_meta:__legacy__后端)。当build-backend存在时,它优先,源码树遵循该后端规定的格式和约定。


一个完整的项目元数据示例:


[build-system]
requires = ["setuptools>=61"]
build-backend = "setuptools.build_meta"

[project]
name = "myapp"
version = "1.0.0"
description = "示例项目"
requires-python = ">=3.9"
dependencies = [
"requests>=2.31",
]

[project.scripts]
myapp = "myapp.cli:main"

[project.scripts]里的条目会在安装后生成同名的命令行入口,实现方式是包装一个可调用对象。


二、构建产物:sdist 与 wheel


构建由「前端」发起,常见的是 PyPA 的build工具:


# 装好构建前端(在虚拟环境里执行)
python -m pip install --upgrade build

# 在项目根目录构建,产物落在 dist/
python -m build

产出两类文件:




类型文件名形态说明



sdistmyapp-1.0.0.tar.gz源码分发包,安装时需要现场构建

wheelmyapp-1.0.0-py3-none-any.whl预构建的二进制分发包,安装快,不需要编译器



wheel 的文件名里,py3是 Python 标签,none是 ABI 标签,any是平台标签。py3-none-any表示「纯 Python、与平台无关」——绝大多数纯 Python 项目都是这个。如果项目有 C 扩展,平台标签会变成manylinux之类,这种 wheel 不能跨发行版随便拷。


setup.py里那套老命令(python setup.py sdist、python setup.py bdist_wheel、python setup.py install)今天不该再用了,官方路径是python -m build构建、pip install安装。


三、在服务器上部署:虚拟环境 + 安装


Linux 上的常见步骤:


# 1) 上传代码或构建产物,解压到 /opt/myapp
sudo mkdir -p /opt/myapp
sudo chown "$USER" /opt/myapp

# 2) 创建虚拟环境(venv 自 Python 3.5 起是官方推荐做法)
cd /opt/myapp
python3 -m venv .venv

# 3) 激活并升级基础工具
source .venv/bin/activate
python -m pip install --upgrade pip

# 4) 安装项目及其依赖
# 方式 A:直接装当前目录(会自动走 PEP 517 构建)
python -m pip install .

# 方式 B:先构建再装 wheel
python -m pip install build
python -m build
python -m pip install dist/myapp-1.0.0-py3-none-any.whl

两个细节:



  • 不要用sudo pip install。系统 Python 的包由发行版包管理器管,用 pip 直接装会和系统包打架,很多新版发行版也会直接拒绝。一切都装在虚拟环境里。

  • 脚本里最好用.venv/bin/python -m pip这种绝对路径调用,而不是依赖source activate——activate只在交互式 shell 里方便,写进 systemd 或 cron 里容易失效。


如果只需要依赖、不需要把项目本身装成包,也可以退一步:


/opt/myapp/.venv/bin/python -m pip install -r requirements.txt

四、让它常驻:systemd


前台能跑起来只是第一步,服务器上还需要进程守护、开机自启、崩溃重拉。systemd 是现在 Linux 上的标准做法。在/etc/systemd/system/myapp.service写一个单元文件:


[Unit]
Description=My Python App
After=network.target

[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
Environment="PYTHONUNBUFFERED=1"
EnvironmentFile=-/opt/myapp/.env
ExecStart=/opt/myapp/.venv/bin/python -m myapp
Restart=on-failure
RestartSec=3

[Install]
WantedBy=multi-user.target

维护命令:


sudo systemctl daemon-reload
sudo systemctl enable --now myapp
sudo systemctl status myapp
journalctl -u myapp -f

要点说明:



  • ExecStart必须写绝对路径,systemd 不做PATH查找,也不读取 shell 的activate结果。

  • Type=simple表示主进程就是那个前台进程;如果程序会自己 fork 到后台,得用Type=forking。

  • EnvironmentFile前面的减号表示文件不存在也不报错,适合放密钥。

  • 如果要跑多个 worker 的 Web 服务,通常用 gunicorn 之类的 WSGI 服务器作为ExecStart,再在前面挂 Nginx 做反向代理和 TLS 终止。


五、打包方式的选择




场景推荐做法



内网单机、代码就是全部上传源码 +venv+pip install -r requirements.txt

需要可分发、可版本化的产物python -m build产出 wheel/sdist,分发 wheel

需要命令行入口pyproject.toml里配[project.scripts]

依赖里有需要编译的包在有编译环境的机器上构建 wheel,再分发

目标机不能联网在联网机器pip download -d wheels/,拷过去pip install --no-index --find-links wheels/

需要完全一致的环境容器镜像(另题)或锁文件 + 固定版本号



「锁文件」这个概念值得单独提一句:requirements.txt里写requests和写requests==2.31.0是两个不同级别的可复现性。生产环境应当固定到确切版本,并且最好用pip freeze从已验证过的环境里导出。


实战:从零到常驻的完整流程


# ---- 构建机(有网络、有编译环境)----
cd /path/to/project
python3 -m venv .venv-build
source .venv-build/bin/activate
python -m pip install --upgrade pip build
python -m build
ls dist/
# dist/myapp-1.0.0-py3-none-any.whl
# dist/myapp-1.0.0.tar.gz

# 顺带把依赖也下载下来,便于离线部署
python -m pip download -d wheels/ -r requirements.txt

# ---- 目标服务器 ----
sudo useradd --system --create-home --shell /usr/sbin/nologin myapp
sudo mkdir -p /opt/myapp
sudo chown -R myapp:myapp /opt/myapp

# 上传 dist/ 与 wheels/ 到 /opt/myapp 后:
sudo -u myapp python3 -m venv /opt/myapp/.venv
sudo -u myapp /opt/myapp/.venv/bin/python -m pip install --upgrade pip
sudo -u myapp /opt/myapp/.venv/bin/python -m pip install \
/opt/myapp/dist/myapp-1.0.0-py3-none-any.whl

# 写 systemd 单元并启动(内容见上一节)
sudo systemctl daemon-reload
sudo systemctl enable --now myapp
sudo systemctl status myapp

如果python3 -m venv报错说缺少ensurepip,说明系统没装 venv 组件,在 Debian/Ubuntu 上装python3-venv即可;RHEL 系对应的是python3完整包。


常见坑点


1. 用了 Python 2 或 3.12 之前的distutils导入


❌ 错误写法:


from distutils.core import setup

setup(name="myapp", version="1.0.0")

distutils已在 Python 3.12 中从标准库移除(PEP 632),这行直接ModuleNotFoundError。


✅ 正确写法:改用 setuptools +pyproject.toml(setuptools 至今仍提供distutils的兼容实现,但不应再依赖它):


[build-system]
requires = ["setuptools>=61"]
build-backend = "setuptools.build_meta"

2. 在虚拟环境里以为 setuptools 一定在


❌ 错误想法:python -m venv .venv之后就能直接用setuptools。


✅ 正确认识:从 Python 3.12 起,venv不再预装 setuptools,distutils、setuptools、pkg_resources、easy_install默认都不可用;需要时先装:


source .venv/bin/activate
python -m pip install setuptools

3. 用sudo pip install装到系统环境


❌ 错误写法:


sudo pip install -r requirements.txt

会和发行版包管理器抢文件,升级系统时冲突,很多新发行版也直接禁止。


✅ 正确写法:


python3 -m venv /opt/myapp/.venv
/opt/myapp/.venv/bin/python -m pip install -r requirements.txt

4. 把pyproject.toml和setup.py当成一回事


❌ 错误想法:以为写了pyproject.toml就必须删掉setup.py,或者以为两者可以随便混着写。


✅ 正确认识:pyproject.toml的[build-system]由 PEP 518 定义、build-backend由 PEP 517 定义;项目元数据放[project]表。若文件里没有build-backend,工具会回退到运行setup.py的旧行为。迁移时应当把元数据搬到[project],而不是在两边各写一份。


5. 忘记requires是[build-system]表的必填键


❌ 错误写法:


[build-system]
build-backend = "setuptools.build_meta"

✅ 正确写法:


[build-system]
requires = ["setuptools>=61"]
build-backend = "setuptools.build_meta"

6. systemd 的ExecStart用相对命令或依赖activate


❌ 错误写法:


ExecStart=python -m myapp

systemd 不做PATH查找,也不读 shell 的激活状态,服务会启动失败。


✅ 正确写法:


ExecStart=/opt/myapp/.venv/bin/python -m myapp

7. 依赖没有固定版本,两次部署结果不一致


❌ 错误写法:


# requirements.txt
requests
flask

✅ 正确写法:固定到确切版本,并从已验证环境导出:


python -m pip freeze > requirements.txt

8. 构建产物里混进了不该带的文件


❌ 错误做法:python -m build之后发现dist/里的包带着.venv、测试数据、.env。根源通常是没配排除规则。


✅ 正确做法:在pyproject.toml里声明打包时包含哪些包,并用MANIFEST.in控制 sdist 的文件范围;同时别把虚拟环境建在项目目录里。


总结




概念归属关键点



setup.py旧方式执行代码来声明构建方式;今天只在回退路径上使用

pyproject.tomlPEP 518 / 517[build-system]的requires必填;build-backend缺失则回退旧行为

sdist构建产物源码包,安装时现场构建

wheel构建产物预构建包,纯 Python 项目一般是py3-none-any

构建命令构建前端python -m build,产出到dist/

安装部署pip install .或pip install 某.whl,装在虚拟环境里

虚拟环境部署python3 -m venv .venv;3.12 起不再预装 setuptools

常驻运行部署systemd 单元,ExecStart用绝对路径

移除项版本事实distutils在 Python 3.12 已移出标准库(PEP 632)



部署一条龙可以概括为:用pyproject.toml描述项目、用python -m build产出 wheel、在服务器上用venv建隔离环境、用pip install安装、再用 systemd 让它常驻。只要把「打包」和「部署」分开看,并且记住pyproject.toml属于 PEP 518 / 517 这一代而setup.py是回退路径,这套流程就不会乱。




版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/29 6:27:05

搜索优化:如何通过负反馈捕捉提升用户体验

1. 项目背景与核心诉求去年夏天团队内部的一次产品讨论会上,我们围绕搜索功能优化产生了激烈争论。当时有个现象特别有意思:当展示新设计的搜索算法效果时,80%的同事表示"还不错",但两周后的用户调研却显示实际使用率下…

作者头像 李华
网站建设 2026/10/29 6:25:31

Agent-Reach:用CLI+Python让AI Agent真正触达外部世界

1. 项目缘起:为什么我要折腾一个叫 Agent-Reach 的东西先说说这个标题的由来。Agent-Reach 这个名字,拆开看就是两层意思:Agent 指的是 AI Agent,Reach 指的是触达、连接、把能力伸出去。合在一起,它想解决的核心问题就…

作者头像 李华
网站建设 2026/10/29 6:24:26

CTF竞赛中的Wireshark流量分析技巧与实战

1. 流量分析在CTF竞赛中的核心价值在网络安全竞赛领域,流量分析题目几乎出现在每场CTF赛事中。这类题目通常会提供一个网络数据包文件(通常为.pcap格式),要求参赛者从中提取隐藏的flag或还原攻击过程。不同于Web渗透或逆向工程&am…

作者头像 李华
网站建设 2026/10/29 6:24:22

企业需求预测体系落地:预测粒度、数据治理与模型选型

开头这十几年我经手过的预测项目,从月度销售预估到每天几十万条SKU级别的出库量,最后能真正跑起来并且被业务用起来的,不到一半。多数项目不是败在模型不够先进,而是败在第一步就没想明白:这家企业到底要预测什么、预测…

作者头像 李华
网站建设 2026/10/29 6:23:50

C++多态全解析:虚函数表、vptr与工程踩坑

写了这么多年 C,如果让我挑一个最能区分“会写语法”和“会做设计”的知识点,多态绝对排得上前三。很多人背得出“一个接口,多种实现”,可真到了要把一段越写越长的 if-else 拆成可扩展的结构,或者在 delete 一个基类指…

作者头像 李华
网站建设 2026/10/29 6:23:48

华为CANN自定义算子开发实战:NPU加速与性能优化

1. 项目概述在NPU加速计算领域,CANN(Compute Architecture for Neural Networks)作为华为推出的异构计算架构,正在重塑AI算力的边界。最近我在一个图像超分辨率项目中遇到了标准算子库的性能瓶颈,这促使我深入探索了CA…

作者头像 李华