前言

刚接触一个开源项目,用 Gunicorn 作为启动及 Web 服务程序,初次接触,整理了些资料,实现:项目自启动 + nginx 作为前端 Web服务,以备后用。

Gunicorn 简介

Gunicorn(Green Unicorn)是一个用于 UNIX 的 Python WSGI HTTP 服务器。Gunicorn 服务器广泛兼容各种 Web 框架,实现简单,服务器占用资源少,速度相当快。

Gunicorn 没有依赖项,因此下载后可以很容易迁移到生产环境。

安装

1
pip install gunicorn

快速使用

直接在项目目录内,也就是 manage.py 所在的目录内执行:

1
gunicorn your_project.wsgi:application --bind 0.0.0.0:8080

即可启动生产级别的 Web 服务,前提是你的项目也是生产环境的配置,例如 Debug = False

方案组合

  • 一般服务器上都装有 nginx,所以就用 nginx 反代到后端项目提供服务,
  • 使用 systemd 监控管理 Gunicorn
  • Gunicornnginx 之间监听指定端口或用 Unix sock 通讯「推荐nginx 的 conf 文件中 不用代理 ip:prot 形式,而是代理 sock 文件。」

根据以上罗列方案组合,需要建立以下文件:

  1. 系统服务管理:/etc/systemd/system/gunicorn.service
  2. 系统级别的套接字文件:/etc/systemd/system/gunicorn.socket
  3. nginx 的网站配置:/etc/nginx/conf.d/domain.conf

系统服务管理:/etc/systemd/system/gunicorn.service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[Unit]
Description=Gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
User=www
Group=www
# WorkingDirectory 是项目路径目录
WorkingDirectory=/www/wwwroot/domain.com
# ExecStart=/www/wwwroot/domain.com/venv/bin/gunicorn \
# --access-logfile - \
# --workers 3 \
# --bind unix:/run/gunicorn.sock \
# myproject.wsgi:application
# 使用配置代替执行命令中的各种参数
# 原本在虚拟环境中要执行的 gunicorn -c gunicorn_conf.py main:app -k uvicorn.workers.UvicornWorker
# 其中 gunicorn 和 gunicorn_conf.py 要写完整的路径名称
ExecStart=/www/wwwroot/domain.com/venv/bin/gunicorn -c /www/wwwroot/domain.com/gunicorn_conf.py main:app -k uvicorn.workers.UvicornWorker
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=mixed
TimeoutStopSec=5
PrivateTmp=true

[Install]
WantedBy=multi-user.target

系统级别的套接字文件:/etc/systemd/system/gunicorn.socket

1
2
3
4
5
6
7
8
[Unit]
Description=Gunicorn socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target

这样我们就可以在系统启动的时候启动 Gunicorn 服务,也可以很方面的启动、停止、重启 Gunicorn

1
2
3
4
systemctl enable gunicorn
systemctl start gunicorn
systemctl stop gunicorn
systemctl restart gunicorn

查看服务状态:

1
systemctl status gunicorn.socket

gunicorn_conf.py

为了后期更改方便,将 Gunicorn 参数写进配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 根据项目实际情况引入库
# coding=utf-8
# from gevent import monkey
# monkey.patch_all()
# import multiprocessing
# 生产环境记得关闭debug
debug = True
# 修改代码时自动重启
reload = True
reload_engine = 'inotify'
# //绑定与Nginx通信的端口
# bind = '127.0.0.1:3002'
bind = 'unix:/run/gunicorn.sock' #与 /etc/systemd/system/gunicorn.socket 中对应
pidfile = 'log/gunicorn.pid'

# workers = 4 # 进程数
workers = multiprocessing.cpu_count() * 2 + 1 #进程数

# worker_class = 'uvicorn.workers.UvicornWorker' # 使用 unicorn ,不使用 gunicorn 自带的方式. unicorn相关文档: http://www.uvicorn.org/deployment/#running-gunicorn-worker

# 日志级别
# debug:调试级别,记录的信息最多;
# info:普通级别;
# warning:警告消息;
# error:错误消息;
# critical:严重错误消息;
loglevel = 'debug'
# 访问日志路径
accesslog = 'log/gunicorn_access.log'
# 错误日志路径
errorlog = 'log/gunicorn_error.log'

# 设置gunicorn访问日志格式,错误日志无法设置.貌似无效
access_log_format = '%(t)s %(p)s %(h)s "%(r)s" %(s)s %(L)s %(b)s %(f)s" "%(a)s"'

# 启动命令
# gunicorn -c gunicorn_conf.py main:app
# gunicorn -c gunicorn_conf.py main:app -k uvicorn.workers.UvicornWorker

实测使用 supervisor 守护进程常规方式无法启动,各种报错

nginx 的网站配置:domain.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
server {
listen 80;
server_name server_domain_or_IP;

location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /www/wwwroot/domain.com;
}

location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
}

nginx -t 测试配置是否有误,nginx -s reload 重载配置让配置生效

NginxGunicorn 故障排除

对于故障排除,日志可以帮助找到根本原因。检查以下日志可以帮助排除故障:

  • 查看 Nginx 进程日志:journalctl -u nginx
  • 查看 Nginx 访问日志:less /var/log/nginx/access.log
  • 检查 Nginx 错误日志:less /var/log/nginx/error.log
  • 检查 Gunicorn 应用程序日志:journalctl -u gunicorn
  • 检查 Gunicorn 套接字日志:journalctl -u gunicorn.socket

参考文档

  1. 官方文档:Deploying Gunicorn
  2. nginx+gunicorn+fastapi 部署自动后台启动
  3. 使用 nginx + gunicorn 来部署生产环境的 Django app
  4. django 部署,gunicorn、virtualenv、nginx