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。现在它又开始工作了,我很高兴。
这是关于什么的
我正在寻找一种可能性来简化我服务器上 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。现在它又开始工作了,我很高兴。