sadfQED2
V2EX  ›  Python

Python Web 项目的部署如此之复杂!

By sadfQED2 at 2023 年 12 月 12 日 · 5331 次点击

接手了一个 python django 写的上古项目。今天稍稍改了改,部署上线的时候突然看到启动命令竟然写的是python manage.py runserver

虽然我从来没写过 django 项目,但是我也知道这命令启动的是开发测试服务器。就跟前端的npm run dev一样。此时我内心”这特么怎么行,线上业务啊,怎么能这么敷衍,跑个测试服务器就上线“。于是想着改改 Dockerfile ,改成正经的线上部署。

可是我也没搞过 django 啊,经过一通搜索,大致了解到,django 可以通过 Gunicon 、uWSGI 、Apache mod_wsgi 、Daphne 、Hypercom 、Uvicom 等等方式部署。我淦,怎么这么多啊,我也不知道选哪个啊,uWSGI 在官网写在第一个的,那就他吧。

照着官网示例抄吧,先这样再那样,Dockerfile 改好了,试一试,草,Docker 容器怎么启动就停了?一通排查,原来 uwsgi --ini uwsgi.ini这命令不是前台运行的,Dockerfile 里面拿这个当启动命令起来立马就没了。

经过 N 久翻阅文档,发现 uwsgi 启动会生成一个 pid 文件,看到这里,我这个大聪明有办法了,于是 Dockerfile 启动命令改成CMD uwsgi --ini uwsgi.ini && tail -f uwsgi.pid ,再次尝试,容器成功保活。

正在得意我的聪明才智的时候,结果一看,我淦,uwsgi 是起来了,但是服务为啥不能用啊。又一通排查,我淦,uwsgi.ini 里面的路径好像有问题,可这玩意路径写到哪里文档也没说啊,网上一会说是项目路径,一会说是 app 路径,什么鬼啊,一个一个尝试,结果都特么不行。

再仔细翻翻文档,这什么玩意呀,部署上线什么还要带个 sqllite 文件呀,怎么还有先执行命令整理代码啊,怎么还要。。。。。

从早上 10 点一直捣鼓到现在晚上 8 点,饭都没吃饱,这什么破玩意啊。md 果断敲下 git reset -hard 。滚 tm 的,我真是吃饱了没事干,服务跑得好好的,改什么改,前人用开发服务器肯定是有他的道理的,瞎改什么改。就算服务挂了,Docker 容器自动拉起,有毛线关系啊。

不得不感叹,我部署过上古时期的 java 项目,拷个 war 包上线。也部署过 php 项目,拷份代码到目录就上线,也部署过 golang 项目,本地交叉编译拷个二进制文件上线,也部署过 c c++项目... 像 python 这么恶心的还是第一次,什么乱七八糟路径,调试又没日志,找到日志又不清不楚的,没人用这玩意果然是有原因的。

43 条回复  •  2024-02-06 11:27:57 +08:00
yakun4566
   1
yakun4566  
   2023 年 12 月 12 日
python *.py 还好吧,我们线上项目 Java 也是 java -jar 啊(也有可能是我们水分太大
volvo007
   2
volvo007  
   2023 年 12 月 12 日
op 好惨,上来选了个最“基础” 的…… 选 gunicorn 可破,但是,光选中间件也不行啊,你还没部署 nginx 反向代理呢 (狗头
shimada666
   3
shimada666  
   2023 年 12 月 13 日   ❤️ 2
搞那么麻烦干嘛,直接 python manage.py runserver 就好了。
等 qps 过 20 再考虑别的吧
arischow
   4
arischow  
   2023 年 12 月 13 日 via iPhone   ❤️ 7
你接手的代码烂,你也菜😄
llsquaer
   5
llsquaer  
   2023 年 12 月 13 日
写的 api 接口,直接 python manage.py runserver 没毛病。。工作期间 8 小时内 平均 QPS 80 左右至今没问题。内部使用。

不过 python web 是略显复杂。主要就几个容器的区别。熟悉一个当万金油用
sadfQED2
   6
sadfQED2  
OP
   2023 年 12 月 13 日 via Android
@shimada666 线上大几十台机器,你说 qps 过 20 不

@llsquaer 直接 runserver 区别大吗?是一个 ai 模型,为了提供 api 调用,就 django 包了一层,整个项目就一个接口,代码不超过 100 行
ihmily
   7
ihmily  
   2023 年 12 月 13 日
项目就一个接口,直接使用 fastapi 就好了
JiaNa
   8
JiaNa  
   2023 年 12 月 13 日 via iPhone
@sadfQED2 既然你说了是旧项目,如果之前没有出现性能问题,那么没有性能问题。
如果你愿意折腾、学东西,模拟生产环境 API 进行压测,比较不同方式的性能区别。
shimada666
   9
shimada666  
   2023 年 12 月 13 日
@sadfQED2 完全没问题,容器挂个 restart=always ,崩了还能重新启动
sadfQED2
   10
sadfQED2  
OP
   2023 年 12 月 13 日
@JiaNa 线上服务,不能随便压。我也不是专业运维,也不是专业的 python 开发。但是就我的理解,直接 python runserver 这应该是单进程运行的,就 python 来说这应该完全没办法充分利用 cpu 。

但是这个项目本质上是调用 PyTorch ,PyTorch 底层又是调用 C++模块,C++模块是不是就能不受限于 Pyton 的单进程直接跑满 CPU 了我也不清楚。

所以到底能不能充分利用 cpu 我也搞不清楚。
sadfQED2
   11
sadfQED2  
OP
   2023 年 12 月 13 日
@shimada666 #9 现在容器就是 restart=always ,然后上层网关配置了故障转移。某次请求失败会自动转到其他机房的容器上。但是想着 python runserver 还监听代码变化,随时重启,心里就觉得不舒服
RedisMasterNode
   12
RedisMasterNode  
   2023 年 12 月 13 日
感觉不是语言的问题。不太理解,这些东西不是在 README 里面写好就行了吗?

https://images2.imgbox.com/91/09/qF1P6Xv1_o.png

这是自己写的古老的新人项目,入职第一周做的,要怎么运行写好就是了,python 也是一样的。

所以骂 python 没用,python 也有一样轻轻松松启动的项目,要怪就怪你这个同事。我运行 java 项目也摸索了很久不知道要怎么启动,c++ 也是各种依赖问题,说白了就是还菜(没有贬义,每个人都有新学东西的时候),还没入门,接手了不熟悉的语言就要运行要调试了,心态放好点都不至于这样。
simple2025
   13
simple2025  
   2023 年 12 月 13 日
因为 python 有 gil,所以 djanog runserver 就可以了啊,gunicorn 用进程模型的话,就相当于 master 负责起多个进程
simple2025
   14
simple2025  
   2023 年 12 月 13 日
python 像 tornado 想要利用多核,就是 supervisor 起多个进程,模型更简单粗暴
wizardyhnr
   15
wizardyhnr  
   2023 年 12 月 13 日
uwsgi+nginx+django 部署本来就是配置多个服务,这种多进程通信 debug 就很难了。楼主还选 docker 容器,docker 推荐一个容器一个服务,一个容器部署多个服务可能很多坑。楼主属于踩坑体质吧?
msg7086
   16
msg7086  
   2023 年 12 月 13 日
下次你试试看部署一下那种 2000 年前后写的带汇编的 C 项目到现代的平台。才折腾一天叫什么复杂。
光是把内嵌的 MMX 和 3dnow!汇编全部重写成 SSE/AVX 就得花掉你几星期(笑)
biaodianfu
   17
biaodianfu  
   2023 年 12 月 13 日   ❤️ 1
Django 没接触,不知道怎么部署还情有可原,Linux 命令也不熟悉,才得意自己的聪明才智,即使不知道使用 supervisor 守护进程,也应该知道使用 nohup 命令让程序不挂起。
wenrouxiaozhu
   18
wenrouxiaozhu  
   2023 年 12 月 13 日
@sadfQED2 用 Gunicon 吧👀...觉得“runserver 监听代码变化,随时重启,心里就觉得不舒服” ,可以后面加一个--noreload 😂
elboble
   19
elboble  
   2023 年 12 月 13 日
是略烦,反正 supervisor+uwsgi+nginx+django ,搞过一次就行了,路径什么的,的确文档说的不清楚,每次都是对着原来的例子改的。
dayeye2006199
   20
dayeye2006199  
   2023 年 12 月 13 日
chatgpt 糊个 dockerfile 很快的
tfdetang
   21
tfdetang  
   2023 年 12 月 13 日
@sadfQED2 ai 模型直接 runserver 会阻塞吧,并发请求还是会有问题的;
如果这种场景最好还是用 fastapi ; 可以找个 uvicorn + fastapi + docker 的模板项目改改就行了;
当然现在这样也不是不能用
sadfQED2
   22
sadfQED2  
OP
   2023 年 12 月 13 日 via Android
@tfdetang 啊?会阻塞吗?我等会试试,现在一次推理也就十多二十毫秒,可能机器够多,负载均衡后一直没发现问题

fastapi 能简单一点?你别忽悠我,我部署这玩意已经恶心吐了,换一个等会我又几天搞不出来。主要是这破玩意还要 GPU ,然后走公司部署系统又必须要 Dockerfile ,在 docker 里面搞显卡驱动 cuda 啥的我已经吐了
sadfQED2
   23
sadfQED2  
OP
   2023 年 12 月 13 日 via Android
@tfdetang 我测试了一下,不会阻筛,两个请求是并行的
nevermoreluo
   24
nevermoreluo  
   2023 年 12 月 13 日
哈哈哈哈哈 确实挺复杂的
去年闲时捡起了很多年前 python ,随便折腾也折腾了一下午 docker+uwsgi+django
https://github.com/nevermoreluo/kitchen/blob/main/docker-compose.yml
祝你好运吧
simple2025
   25
simple2025  
   2023 年 12 月 13 日
@sadfQED2 汗了,django 单进程,同步肯定阻塞啊,你不信,就去 sleep 看一下,就知道了,一般而已 python 要部署多个实例,
在 docker 之前就是用 supervisor 起多个进程, docker 时代应该是起多个实例
sadfQED2
   26
sadfQED2  
OP
   2023 年 12 月 13 日 via Android
@chenqh 我就是 sleep 测试的,sleep10 秒,同时发两个请求,两个都 10s 后正常返回
simple2025
   27
simple2025  
   2023 年 12 月 13 日
@sadfQED2 你不会是起了多个 docker 实例吧,还是说我的理解有问题?
sadfQED2
   28
sadfQED2  
OP
   2023 年 12 月 13 日
@chenqh #27
```
re_path("sleep",data.sleep)

def sleep(request):
time.sleep(10)
return HttpResponse(json.dumps({
"status": 1,
}))
```

python manage.py runserver 启动

开 2 个命令行,同时 curl 127.0.0.1:8000/sleep ,两个请求都是 10s 后同时返回
simple2025
   29
simple2025  
   2023 年 12 月 13 日   ❤️ 1
simple2025
   30
simple2025  
   2023 年 12 月 13 日
@sadfQED2 我的,我用 tornado 来理解 django 了
KJR5OR04CnCiWf02
   31
KJR5OR04CnCiWf02  
   2023 年 12 月 13 日
楼主在做什么 ai 应用?感觉是个大怨种。
XxxxD
   32
XxxxD  
   2023 年 12 月 13 日
uwsgi 文档感觉好久都没更新,可以 youtube 搜下搭配 Gunicorn 部署
fantathat
   33
fantathat  
   2023 年 12 月 13 日
确实复杂,用 gunicorn 涉及到 wsgi, 需要导出 application?
iorilu
   34
iorilu  
   2023 年 12 月 14 日
生成环境不要设折腾, 只要能跑就不要动
IurNusRay
   35
IurNusRay  
   2023 年 12 月 14 日
你的 uwsgi.ini 文件是不是配置了 daemonize , 这种模式 uwsgi 主进程开启子进程后会退出,于是 docker 容器也会停止,改成 logto 就可以
tfdetang
   36
tfdetang  
   2023 年 12 月 14 日
@sadfQED2 看来 django 默认开启了多线程; 其实 docker 里不用搞显卡驱动啥的,base 镜像直接用 torch 啥的官方 gpu 版本的镜像,后面只要把 python 的部分搞定就行了
sanzrolee
   37
sanzrolee  
   2023 年 12 月 14 日
uvicom + supervisor 嘎嘎香,再套层 docker 容器在最外层也可以。
julyclyde
   38
julyclyde  
   2023 年 12 月 15 日
uwsgi 难道没有“前台运行”功能吗?
干嘛用 tail 来保活?

那你用了 tail ,将来运行 docker kill 的时候,你让 tail 命令去被 kill 么?
julyclyde
   39
julyclyde  
   2023 年 12 月 15 日
你想要的那种“只上传应用程序本身,但是不管运行机制”其实在 python 世界也是存在的
就是 google appengine 、sina appengine 、heroku 那一类

python 、nodejs 、java 比较像,都是“由该语言本身写一个服务器”来运行自己
julyclyde
   40
julyclyde  
   2023 年 12 月 15 日
还有,如果你们的数据库是 sqlite ,将来可能扩容到多实例的时候会遇到问题
julyclyde
   41
julyclyde  
   2023 年 12 月 15 日
@sadfQED2 大几十台机器不一定过 20 啊
你知道不,东南亚某知名电子商务网站,在 99 大促销的时候,曾经有关键组件“高达四十八 QPS”,比平时翻两番呢

你 AI 模型的运行速度,浏览器能等得了么?回头估计还得加个 celery
Maerd
   42
Maerd  
   2023 年 12 月 20 日
比较好奇 一个接口为什么要用 django,而不是用更方便的 fastapi
Xs2y6914BljWqNfl
   43
Xs2y6914BljWqNfl  
   2024 年 2 月 6 日
@Maerd 完全看个人喜好的
推荐学习书目
› Learn Python the Hard Way
Python Sites
› PyPI - Python Package Index
› http://diveintopython.org/toc/index.html
› Pocoo
值得关注的项目
› PyPy
› Celery
› Jinja2
› Read the Docs
› gevent
› pyenv
› virtualenv
› Stackless Python
› Beautiful Soup
› 结巴中文分词
› Green Unicorn
› Sentry
› Shovel
› Pyflakes
› pytest
Python 编程
› pep8 Checker
Styles
› PEP 8
› Google Python Style Guide
› Code Style from The Hitchhiker's Guide
© 2026 V2EX · 104ms · 3.9.8.5