虽然 Flask 内置了服务器,其轻便且易于使用,但是 **Flask 的内建服务器不适用于生产**,也不能很好 的扩展。
## 独立 WSGI 容器 - Gunicorn
Gunicorn (绿色独角兽) 是一个 Python WSGI UNIX 的 HTTP 服务器。这是一个 pre-fork worker 的模型,从 Ruby 的独角兽([Unicorn](http://www.oschina.net/p/unicorn))项目移植。该 Gunicorn 服务器大致与各种 Web 框架兼容,实现非常简单,轻量级的资源消耗。Gunicorn 直接用命令启动,不需要编写配置文件,相对 uWSGI 要容易很多。
### 安装 gunicorn
```
(.venv) root@airvip:~/python_app/flask-demo# pip install gunicorn
```
安装成功后,通过命令行的方式可以查看如何使用 gunicorn
```
(.venv) root@airvip:~/python_app/flask-demo# gunicorn -h
usage: gunicorn [OPTIONS] [APP_MODULE]
optional arguments:
-h, --help show this help message and exit
-v, --version show program's version number and exit
```
运行我们的项目
```
(.venv) root@airvip:~/python_app/flask-demo# gunicorn -w 4 -b 127.0.0.1:8889 manage:app
[2021-01-12 07:29:33 +0000] [22184] [INFO] Starting gunicorn 20.0.4
[2021-01-12 07:29:33 +0000] [22184] [INFO] Listening at: http://127.0.0.1:8889 (22184)
[2021-01-12 07:29:33 +0000] [22184] [INFO] Using worker: sync
[2021-01-12 07:29:33 +0000] [22187] [INFO] Booting worker with pid: 22187
[2021-01-12 07:29:33 +0000] [22188] [INFO] Booting worker with pid: 22188
[2021-01-12 07:29:33 +0000] [22189] [INFO] Booting worker with pid: 22189
[2021-01-12 07:29:33 +0000] [22190] [INFO] Booting worker with pid: 22190
# gunicorn 记录日志
gunicorn -w 4 -b 127.0.0.1:8889 manage:app --access-logfile /root/python_app/flask-demo/logs/access.log --error-logfile /root/python_app/logs/flask-demo/error.log
```
测试
```
root@airvip:~# curl 127.0.0.1:8889
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="/static/css/style.css">
<title>前后端分离静态页面</title>
</head>
<body>
* 前后端分离的静态 HTML
</body>
</html>
```
传送门:[Flask 部署方式更多使用技巧](https://dormousehole.readthedocs.io/en/latest/deploying/index.html#deployment)
## 进程管理工具 supervisor
Supervisor 是一个 Python 开发的通用的进程管理程序,可以管理和监控 Linux 上面的进程,能将一个普通的命令行进程变为后台 daemon,并监控进程状态,异常退出时能自动重启。
### 安装 supervisor
```
root@airvip:~# apt-get install supervisor
```
supervisor 是一个 Python 开发的,当然也可以使用 pip 安装。
### 配置
```
root@airvip:/etc/supervisor/conf.d# vim flask_demo.conf
```
内容如下
```
[group:flask_demo]
; programs=flask-demo-app
,flask-demo-celery
programs=flask-demo-app
; [program:xx] 被管理的进程配置参数,xx 是进程的名称
[program:flask-demo-app]
; directory 脚本目录
directory=/root/python_app/flask-demo
; command 执行的命令
command=/root/python_app/flask-demo/scripts/manage.sh
; autostart 在supervisord启动的时候也自动启动
autostart=true
; startsecs 启动10秒后没有异常退出,就表示进程正常启动了,默认为1秒
startsecs=10
; autorestart 程序退出后自动重启,可选值:[unexpected,true,false],默认为 unexpected,表示进程意外杀死后才重启
autorestart=true
; startretries 启动失败自动重试次数,默认是3
startretries=3
; user 用哪个用户启动进程,默认是root
user=root
; priority 进程启动优先级,默认999,值小的优先启动
priority=999
; redirect_stderr 改为 true 则把 stderr 重定向到 stdout,默认 false
redirect_stderr=true
; stdout_logfile_maxbytes 日志文件大小,默认 50MB
stdout_logfile_maxbytes=50MB
; stdout_logfile_backups 日志文件备份数,默认是 10
stdout_logfile_backups=10
; stdout_logfile 需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录(supervisord 会自动创建日志文件)
stdout_logfile=/mnt/logs/xx_stdout.log
stderr_logfile=/mnt/logs/xx_stderr.log
loglevel=info
stopsignal=KILL
; stopasgroup 默认为 false,进程被杀死时,是否向这个进程组发送 stop 信号,包括子进程
stopasgroup=true
; killasgroup 默认为 false,向进程组发送 kill 信号,包括子进程
killasgroup=true
```
在 `/root/python_app/flask-demo/scripts/` 目录下新建 `manage.sh
`,内容如下
```
#!/bin/bash
source ~/.bashrc
export FLASK_ENV=production
cd /root/python_app/flask-demo/
source .venv/bin/activate
exec gunicorn -b 0.0.0.0:8889 --access-logfile /root/python_app/flask-demo/logs/access.log --error-logfile /root/python_app/flask-demo/logs/error.log manage:app
```
给 `manage.sh` 脚本可执行权限
```
(.venv) root@airvip:~/python_app/flask-demo/scripts# chmod +x manage.sh
```
查看
```
# 查看 supervisor 是否已启动
root@airvip:/etc/supervisor/conf.d# ps -aux | grep supervisor
root 11028 0.0 0.0 13136 1104 pts/2 S+ 09:22 0:00 grep --color=auto supervisor
root 27948 0.0 1.0 65548 21372 ? Ss 07:59 0:01 /usr/bin/python /usr/bin/supervisord -n -c /etc/supervisor/supervisord.conf
root@airvip:~# systemctl status supervisor
root@airvip:~# systemctl start supervisor
root@airvip:~# systemctl stop supervisor
```
### supervisorctl
supervisor 已经启动,我们可以利用 supervisorctl 来管理
```
root@airvip:/etc/supervisor/conf.d# supervisorctl
supervisor> update
flask_demo: added process group
supervisor> status
flask_demo:flask-demo-app RUNNING pid 19110, uptime 0:00:19
```
### supervisorctl 常用命令
```
supervisor> status # 查看程序状态
supervisor> start flask-im # 启动 flask-im 单一程序
supervisor> stop flask-demo:* # 关闭 flask-demo 组程序
supervisor> start flask-demo:* # 启动 flask-demo 组程序
supervisor> restart flask-demo:* # 重新启动 flask-demo 组程序
supervisor> update # 重启配置文件修改过的程序
supervisor> reload # 重新启动配置文件中的所有程序
supervisor> exit # 退出
```