Flask+Gunicorn+Supervisor+Nginx部署

1,014 阅读3分钟

生产环境配置

创建项目部署目录

mkdir -p /data/www

拉取项目

cd /data/www
git clone xxx

拉取的项目不包含带有敏感信息的.env 文件,手动生成并写入需要的配置信息

vim .env

# 敏感配置
PRD_DATABASE_URL="mysql+pymysql://admin:admin@localhost:3306/xxx?charset=utf8mb4"

使用pyenv 设置项目目录虚拟Python环境

pyenv local 3.7.6

安装依赖

pip install -r requirements.txt

Gunicorn 配置

项目中的gunicorn_cfg.py 配置如下

import gevent.monkey
import multiprocessing

gevent.monkey.patch_all()

# debug = True
loglevel = 'info'
bind = "0.0.0.0:8080"
pidfile = "logs/gunicorn.pid"
accesslog = "-"
errorlog = "-"

access_log_format = '%({x-forwarded-for}i)s %(l)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
# daemon = True

workers = multiprocessing.cpu_count() * 2 + 1
worker_class = 'gevent'

logs

  • accesslog:用户的访问的日志的目录,和nginx的access_log很像,都是记录访问服务器的用户的信息;
accesslog = '/var/logs/gunicorn.access.log'
accesslog = '-' # 记录到标准输出
  • access_log_format:设置记录访问信息的日志的格式;
access_log_format = '%(h)s %(l)s %(u)s %(t)s'
access_log_format = '%(h) -  %(t)s - %(u)s - %(s)s %(H)s'

gunicorn有多个内置的参数可用来配置:

h   远程地址
l   “-“
u   用户名
t   时间
r   状态行,如:GET /test HTTP/1.1
m   请求方法
U   没有查询字符串的URL
q   查询字符串
H   协议
s   状态码
B   response长度
b   response长度(CLF格式)
f   参考
a   用户代理
T   请求时间,单位为s
D   请求时间,单位为ms
p   进程id
{Header}i   请求头
{Header}o   相应头
{Variable}e 环境变量

注: 可以用%({x-forwarded-for}i)s 记录通过nginx代理的远程IP

  • errorlog:记录服务器运行的日志;
errorlog = '/var/logs/gunicorn.error.log'
errorlog = '-' # 记录到标准输出
  • loglevel:设置错误日志的输出等级;有个级别可以选择;
loglevel = 'error'  # 引号包裹
debug		# 调试级别,记录的信息最多;
info		# 普通级别;
warning		# 警告消息;
error		# 错误消息;
critical	# 严重错误消息;

workers

worker_class是指开启的每个工作进程的模式类型,默认为sync模式,也可使用gevent模式。

workers是工作进程数量,在上述gunicorn_cfg.py 中,取的是CPU的数量。需要注意部署机器的性能,不能无限制多开。一般使用multiprocessing.cpu_count() * 2 + 1 这个数量

daemon

daemon = True # 意味着开启后台运行,默认为`False

Supervisor 配置

首先是一个配置文件,写在 /etc/supervisor/conf.d 路径下面创建 xxx.ini 文件:

[program:yblog]
command = /data/.pyenv/versions/xxx/bin/gunicorn -c gunicorn_cfg.py wsgi:app   ; 启动命令,因为在虚拟Python环境中,需要使用绝对路径
directory = /data/www/xxx      ; 项目目录
user = root          ; 用哪个用户启动
autostart = true     ; 在 supervisord 启动的时候也自动启动   
startsecs = 1        ; 启动 1 秒后没有异常退出,就当作已经正常启动了   
autorestart = true   ; 程序异常退出后自动重启   
startretries = 3     ; 启动失败自动重试次数,默认是 3   
stopasgroup = true     ; 确保在关闭程序时停止所有相关的子进程
killasgroup = true     ; 确保在关闭程序时停止所有相关的子进程
stdout_logfile_maxbytes = 20MB  ; stdout 日志文件大小,默认 50MB   
stdout_logfile_backups = 10     ; stdout 日志文件备份数 
stdout_logfile = /data/www/xxx/logs/xxx_access.log    ; log 日志
stderr_logfile = /data/www/xxx/logs/xxx_error.log     ; 错误日志

之后是几个常用的操作:

# 通过配置文件启动 supervisor
supervisord -c supervisor.conf 

# 查看 supervisor 的状态
supervisorctl -c supervisor.conf status 

# 重新载入配置文件,每次修改之后记得重新载入
supervisorctl -c supervisor.conf reload

# 启动指定/所有 supervisor 管理的程序进程
supervisorctl -c supervisor.conf start [all]|[appname]

# 关闭指定/所有 supervisor管理的程序进程
supervisorctl -c supervisor.conf stop [all]|[appname]

Nginx 配置

一个很简单的配置文件:

server {
    listen 80;
    server_name example.com;

    location / {
            proxy_pass http://127.0.0.1:8080;
            proxy_redirect off; 
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

重启nginx

nginx -s reload