自动部署Django项目详解(3)

在上一篇自动部署Django项目详解使用Python编写Git Hooks,笔者直接通过Python模拟正常的人肉linux命令来确定python debug server是否在指定端口运行,如果正在运行则先杀掉该进程,在更新了Git仓库之后再人肉启动python debug server。

咦,好像有哪里不对,为什么不直接删掉文件,然后进程不就自动结束了吗?这样子就不用检查端口是否有进程在运行了。

相信大家都试过,在linux下如果先开启python debug server进程,然后把进程的相关文件都删掉,而进程还能正常运行。这是因为linux下的删除(rm)其实是减少对文件的link数目,虽然删除了文件,但是打开的进程还保持着对文件的一个link,因此在执行了rm之后文件并不会被立即删除,只有link数为0的时候才会被删除。

因此,笔者希望在服务器上运行一个进程管理工具监控Git仓库,每当仓库更新的时候,进程管理工具就自动重启python debug server,而Git Hooks只要负责仓库的更新就可以了。

在Python的进程管理工具中,supervisor应该是比较广为人知,而uWSGI emperor的曝光度似乎并不太高,然而基于nginx+uwsgi+django的标配,笔者还是对uWSGI emperor的折腾比较期待的。
uWSGI文档传送门:Quickstart for Python/WSGI applications

准备 配置文件uwsgi.ini

首先新建一个名为uwsgi_test的Django项目:

uwsgi_test ├── manage.py ├── uwsgi_test │ ├── __init__.py │ ├── __init__.pyc │ ├── settings.py │ ├── settings.pyc │ ├── urls.py │ ├── urls.pyc │ ├── wsgi.py │ └── wsgi.pyc └── uwsgi_test.ini

uwsgi_test.ini配置如下:

[uwsgi] chdir = /path/to/uwsgi_test module = uwsgi_test.wsgi master = true processes = 4 http = :8080 vaccum = true

当在Mac系统上运行如下的uwsgi的启动命令之后就能访问浏览器的8080端口并看到Django的默认欢迎界面了。

uwsgi --ini uwsgi_test.ini

在以上的配置中生成了一个主进程和四个进程,以及一个Http路由(Http Router)进程,其中主进程负责当4个进程中有进程die的时候重新生成一个进程,而Http Router进程则负责将请求转发给WSGI Application。

*** Operational MODE: preforking *** WSGI app 0 (mountpoint='') ready in 0 seconds on interpreter 0x7f9c5ae000d0 pid: 8514 (default app) *** uWSGI is running in multiple interpreter mode *** spawned uWSGI master process (pid: 8514) spawned uWSGI worker 1 (pid: 8515, cores: 1) spawned uWSGI worker 2 (pid: 8516, cores: 1) spawned uWSGI worker 3 (pid: 8517, cores: 1) spawned uWSGI worker 4 (pid: 8518, cores: 1) spawned uWSGI http 1 (pid: 8519) 配置选项:http,socket与http-socket 在centos系统上运行配置文件

当笔者在centos系统上部署相同的项目和配置文件时,uWSGI却报了一个奇怪的错误。

The -s/--socket option is missing and stdin is not a socket.

笔者在上面使用的明明是http选项,为什么会出现socket选项呢?
这是因为不同的linux发行版的包安装工具所安装的uWSGI,有时候会以模块的方式安装,并且在运行的时候默认不会加载这些模块,比如http选项就需要http的plugin。因此官方建议下载uWSGI的源码下来自行build。
uWSGI官方文档解释如下:

Installing uWSGI with Python support
When you start learning uWSGI, try to build from official sources: using distribution-supplied packages may bring you plenty of headaches. When things are clear, you can use modular builds (like the ones available in your distribution).

Installing via your package distribution is not covered (would be impossible to make everyone happy), but all of the general rules apply.

One thing you may want to take into account when testing this quickstart with distro-supplied packages, is that very probably your distribution has built uWSGI in modular way (every feature is a different plugin that must be loaded). To complete this quickstart, you have to prepend –plugin python,http to the first series of examples, and –plugin python when the HTTP router is removed (if this doesn’t make sense to you, just continue reading).

因此,在ini配置文件中加上:

plugin = python, http

就能解决这个问题了。

uWSGI emperor

OK,在前面的介绍中,uWSGI终于能正常运行了。下面介绍正餐emperor模式吧。

emperor翻译为中文的意思其实就是皇帝的意思,那么既然有皇帝,那就肯定有“臣子”(vassals),其中“臣子”就是指实际运行的一个app实例,在这里就是uwsgi_test.ini配置文件了。

emperor模式开启的命令是:

sudo uwsgi --emperor /path/to/vassals/

其中,vassals文件夹里包含了各个app的配置文件,这个文件夹将会被emperor一直监视,只要有配置文件的修改或新建,app实例就会被重新加载或新建,可以通过软链接将实际项目中的配置文件链接到vassal文件夹目录下:

ln -s /path/to/uwsgi_test.ini /path/to/vassals/

uWSGI官方文档展示了uWSGI emperor的功能:

Whenever an imperial monitor detects a new configuration file, a new uWSGI instance will be spawned with that configuration.

Whenever a configuration file is modified (its modification time changed, so touch –no-dereference may be your friend), the corresponding app will be reloaded.

Whenever a config file is removed, the corresponding app will be stopped.

If the emperor dies, all the vassals die.

If a vassal dies for any reason, the emperor will respawn it.

在文档中,emperor监视的是配置文件目录,但是问题来了,笔者希望每次Git仓库更新一次就重新启动实例,而如果这次更新并没有对配置文件进行修改,实例自然就不会重新启动了。
幸好配置文件提供了touch-reload选项,只要指定文件夹发生改动就重启实例:

touch-reload = /path/to/uwsgi_test # or touch-reload = .git/index

最后一个问题,在上一篇 自动部署Django项目详解(一):开发配置与生产配置中,笔者通过环境变量来确定Django配置的加载,因此在uWSGI的配置文件中还需要加上对环境变量的添加:

env = DJANGO_PRODUCTION_SETTINGS=TRUE

最后,使用nohup命令启动uWSGI emperor即可实现进程管理(别忘了Git Hooks需修改为只拉取仓库更新)

完整的配置 [uwsgi] plugin = python, http env = DJANGO_PRODUCTION_SETTINGS=TRUE chdir = /path/to/uwsgi_test module = umefit.wsgi master=True processes = 4 http = :8080 vaccum=True touch-reload = /path/to/uwsgi_test

OK,搞定。

Django 的详细介绍请点这里
Django 的下载地址请点这里

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/0c92a39958122c372d5deaf8b6be9c2a.html