182013
 

Django是一个高效,灵活,动态的Web应用开发框架。在Django刚开始流行的时候,大多数推荐的Django运行环境配置都是基于使用mod_wsgi模块的Apache。而近来大家所推荐的关于更高级的Django运行环境配置则更加高效和具有弹性,但同时也更加复杂,使用的工具包括:Nginx, Gunicorn, virtualenv, supervisord和PostgreSQL.

在这篇文章中我会解释如何在Linux上将这些组件组合起来,成为一个能够运行django的服务器。

预置条件:

首先我假设你有一台具有Root权限的服务器,我正在使用的Linux发行版是debian7,所以以下的内容也同样适用于Ubuntu或者其他基于Debian的Linux发行版。如果你是在使用基于RPM的Linux发行版(比如说CentOS),你需要用yum替换掉以下命令中提到的apt-get,如果你在使用FreeBSD,你可以使用Ports安装这些组件。

如果你暂时没有服务器,那么我推荐你使用Linode的VPS,虽然价格稍贵,但是各项服务及服务器性能都是最佳的。如果你使用我提供的链接购买Linode,我会获得一点推荐佣金。

同样的我也假设你已经将你的域名通过DNS指向了你的服务器IP,而你的域名是example.com。

升级系统:

首先我们需要确定我们的系统是否是最新的。

$ sudo apt-get update
$ sudo apt-get upgrade

PostgreSQL

在基于Debian的系统上运行以下命令安装PostgreSQL

$ sudo apt-get install postgresql postgresql-contrib

创建一个数据库以及拥有该数据库权限的用户

$ sudo su - postgres
postgres@django:~$ createdb hello
postgres@django:~$ createuser -P
Enter name of role to add: hello_django
Enter password for new role:
Enter it again:
Shall the new role be a superuser? (y/n) n
Shall the new role be allowed to create databases? (y/n) n
Shall the new role be allowed to create more new roles? (y/n) n
postgres@django:~$ psql
psql (9.1.9)
Type "help" for help.
postgres=# GRANT ALL PRIVILEGES ON DATABASE hello TO hello_django;
GRANT
postgres=# \q
postgres@django:~$ logout
$

对于习惯使用Mysql的同学,这里也可以安装Mysql来替换PostgreSQL,运行以下命令安装Mysql

$ sudo apt-get install mysql-server

Mysql的安全设置

$ mysql_secure_installation

按照提示一步一步进行即可

如果你需要修改Mysql的Root密码,那么运行以下命令:

$ dpkg-reconfigure mysql-server-5.0

进入Mysql控制台

$ mysql -uroot -p

创建数据库和拥有该数据库权限的用户

CREATE DATABASE hello;
CREATE USER 'example_user' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON hello.* TO 'example_user';
exit

安装virtualenv然后为你的django应用创建一个运行环境

Virtualenv是一个能够允许你在系统中创建隔离的Python环境的工具。这使你能够在同一台服务器上运行需要不同设置的应用程序(例如,一个基于Django1.2,另一个基于Django1.5)。Virtualenv在debian系统上很容易安装:

$ sudo apt-get install python-virtualenv

为你的应用创建并激活一个虚拟环境

因为django的特性,你可以在任何地方创建你的虚拟环境目录,我这里是在/webapps/目录下创建,如果你习惯使用类似于/var/www/的目录或者其他目录,只需要替换掉/webapps/就行。

$ cd /webapps/
$ virtualenv hello_django
New python executable in hello_django/bin/python
Installing distribute.............................done
Installing pip........................................done
$ cd hello_django
$ source bin/activate
(hello_django) $

看到上面的提示符时,就表明你的虚拟环境已经激活,然后你就可以在里面安装Django了。在安装的时候你可以看到pip已经被安装到了虚拟环境中,所以你可以直接使用pip来安装需要的python组件。

(hello_django) $ pip install django
Downloading/uppacking django
(...)
Installing collected packages: django
(...)
Successfully installed django
Cleaning up...

现在你的Django虚拟环境应该已经可以使用了,创建一个空的Django项目试试看。

(hello_django) $ django-admin.py startproject hello

你可以使用开发服务器来测试一下

(hello_django) $ cd hello
(hello_django) $ python manage.py runserver example.com:8000

使用http://example.com:8000来访问服务器试一下,在这之前,请确保你的服务器防火墙开了8000端口。

设置PostgreSQL在Django下工作

要在Django下使用PostgreSQL,你需要在虚拟环境中安装psycopg2数据库适配器,这一步需要原生扩展编译,如果没法找到头文件、使用libpq(用来与Postgres通信的库)链接C程序的静态库和创建Python模块的python开发库(python-dev package),编译将会失败。所以我们必须先安装这些依赖包,然后再使用PIP安装psycopg2。

安装依赖包

$ sudo apt-get install libpq-dev python-dev

安装psycopg2数据库适配器

(hello_django) $ pip install psycopg2

在你的django项目settings.py文件中修改数据库连接设置,这一步在默认的settings.py文件中有详细的注释,就不在此列出了。

使用Django初始化数据库

(hello_django) $ python manage.py syncdb

P.S. 如果你使用了MySQL作为数据库,那么你需要安装Python-MySQL来使python程序能够访问mysql,具体安装部骤网上很多,可以自行google一下。

Gunicorn

在生产环境中我们肯定不会使用Django的单线程开发服务器,而是使用一个专用的应用服务器,叫作Gunicorn。
在你的应用虚拟环境中安装Gunicorn

(hello_django) $ pip install gunicorn
Downloading/unpacking gunicorn
Downloading gunicorn-0.17.4.tar.gz (372Kb): 372Kb downloaded
Running setup.py egg_info for package gunicorn
Installing collected packages: gunicorn
Running setup.py install for gunicorn
Installing gunicorn_paster script to /webapps/hello_django/bin
Installing gunicorn script to /webapps/hello_django/bin
Installing gunicorn_django script to /webapps/hello_django/bin
Successfully installed gunicorn
Cleaning up...

Ok,现在你已经这安装好了Gunicorn,尝试测试一下Gunicorn和Django是否可以正常工作

(hello_django) $ gunicorn_django --bind example.com:8001

在浏览器中访问http://example.com:8001,看看django是否正常工作。
到现在为止,Gunicorn已经安装好,并且已经可以和django一起正常工作了,接下来让我们来做一些设置让gunicorn更加好用一些。我喜欢设置一些参数,所以我们可以把它们放在一个BASH脚本里,我将这个脚本保存在bin/gunicorn_start。
bin/gunicorn_start

#!/bin/bash
NAME="hello_app" # Name of the application
DJANGODIR=/webapps/hello_django/hello # Django project directory
SOCKFILE=/webapps/hello_django/run/gunicorn.sock # we will communicte using this unix socket
USER=michal # the user to run as
GROUP=michal # the group to run as
NUM_WORKERS=3 # how many worker processes should Gunicorn spawn
DJANGO_SETTINGS_MODULE=hello.settings # which settings file should Django use

echo "Starting $NAME"

# Activate the virtual environment
cd $DJANGODIR
source ../bin/activate
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DJANGODIR:$PYTHONPATH

# Create the run directory if it doesn't exist
RUNDIR=$(dirname $SOCKFILE)
test -d $RUNDIR || mkdir -p $RUNDIR

# Start your Django Unicorn
# Programs meant to be run under supervisor should not daemonize themselves (do not use --daemon)
exec ../bin/gunicorn_django \
--name $NAME \
--workers $NUM_WORKERS \
--user=$USER --group=$GROUP \
--log-level=debug \
--bind=unix:$SOCKFILE

接下来将gunicorn_start脚本设置为可执行

$ chmod u+x bin/gunicorn_start

运行以下命令来测试gunicorn_start是否正常

$ ./bin/gunicorn_start
Starting hello_app
2013-06-09 21:14:07 [2792] [INFO] Starting gunicorn 0.17.4
2013-06-09 21:14:07 [2792] [DEBUG] Arbiter booted
2013-06-09 21:14:07 [2792] [INFO] Listening at: unix:/webapps/hello_django/run/gunicorn.sock (2792)
2013-06-09 21:14:07 [2792] [INFO] Using worker: sync
2013-06-09 21:14:07 [2798] [INFO] Booting worker with pid: 2798
2013-06-09 21:14:07 [2799] [INFO] Booting worker with pid: 2799
2013-06-09 21:14:07 [2800] [INFO] Booting worker with pid: 2800

注意gunicorn_start中的参数设置,你需要修改里面的参数以适合你自己的设置。
根据经验(as a rule-of-thumb),通过以下公式来设置 –worker(NUM_WORKERS):
2 * CPUs + 1。
–name(NAME)参数指定你如何在程序中识别你的应用。默认值为gunicorn,如果你不修改的话,当你的服务器中有多个gunicorn驱动的应用时会使应用难以区分。
为了使–name参数起作用,你需要安装一个叫做setproctitle的Python模块。在你的系统中安装python-dev依赖包然后再安装setproctitle。

$ sudo apt-get install python-dev
(hello_django) $ pip install setproctitle

现在你可以将进程都列出来,你应该可以看到哪个gunicorn进程属于哪个应用。

$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
(...)
michal 16124 0.0 1.9 56168 9860 ? S 15:37 0:00 gunicorn: master [hello_app]
michal 16130 0.0 4.5 73520 23004 ? S 15:37 0:00 gunicorn: worker [hello_app]
michal 16131 0.0 4.5 73496 23004 ? S 15:37 0:00 gunicorn: worker [hello_app]
michal 16132 0.0 4.5 73504 23004 ? S 15:37 0:00 gunicorn: worker [hello_app]

使用Supervisor来启动和监测应用

现在gunicorn_start脚本已经可以正常工作了,下面我们需要让它在开机时自启动,或者在某些情况下能够正常重启。我们使用supervisor来处理这些任务。
安装非常简单:

$ sudo apt-get install supervisor

当supervisor安装好后,你可以在/etc/supervisor/conf.d目录下创建配置文件来管理gunicorn。下面是为hello这个应用创建的一个配置文件
/etc/supervisor/conf.d/hello.conf

[program:hello]
command = /webapps/hello_django/bin/gunicorn_start ; Command to start app
user = michal ; User to run as
stdout_logfile = /webapps/hello_django/logs/gunicorn_supervisor.log ; Where to write log messages
redirect_stderr = true ; Save stderr in the same log

当然你还可以设置其他的选项,但是基础配置已经足够了。
保存好后,告诉supervisor重新读取配置文件并更新(这将会启动你刚注册的应用)

$ sudo supervisorctl reread
hello: available
$ sudo supervisorctl update
hello: added process group

你也可以使用supervisor检查你的应用的状态,或者启动、停止应用。

$ sudo supervisorctl status hello
hello RUNNING pid 18020, uptime 0:00:50
$ sudo supervisorctl stop hello
hello: stopped
$ sudo supervisorctl start hello
hello: started
$ sudo supervisorctl restart hello
hello: stopped
hello: started

现在,你的应用将可以在系统重启之后自动启动,或者在由于某些原因发生错误时自动重启。

Nginx

现在是时候为我们的应用和静态文件配置Nginx服务了,安装并启动Nginx:

$ sudo apt-get install nginx
$ sudo service nginx start

在浏览器中访问你的服务器(http://example.com)。你应该可以看到nginx的欢迎界面-“Welcome to nginx”。
每一个Nginx虚拟服务器配置文件应该放在/etc/nginx/sites-available/目录下,你可以选择将你想要启用的站点配置文件符号连接至/etc/nginx/sites-enabled/目录下。
在/etc/nginx/sites-available/目录下创建一个新的nginx服务器配置文件。一般来说文件应该包含下面这些配置,如果你需要更详细的配置说明,请看这里:
https://github.com/benoitc/gunicorn/blob/master/examples/nginx.conf
/etc/nginx/sites-available/hello

upstream hello_app_server {
# fail_timeout=0 means we always retry an upstream even if it failed
# to return a good HTTP response (in case the Unicorn master nukes a
# single worker for timing out).

server unix:/webapps/hello_django/run/gunicorn.sock fail_timeout=0;

server {
listen 80;
server_name example.com;

client_max_body_size 4G;

access_log /webapps/hello_django/logs/nginx-access.log;
error_log /webapps/hello_django/logs/nginx-error.log;
location /static/ {
alias /webapps/hello_django/static/;
}
location /media/ {
alias /webapps/hello_django/media/;
}

location / {
# an HTTP header important enough to have its own Wikipedia entry:
# http://en.wikipedia.org/wiki/X-Forwarded-For
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

# enable this if and only if you use HTTPS, this helps Rack
# set the proper protocol for doing redirects:
# proxy_set_header X-Forwarded-Proto https;

# pass the Host: header from the client right along so redirects
# can be set properly within the Rack application
proxy_set_header Host $http_host;

# we don't want nginx trying to do something clever with
# redirects, we set the Host: header above already.
proxy_redirect off;

# set "proxy_buffering off" *only* for Rainbows! when doing
# Comet/long-poll stuff. It's also safe to set if you're
# using only serving fast clients with Unicorn + nginx.
# Otherwise you _want_ nginx to buffer responses to slow
# clients, really.
# proxy_buffering off;

# Try to serve static files from nginx, no point in making an
# *application* server like Unicorn/Rainbows! serve static files.
if (!-f $request_filename) {
proxy_pass http://hello_app_server;
break;
}
}

# Error pages
error_page 500 502 503 504 /500.html;
location = /500.html {
root /webapps/hello_django/static/;
}
}
重启Nginx
$ sudo service nginx restart

现在再访问http://example.com你应该要以看到django的欢迎界面了。

如果你在以上的配置中发现任何问题,可以在评论中留言。

最终的目录结构:

/webapps/hello_django/
├── bin <= Directory created by virtualenv
│ ├── activate <= Environment activation script
│ ├── django-admin.py
│ ├── gunicorn
│ ├── gunicorn_django
│ ├── gunicorn_start <= Script to start application with Gunicorn
│ └── python
├── hello <= Django project directory, add this to PYTHONPATH
│ ├── manage.py
│ ├── project_application_1
│ ├── project_application_2
│ └── hello <= Project settings directory
│ ├── __init__.py
│ ├── settings.py <= hello.settings - settings module Gunicorn will use
│ ├── urls.py
│ └── wsgi.py
├── include
│ └── python2.7 -> /usr/include/python2.7
├── lib
│ └── python2.7
├── lib64 -> /webapps/proxydemo/lib
├── logs <= Application logs directory
│ ├── gunicorn_supervisor.log
│ ├── nginx-access.log
│ └── nginx-error.log
├── media <= User uploaded files folder
├── run
│ └── gunicorn.sock
└── static <= Collect and serve static files from here

卸载django应用

如果你需要卸载掉你的django应用,按照以下步骤

移除Nginx sites-enabled文件夹中的虚拟服务器配置文件

$ sudo rm /etc/nginx/sites-enabled/hello_django

重启Nginx

$ sudo service nginx restart

如果你不想再次使用该应用,你可以从sites-available文件夹中删除掉真实的配置文件

$ sudo rm /etc/nginx/sites-available/hello_django

使用supervisor停止应用

$ sudo supervisorctl stop hello

从supervisor的控制脚本目录中移除应用

$ sudo rm /etc/supervisor/conf.d/hello.conf

如果你真的不想再使用这个应用了,哥们,你肯定是受到什么打击了。你可以在webapps中移除整个目录:

$ sudo rm -rf /webapps/hello_django

原文链接:http://michal.karzynski.pl/blog/2013/06/09/django-nginx-gunicorn-virtualenv-supervisor/