Centos7 下部署django

Posted on 一 12 12月 2016 in python

前几天在阿里云上部署了一个系统。顺便了解了一下nginx, uwsgi, django部署的流程

首先安装nginx,这个比较简单

sudo yum install nginx

安装uwsgi, 这里要注意,最好用pip安装,而不用yum安装。通常用yum或者apt-get安装的,需要在命令后面加上 --plugin python

pip install --user uwsgi

一步一步使用uwsgi, 第一个WSGI project, 保存为foobar.py

def application(env, start_response):
    start_response('200 OK', [('Content-Type','text/html')])
    return [b"Hello World"]

部署到9090端口

启动uWSGI作为http服务器转发请求到WSGI application
uwsgi --http :9090 --wsgi-file foobar.py

浏览器访问 http://localhost:9090就可以看到效果。
如果是在服务器,可以用 curl -i "http://localhost:9090"

开启并发处理,监控

uwsgi --http :9090 --wsgi-file foobar.py --master --processes 4 --threads 2 --stats 127.0.0.1:9191

开启了4个进程,2个线程(这里我其实不是太清楚), 127.0.0.1:9191会输出各个进程和线程的状态 这里推荐一个项目 djano-uwsgi

uWSGI 支持HTTP, FastCGI, SCGI,和 uwsgi。但是对uwsgi协议支持是性能最好的。nginx也支持uwsgi协议。所以可以配合来使用
nginx配置

location / {
    include uwsgi_params;
    uwsgi_pass 127.0.0.1:3031;
}

上面的配置意思是把服务器3031端口的的请求转成uwsgi协议
然后uWSGI使用uwsgi协议

uwsgi --socket 127.0.0.1:3031 --wsgi-file foobar.py --master --processes 4 --threads 2 --stats 127.0.0.1:9191

部署Django应用
Django应用目录在/home/foobar/myproject

uwsgi --socket 127.0.0.1:3031 --chdir /home/foobar/myproject/ --wsgi-file myproject/wsgi.py --master --processes 4 --threads 2 --stats 127.0.0.1:9191

上面命令的参数太多了,uWSGI支持配置文件,新建uwsgi.ini文件

[uwsgi]
socket = 127.0.0.1:3031
chdir = /home/foobar/myproject/
wsgi-file = myproject/wsgi.py
processes = 4
threads = 2
stats = 127.0.0.1:9191

然后运行

uwsgi uwsgi.ini

以上内容是从官方的教程提取出来的。下面是我实际中结合文档的操作

django deployment checklist

运行 python mannage.py check --deploy
会检查settings.py里面的设置是否合适,比如关闭debug等等

django Deploying static files

在settings.py里面要设置一个STATIC_ROOT,

STATIC_ROOT = os.path.join(BASE_DIR, "collected_static/")

部署服务器上运行 python manage.py collectstatic, 把静态文件拷贝到collected_static目录上,否则运行之后报404错误

新建nginx的配置文件,eng_nginx.conf

# the upstream component nginx needs to connect to
upstream ent {
    server unix:///run/uwsgi/ent.sock; # for a file socket
    #server 127.0.0.1:8001; # for a web port socket (we'll use this first)
}

# configuration of the server
server {
    # the port your site will be served on
    listen      80;
    # the domain name it will serve for
    server_name xxx.com; # substitute your machine's IP address or FQDN
    charset     utf-8;

    # max upload size
    client_max_body_size 75M;   # adjust to taste

    # Django media
    location /favicon.ico{
        alias  /var/www/ent/ent/media/favicon.ico; # your Django project's media files - amend as required
    }

    # Django media
    location /media  {
        alias  /var/www/ent/ent/media; # your Django project's media files - amend as required
    }

    location /static {
        alias /var/www/ent/ent/collected_static; # your Django project's static files - amend as required
    }

    # Finally, send all non-media requests to the Django server.
    location / {
        uwsgi_pass  ent;
        include     /var/www/ent/ent/uwsgi_params; # the uwsgi_params file you installed
    }
}

这里使用了unix sock方式,而没有使用端口方式, sock文件路径是 /run/uwsgi/ent.sock,这个路径是systemd动态创建的,不需要手动创建。 uwsgi_params可以使用project中的,也可以使用nginx安装路径的。
static请求要指定到上一步对应的目录中。 media也是要指定到对应目录。
注意上面两个目录必须包含nginx运行的用户组,有可能是www-data,也有可能是nginx,并且当前用户要加入到nginx的用户组。

sudo chown -R user:nginx collected_static
sudo chown -R user:nginx media

uwsgi配置

这里直接使用 uWSGI的emperor 模式

# create a directory for the vassals
sudo mkdir /etc/uwsgi
sudo mkdir /etc/uwsgi/vassals
# symlink from the default config directory to your config file
sudo ln -s /path/to/your/mysite/mysite_uwsgi.ini /etc/uwsgi/vassals/
# run the emperor
uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data
# touch emperor.ini
cd ..
touch emperor.ini
[uwsgi]

# the base directory (full path)
chdir = /home/maemo/workspace/python/ent

# Django s wsgi file
module = ent.wsgi:application

;home = /var/www/ent/uwsgi

# process-related settings
# master
master = true

# maximum number of worker processes
processes = 1

socket = /run/uwsgi/ent.sock

# ... with appropriate permissions - may be needed
chmod-socket = 664
# clear environment on exit
vacuum = true

die-on-term = true

;logto = /tmp/ent.log
;logfile-chmod = 666
daemonize = /var/log/uwsgi/ent.log

mysite_uwsgi.ini的内容:

[uwsgi]

    uid = maemo
    gid = nginx
    # the base directory (full path)
    chdir = /var/www/ent/ent

    # Django s wsgi file
    module = ent.wsgi:application

    ;home = /var/www/ent/uwsgi

    # process-related settings
    # master
    master = true

    # maximum number of worker processes
    processes = 1

    #socket = /var/www/ent/ent.sock
    socket = /run/uwsgi/ent.sock

    # ... with appropriate permissions - may be needed
    chmod-socket = 664
    # clear environment on exit
    vacuum = true

    die-on-term = true

    ;logto = /tmp/ent.log
    ;logfile-chmod = 666
    daemonize = /var/log/uwsgi/ent.log

emperor.ini 内容如下:

[uwsgi]
emperor = /etc/uwsgi/vassals
#uid = user
#gid = nginx

上面指定了uWSGI的用户是user,用户组是nginx,当然,这个在上面的mysite_uwsgi.ini也可以单独配置,这个很重要
另外,mysite_uwsgi.ini中的sock文件与ent_ngixn.conf中的sock一定要是相同的

使用systemd启动和停止uWSGI

cd /etc/systemd/system
sudo touch emperor.uwsgi.service

emperor.uwsgi.service的内容如下:

[Unit]
Description=uWSGI Emperor
After=syslog.target

[Service]
ExecStart=/home/user/.local/bin/uwsgi --ini /etc/uwsgi/emperor.ini
RuntimeDirectory=uwsgi
Restart=always
KillSignal=SIGQUIT
Type=notify
StandardError=syslog
NotifyAccess=all
User=maemo
Group=nginx

[Install]
WantedBy=multi-user.target

注意到上面uwsgi是绝对路径,因为我是用pip安装到当前用户的 RuntimeDirectory=uwsgi这一句就会自动在/run/下面创建uwsgi/ent.sock文件,在旧版本的systemd中可能要参考其它方法

启动nginx和uWSGI

sudo systemctl restart nginx.service
sudo systemctl restart emperor.uwsgi.service

在这个过程中,我遇到很多错误,最有用的是看nginx和uWSGI的log,通过log再到网上去查能很快解决问题