Nginx+Gunicorn+virtualenv+supervisord+Postgresql部署Django應用

關於Django應用部署


Django是一個高效、多功能和動態地進化的Web應用開發框架。目前比較流行的部署、運行Django應用方式是基於Apache的mod_wsgi模塊,但更加高效、彈性,同時又更加複雜的方式是使用以下工具來部署實施:Nginx、Gunicorn、virtualenv、supervisord、Postgresql。以下詳細介紹如何結合這些工具來部署Django應用到Linux上。


準備工作


需要有一臺擁有root權限的Linux服務器,這是部署應用的平臺。本文采用CentOS,域名直接使用localhost,ip地址爲192.168.56.1。

使用yum在線升級機制來更新系統:

yum update -y


PostgreSQL


使用PostgreSQL來作爲Django應用的後臺數據庫,在CentOS上安裝:

yum install postgresql-contrib postgresql postgresql-server postgresql-devel


創建應用的數據庫用戶django和數據庫hello_django:

su - postgres

createuser -P

    Enter name of role to add: 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

createdb --owner django hello_django

logout


爲應用添加系統用戶


爲Django應用創建專門的系統用戶,並加入django_webapps羣組:

groupadd django_webapps

useradd -g django_webapps -d /django_webapps/hello_django django


創建應用的Python虛擬環境


創建django_webapps目錄來保存web apps,創建hello_django目錄存儲應用,並修改應用目錄的擁有者:

mkdir -p /django_webapps/hello_django/

chown django /django_webapps/hello_django/


在應用目錄創建虛擬環境,以django用戶來創建:

su - django

cd /django_webapps/hello_django/

virtualenv .

激活虛擬環境:

source bin /activate

安裝django:

pip install django


創建一個空的django項目,項目名爲hello:

django-admin.py startproject hello


運行django自帶的服務器來測試:

cd hello

python manage.py runserver localhost:8000

Validating models...

0 errors found
June 14, 2014 - 03:28:01
Django version 1.6.5, using settings 'hello.settings'
Starting development server at http://localhost:8000/
Quit the server with CONTROL-C.

登錄http://localhost:8000 ,可查看到django的歡迎頁面。


允許其他用戶對應用目錄寫使能


應用是以django用戶來運行的,該用戶具有應用目錄的所有權限。如果想讓其他的常規用戶也能夠修改應用文件,那麼可以設置羣組users爲該目錄的羣擁有者,並賦予users寫權限:

chown -R django:users /django_webapps/hello_django

chmod -R g+w /django_webapps/hello_django


將django加入users羣組中,並檢查:

usermod -a -G users `whoami`

id

uid=507(django) gid=510(django_webapps) groups=510(django_webapps),100(users)


配置PostgreSQL


爲了在Django中使用PostgrelSQL,需要安裝psycopg2。在安裝psycopg2之前需要安裝python-devel,以保證能構建python模塊:

yum install python-devel


在虛擬環境中使用pip安裝psycopg2數據庫適應器:

pip install psycopg2


修改settings.py文件來配置數據庫:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'hello_django',
        'USER': 'django',
        'PASSWORD': '131415',    #此處最好使用密鑰,可通過md5來加密
        'HOST': 'localhost',
        'PORT': '',            #set to empty string for default
    }
}


最後構建Django的初始化數據庫:

python manage.py syncdb


註解:構建過程中會出現error:IDENT authentication failed for user “django”

出現這個問題是因爲PostgreSQL的Client Authentication 使用了ident authentication。
通過修改pg_hba.conf可以解決,編輯/var/lib/pgsql/data/pg_hba.conf,修改爲:

# TYPE  DATABASE    USER        CIDR-ADDRESS          METHOD

# "local" is for Unix domain socket connections only
local   all         all                               trust
# IPv4 local connections:
host    all         all         127.0.0.1/32          trust
# IPv6 local connections:
host    all         all         ::1/128               trust


Gunicorn


在生產環境中,我們將不會使用Django自帶的單線程的開發服務器,而是使用專門的Python WSGI 應用服務器——gunicorn,在本博的另一篇文章中有對gunicorn的詳細介紹:Gunicorn

首先在你的應用的虛擬環境中安裝gunicorn:

pip install gunicorn


安裝成功後可以測試下gunicorn是否可以運行Django 應用,在項目hello目錄下運行以下命令:

(hello_django)[django@rango hello]$ gunicorn hello.wsgi:application --bind localhost:8001

通過訪問http://localhost:8001 ,可以訪問到你的Gunicorn服務器。此處特意將端口從8000改爲8001是爲了迫使瀏覽器建立一個新的連接。


Gunicorn現在已經準備好運行你的app,現在可以配置一些選項來使得Gunicorn更加有用。此處通過編寫一個shell腳本來設置一些參數,腳本保存爲/django_webapps/hello_django/bin/gunicorn_start:

#!/bin/bash

NAME="hello_app"    # Name of the application
DJANGODIR=/django_webapps/hello_django/hello    #Django project directory
SOCKFILE=/django_webapps/hello_django/run/gunicorn.sock    #unix socket fro communication

USER=django                     # the user to run as
GROUP=django_webapps                     # the group to run as
NUM_WORKERS=5         # how many worker processes should Gunicorn spawn
DJANGO_SETTINGS_MODULE=hello.settings # which settings file should Django use
DJANGO_WSGI_MODULE=hello.wsgi                 # WSGI module name
 
echo "Starting $NAME as `whoami`"
 
# 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_WSGI_MODULE}:application \
    --name $NAME \
    --workers $NUM_WORKERS \
    --user=$USER --group=$GROUP \
    --log-level=debug \
    --bind=unix:$SOCKFILE


爲該腳本增加可執行權限:

chmod u+x bin/gunicorn_start


以用戶django的身份來運行這個腳本:

su - django

bin/gunicorn_start

Starting hello_app as django
2014-06-15 15:17:20 [18037] [INFO] Starting gunicorn 18.0
2014-06-15 15:17:20 [18037] [DEBUG] Arbiter booted
2014-06-15 15:17:20 [18037] [INFO] Listening at: unix:/django_webapps/hello_django/run/gunicorn.sock (18037)
2014-06-15 15:17:20 [18037] [INFO] Using worker: sync
2014-06-15 15:17:20 [18048] [INFO] Booting worker with pid: 18048
2014-06-15 15:17:20 [18049] [INFO] Booting worker with pid: 18049
2014-06-15 15:17:20 [18050] [INFO] Booting worker with pid: 18050
2014-06-15 15:17:20 [18051] [INFO] Booting worker with pid: 18051
2014-06-15 15:17:20 [18052] [INFO] Booting worker with pid: 18052

^C

2014-06-15 15:17:51 [18052] [INFO] Worker exiting (pid: 18052)
2014-06-15 15:17:51 [18051] [INFO] Worker exiting (pid: 18051)
2014-06-15 15:17:51 [18037] [INFO] Handling signal: int
2014-06-15 15:17:51 [18048] [INFO] Worker exiting (pid: 18048)
2014-06-15 15:17:51 [18049] [INFO] Worker exiting (pid: 18049)
2014-06-15 15:17:51 [18050] [INFO] Worker exiting (pid: 18050)
2014-06-15 15:17:51 [18037] [INFO] Shutting down: Master

註解:需要按照你自己的設置來修改腳本的路徑和文件名。

  1. --workers的設置一般是按照2*CPUS+1,我的cpu爲雙核,所以設置爲5.

  2. --name(NAME)爲你的應用在某些程序(top,ps)中的標識,默認爲gunicorn,此處設置爲hello_app以便與其他gunicorn應用區別開來。

  3. 爲了能夠設置--name,需要安裝一個名爲setproctitle的Python模塊:pip install setproctitle


通過ps可查看到哪個gunicorn屬於哪個應用:

ps aux | grep hello_app

django   15226  0.0  0.2  15184  8068 ?        S    Jun13   0:25 gunicorn: master [hello_app]                                                                                                                                                                                                                                    
django   15237  0.0  0.4  27636 16556 ?        S    Jun13   0:01 gunicorn: worker [hello_app]                                                                                                                                                                                                                                    
django   15238  0.0  0.4  27640 16592 ?        S    Jun13   0:02 gunicorn: worker [hello_app]                                                                                                                                                                                                                                    
django   15239  0.0  0.4  27644 16600 ?        S    Jun13   0:01 gunicorn: worker [hello_app]                                                                                                                                                                                                                                    
django   15240  0.0  0.4  27656 16624 ?        S    Jun13   0:01 gunicorn: worker [hello_app]                                                                                                                                                                                                                                    
django   15242  0.0  0.2  19276 10820 ?        S    Jun13   0:01 gunicorn: worker [hello_app]


Supervisord


通過上述操作,gunicorn_start腳本已經可以工作了。爲了確保腳本能夠自動跟隨系統啓動和不期望的原因退出時能夠重啓,我們將會使用supervisord來完成這些工作。

安裝supervisord

yum install supervisord


配置hello應用:vim /etc/supervisord.conf

[program:hello]
command=/django_webapps/hello_django/bin/gunicorn_start            ;command to start app
user=django                                ;user to run as
stdout_logfile=/django_webapps/hello_django/logs/gunicorn_supervisor.log    ;path to write log messages
redirect_stderr=true                            ;save stderr in the same log[program:hello]
command=/django_webapps/hello_django/bin/gunicorn_start            ;command to start app
user=django                                ;user to run as
stdout_logfile=/django_webapps/hello_django/logs/gunicorn_supervisor.log    ;path to write log messages
redirect_stderr=true                            ;save stderr in the same log


創建相應的文件來存儲應用的日誌信息:

mkdir -p /django_webapps/hello_django/logs/

touch /django_webapps/hello_django/logs/gunicorn_supervisord.log


保存好配置文件後讓supervisord重載和更新,從而加入剛剛註冊的應用hello:

supervisorctl reread

hello: available

supervisorctr update

hello:added process group


檢查hello應用的status以及啓動、停止或重啓它:

supervisorctl status hello
hello                            RUNNING    pid 15226, uptime 1 day, 23:26:29

supervisorctl stop hello
hello: stopped

supervisorctl start hello
hello: started

supervisorctl restart hello
hello: stopped
hello: started

通過上述設置,你的應用將會跟隨系統自動重啓以及因某些原因崩潰後的自動重啓。


Nginx


接下來設置Nginx作爲我們的應用的反向代理服務器。以下是關於Nginx正向代理和反向代理的一些知識補充:

  1. 正向代理,也就是傳說中的代理,他的工作原理就像一個跳板,簡單的說,我是一個用戶,我訪問不了某網站,但是我能訪問一個代理服務器,這個代理服務器呢,他 能訪問那個我不能訪問的網站,於是我先連上代理服務器,告訴他我需要那個無法訪問網站的內容,代理服務器去取回來,然後返回給我。從網站的角度,只在代理 服務器來取內容的時候有一次記錄,有時候並不知道是用戶的請求,也隱藏了用戶的資料,這取決於代理告不告訴網站。

    結論就是,正向代理 是一個位於客戶端和原始服務器(origin server)之間的服務器,爲了從原始服務器取得內容,客戶端向代理髮送一個請求並指定目標(原始服務器),然後代理向原始服務器轉交請求並將獲得的內 容返回給客戶端。客戶端必須要進行一些特別的設置才能使用正向代理。

  2. 反向代理,舉例說明:用戶訪問 http://www.test.com/readme,但www.test.com上並不存在readme頁面,他是偷偷從另外一臺服務器上取回來,然後作爲自己的內容返回用戶,但用戶並不知情。這裏所提到的 www.test.com 這個域名對應的服務器就設置了反向代理功能。

    結論就是,反向代理正好相反,對於客戶端而言它就像是原始服務器,並且客戶端不需要進行任何特別的設置。客戶端向反向代理的命名空間(name- space)中的內容發送普通請求,接着反向代理將判斷向何處(原始服務器)轉交請求,並將獲得的內容返回給客戶端,就像這些內容原本就是它自己的一樣。

  3. 兩者區別:正向代理的典型用途是爲在防火牆內的局域網客戶端提供訪問Internet的途徑。正向代理還可以使用緩衝特性減少網絡使用率。反向代理的典型用途是將防火 牆後面的服務器提供給Internet用戶訪問。反向代理還可以爲後端的多臺服務器提供負載平衡,或爲後端較慢的服務器提供緩衝服務。另外,反向代理還可 以啓用高級URL策略和管理技術,從而使處於不同web服務器系統的web頁面同時存在於同一個URL空間下。



安裝nginx:

yum install nginx

啓動nginx:

service nginx start


通過登錄http://localhost可以訪問到nginx的歡迎頁面

ps:如果系統中也安裝了並啓動了監聽在80端口的apache,需要事先關閉apache服務,不然nginx無法啓動。


創建Django的Nginx虛擬服務器:

在Nginx的主配置文件中創建一個新的nginx虛擬服務器配置:cat /etc/nginx/nginx.conf

user              root;
worker_processes  1;

error_log  /var/log/nginx/error.log;
#error_log  /var/log/nginx/error.log  notice;
#error_log  /var/log/nginx/error.log  info;

pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;
    # Nginx virtual server configuration for Django
    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:/django_webapps/hello_django/run/gunicorn.sock fail_timeout=0;
    }
    server {
    
    listen 80;
    server_name localhost;
    client_max_body_size 4G;
    access_log    /django_webapps/hello_django/logs/nginx-access.log;
    error_log     /django_webapps/hello_django/logs/nginx-error.log;
    
    location /static/ {
        alias /django_webapps/hello_django/static/;
    }

    location /media/ {
        alias /django_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 /django_webapps/hello_django/static/;
    }
    }
    
        
    # Load config files from the /etc/nginx/conf.d directory
    # The default server is in conf.d/default.conf
    include /etc/nginx/conf.d/*.conf;

}

註解:

  1. 此處將user設置爲超級用戶root是因爲nginx及其他用戶沒有對django項目所在目錄的任何權限,如果不設置爲root,登錄http://localhost會顯示403 forbidden錯誤。或者也可以添加nginx用戶對應用目錄的讀權限。

  2. upstream表示nginx代理的上游服務器其實是gunicorn。


重啓nginx:

service nginx restart

登錄http://localhost可以看到由Nginx和Gunicorn支持的Django歡迎頁面。現在可以着手構建你自己的項目和應用,enjoy!!


卸載Django應用


通過以下步驟可以卸載掉不需要的應用:

首先修改nginx配置文件來去除虛擬服務器的設置,然後重啓:

service nginx restart


使用supervisord來停止應用,並刪除supervisord配置文件中對應的應用配置信息:

supervisorctl stop hello


如果再也不想使用這個應用,可以考慮刪除掉整個應用文件所在目錄:

rm -rf /django_webapps/hello_django/


運行多個Django應用


在同一個Nginx服務器上可以運行多個Django應用,通過不同的域名設置可以登錄到不同的url來實現對多個django應用的訪問。每一個應用將會設置自己的Python虛擬開發環境,創建專門的運行用戶和對應的權限設置、數據庫用戶和數據庫等。

依據前文構建hello項目的步驟可以構建一個jay項目,包括數據庫的創建、系統用戶的設置、supervisord的設置等等。現在最重要的是Nginx虛擬服務器的設置了:

與前文設置hello_app_server類似,可在nginx配置文件中增加jay_app_server虛擬服務器的設置:

upstream jay_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:/django_webapps/jay_django/run/gunicorn.sock fail_timeout=0;
    }

server {
    
    listen 80;
    server_name jaycn.sysu;
    client_max_body_size 4G;
    access_log    /django_webapps/jay_django/logs/nginx-access.log;
    error_log     /django_webapps/jay_django/logs/nginx-error.log;
    
    location /static/ {
        alias /django_webapps/jay_django/static/;
    }

    location /media/ {
        alias /django_webapps/jay_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://jay_app_server;
            break;
        }
    }
 
    # Error pages
    error_page 500 502 503 504 /500.html;
    location = /500.html {
        root /django_webapps/jay_django/static/;
    }
    }

可以修改hello_app_server服務器的server_name爲hello.sysu

保存配置文件並重啓nginx:

service nginx restart


最後設置好域名,以便DNS服務器能夠解析剛纔設置好的兩個域名:vim /etc/hosts

192.168.56.1    hello.sysu jaycn.sysu


通過登錄每個域名來測試服務器上的app是否設置正確:

http://hello.sysu

http://jaycn.sysu

                                                                                                                                ——遊響雲停



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章