Simplified/PHP/CGI like django应用部署

Simplified/PHP/CGI alike django application deployment

这是关于什么的

我正在寻找一种可能性来简化我服务器上 Django 应用程序的部署。目前我为每个应用程序使用一个 uWSGI 实例。每当我将新项目上传到我的 www-root 文件夹时,我都不想弄乱配置文件。相反,我正在寻找一个更 php 相似的解决方案,我可以在其中将项目文件夹上传到我的 www-root 并通过 nginx-> uWSGI 或 nginx-> Gunicorn "automatically" 访问它,而不必修改一个配置文件。另外最好不要为每个应用程序设置一个进程,这样我就不会浪费内存 (因为我一次从不使用多个应用程序).

当前状态

为此我发现,uWSGI 的 emperor mode for django applications in combination with magic variables 可能有效。但是在我的配置中,只有一个 django 应用程序的设置会被加载并保持加载状态,因此其他应用程序无法启动。

来自 uwsgi.conf.template:

[uwsgi]
master             =  true
socket             =  :8000
master             =  true
reuse-port         =  true
reload-os-env      =  true
vaccuum            =  true
logto              =  /var/log/uwsgi-%n.log
manage-script-name =  true
chdir              =  /usr/local/www/%n
mount              =  /%n=%n/wsgi.py

来自 nginx.conf:

location ~ ^/(.+)/(.+?)$
{
   include uwsgi_params;
   uwsgi_pass 10.0.0.106:8000;
   uwsgi_param UWSGI_SCRIPT .wsgi;
   uwsgi_param SCRIPT_NAME /;
   uwsgi_param UWSGI_CHDIR /usr/local/www/;
   uwsgi_param PATH_INFO "/"; # strip path
 }


 location ~ ^/(.+)/$
 {
   include uwsgi_params;
   uwsgi_pass 10.0.0.106:8000;
   uwsgi_param UWSGI_SCRIPT .wsgi;
   uwsgi_param SCRIPT_NAME ;
   # uwsgi_param UWSGI_APPID /;
   uwsgi_param DJANGO_SETTINGS_MODULE .settings;
   uwsgi_param UWSGI_CHDIR /usr/local/www/;
   uwsgi_param PATH_INFO '';
 }

在又一天的摆弄之后,我找到了一个可行的解决方案。这不会是最终的解决方案,但它现在可以使用,每当我再次改进此配置时,我都会尝试更新此答案。

基本配置

这与 documentation 中的内容有些接近。尽管如此,我还是发现它很难以这种方式工作。

nginx.conf

server
{
  server_name test.example.com;
  listen [::]:80;

  location ~ ^/(.+)/static/(.+)$
  { alias /usr/local/www//static/; }

  location ~ ^/(.+)/media/(.+)$
  { alias /usr/local/www//media/; }

  location ~ ^/(.*?)/
  {
    uwsgi_pass unix:///var/run/uwsgi/.sock;
    include uwsgi_params;        
  }
}

/usr/local/www/uwsgi.skel

[uwsgi]
master             =  true
socket             =  /var/run/uwsgi/%c.sock
reuse-port         =  true
master             =  true
reload-os-env      =  true
vaccuum            =  true
logto              =  /var/log/uwsgi/%c.log
manage-script-name =  true
chdir              =  /usr/local/www/%c
touch-reload       =  /usr/local/www/%c/%c
wsgi-file          =  %c/wsgi.py
mount              =  /%c=%c/wsgi.py
static-map         =  /static=/usr/local/www/%c/static
static-map         =  /media=/usr/local/www/%c/media
unenv              =  DJANGO_SETTINGS_MODULE
unenv              =  DJANGO_SETTINGS
wsgi-env-behaviour =  holy
print              =  we are using %c

我们必须为套接字和日志文件创建所需的文件夹,并注意必要的权限(另见下文)。另请注意,/var/run/ 可能无法在您的 OS 上重新启动,因此另一个文件夹可能更适合:

chmod -R www:www /usr/local/www
mkdir /var/log/uwsgi/
chmod -R www:www /var/log/uwsgi/
mkdir /var/run/uwsgi/
chmod -R www:www /var/run/uwsgi/

正在启动 uWSGI 主实例...

我们现在可以在 emperor 模式下启动 uwsgi 进程,即使在 emperor-tyrant 模式下也是如此:

uwsgi --emperor 'glob:///usr/local/www/*/uwsgi.ini' --emperor-nofollow --emperor-tyrant \
--master --thunder-lock --enable-threads

这是我使用的一个技巧:glob 将尝试从 /usr/local/www/ 下的每个目录中吸取一个名为 uwsgi.ini 的文件。它可能是一个单独的文件,但我只是从上面链接了 skel 文件 (这满足了我不必编辑配置文件的要求):

cd /usr/local/www/django-app1/
ln -s ../uwsgi.skel uwsgi.ini

这也很方便,因为 GIT 的最新版本也支持符号链接,因此我的开发机器上的符号链接可以在 uwsgi.skel 文件中具有其他值(例如,不是 /usr/local/www但是 /var/www/)

关于权限和 'emperor-tyrant' 模式的说明...

皇帝-暴君模式将使uWSGI spawn processes 由不同的用户拥有。哪个用户取决于 uwsgi.ini 文件的权限。然后 uWSGI 进程放弃它的特权并在该文件所属的用户名下运行。我还不需要该功能,但如果您尝试设置专业的托管平台,您将需要它。为此,请记住,nginx 必须具有足够的权限来读取和写入生成的套接字文件,并且 /var/run/uwsgi/ 也必须对所有这些用户都是可写的。

设置虚拟环境

在大约一年没有出现任何问题后,我发现我的一个站点处于非运行状态。事实证明,这是由于 python3 的更新所致。简而言之:我不得不 fiddle 一点,因为为其中一个站点设置虚拟环境并不是那么简单,因为在将 virtualenv = 添加到之后我总是遇到 No module named site 错误我的 uwsgi.ini。我的新 ini 文件现在看起来像这样:

/usr/local/www/project/uwsgi.ini

[uwsgi]
master             =  true
socket             =  /var/run/uwsgi/%c.sock
reuse-port         =  true
reload-os-env      =  true
vaccuum            =  true
manage-script-name =  true

logto              =  /var/log/uwsgi/%c.log
virtualenv         =  /usr/local/www/katalogpro/venv/
chdir              =  /usr/local/www/%c
touch-reload       =  /usr/local/www/%c/%c

mount              =  /%c=%c/wsgi.py
static-map         =  /static=/usr/local/www/%c/static
static-map         =  /media=/usr/local/www/%c/media
print              =  we are using %c

# set cheaper algorithm to use, if not set default will be used
cheaper-algo     = backlog
cheaper-overload = 4
cheaper-idle     = 1
cheaper-initial  = 0

注意,它变得更容易一些,因为其中的设置更少。可以进一步调整它并使用配置作为 .skel-configuration with if 语句,如果有的话,它会自动添加一个 virtualenv。现在它又开始工作了,我很高兴。