Django+Gunicorn+Nginx配置整理

之前一篇文章我们梳理了WSGI与WSGI服务器的一些概念,这里主要整理下web应用部署时候的配置,包括Gunicorn以及Nginx的配置,方便以后翻阅

1. Gunicorn使用及配置

我们可以通过执行**./manage.py runserver**命令来运行我们的django应用程序。但我们知道它被称为开发服务器是有原因的,因为自带的开发服务器不健壮,安全问题,线程问题等等。那么,我们如何真正运行我们的应用呢?

Gunicorn,一个简单,轻便,快速的Python WSGI HTTP Server for UNIX。

  • 绑定一个具体的端口
    1
    gunicorn --bind 0.0.0.0:8030 myproject.wsgi
  • 增加请求服务的worker数量
    1
    gunicorn --workers 3 myproject.wsgi
  • 以守护进程模式来运行
    1
    gunicorn --daemon myproject.wsgi
  • 或者把上面三个组合起来这是常用的
    1
    gunicorn -D -b 0.0.0.0:8030 -w 3 myproject.wsgi
  • 或者我更喜欢把配置写到配置文件里
    1
    gunicorn -c /path/to/config/gunicorn.conf.py  myproject.wsgi

gunicorn.conf.py 配置文件模板如下,具体可以去看Gunicorn官方文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import logging
import logging.handlers
from logging.handlers import WatchedFileHandler
import os
import multiprocessing

bind = "unix:/tmp/gunicorn.sock" #绑定的ip与端口
backlog = 512 #监听队列数量,64-2048
#chdir = '/home/test/server/bin' #gunicorn要切换到的目的工作目录
worker_class = 'sync' #使用gevent模式,还可以使用sync 模式,默认的是sync模式
workers = 4 # multiprocessing.cpu_count() #进程数
threads = 16 #multiprocessing.cpu_count()*4 #指定每个进程开启的线程数
loglevel = 'info' #日志级别,这个日志级别指的是错误日志的级别,而访问日志的级别>无法设置
#access_log_format = '%(t)s %(p)s %(h)s "%(r)s" %(s)s %(L)s %(b)s %(f)s" "%(a)s"'
access_log_format = '%(t)s %(p)s %(h)s "%(r)s" %(s)s'

#accesslog = "./gunicorn_access.log" #访问日志文件
#errorlog = "./gunicorn_error.log" #错误日志文件
accesslog = "-" #访问日志文件,"-" 表示标准输出
errorlog = "-" #错误日志文件,"-" 表示标准输出

2. 一对好基友:Supervisor与Gunicorn

我们可以用supervisor来管理Gunicorn服务,配置模板如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[program:orderlunch]

command= pipenv run gunicorn -c gunicorn.conf.py OrderLunch.wsgi
directory=/home/pi/OrderLunchEnv/OrderLunch

user=pi
numprocs=1

stdout_logfile=/var/log/supervisor/orderlunch.log
stderr_logfile=/var/log/supervisor/orderlunch_error.log

autostart= true
autorestart=true

stopwaitsecs = 600
killasgroup=true
priority=999



3. Gunicorn如何处理静态文件?

在用Gunicorn跑Django的时候,比较郁闷的是静态文件的处理,即使在settings设置DEBUG=True,静态文件也不会正常显示.生产环境下一般不会裸跑Gunicorn,一般都会在前面放一个Nginx反代到Gunicorn,而静态文件直接交给Nginx处理.
但是如heroku,coding.net的演示平台这种PaaS就不能自己配置反向代理,怎么样设置wsgi才能正常处理静态文件呢.这里总结下处理这个问题的经验。

以上问题来自Gunicorn运行Django时静态文件处理

这里提到了两个方法来解决此问题:

  • 1. 强制使用Django自带的静态文件处理器
1
2
3
4
5
6
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
# ... the rest of your URLconf goes here ...
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
  • 2. 使用第三方库Whitenoise用来处理wsgi app静态文件
    这个方法比较好一点,用Whitenoise搭配Gunicorn,完全能在没有Nginx的情况下在生产环境中处理静态文件,配置非常简单,可以参考 Whitenoise官方文档

4. Nginx与Gunicorn配置记录

网上的教程鱼龙混杂,配置各个都不太一样,但大差不差,有些能用有些不能用,踩了蛮多坑,把自己的第一次成功配置贴在下面,方便自己以后回来查看。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
server {
listen 80;
server_name 0.0.0.0;
access_log /var/log/nginx/orderlunch_access_log;
error_log /var/log/nginx/orderlunch_error_log;
location = /favicon.ico { access_log off ; log_not_found off ; }
location / {
include proxy_params;
proxy_pass http://unix:/tmp/gunicorn.sock;
}
location /static {
alias /home/pi/OrderLunchEnv/OrderLunch/collected_static;
# 这里注意alias与root的区别
}
}

这里gunicorn我用的是.sock,所以相应的nginx这边的proxy_pass也要用sock,当然也可以用,http+port的形式。
配置到能访问网址,不止是一个配置文件就能解决的,完整的过程看这边:run-a-django-app-with-nginx-and-gunicorn 以及初次部署django+gunicorn+nginx ,用来看看一些概念和思路。

5. 更好的解决方式:Docker

研究的过程中,接触到了Docker。我们可以用pipenv保持python开发环境的一致,干净,但是当涉及到一些系统级别的服务时,比如redis作为消息队列 ,nginx作为代理服务器时,我们怎么做到隔离呢,那就是用Docker。这真的是太方便了!有时候因为Ubuntu系统版本的问题,或者之前设置过了这会想删除之前项目部署重新设置,可能存在一系列让人烦躁的事情,而Docker直接搞一个Nginx容器用来做反向代理,用一个redis容易作为消息队列的存储,干净的容器,不用了将容器直接关闭或者清除,也不用操心各个容器间的内部网络,都实现好了。
输入关键字docker django能在gihtub找到很多别人写的。我找到一个自己认为较好的,fork之后然后进行了一些修改(比如生成docker 镜像时,新增了国内下载源等),项目地址在这docker-django ,可以先按照教程跑起来然后查看内部的实现原理,会发现docker真的乃一部署神器!

6. 总结

这一配置篇与上一章的概念篇,把我最近关于对wsgi以及部署方面的一些概念进行了总结,也算解了心中一大困惑,部署是常见的事,记录下来,有规矩,才有方圆~