0%

Flak+pyenv+gunicorn+nginx+supervisor初次部署总结

在个人博客的搭建实践完成后,就剩下尝试将项目部署上线了。初次进行项目部署,踩了不少坑,在过程中浏览了不少教程和资料,然而都不甚完整,因此将自己部署过程记录下来,以做总结、参考。

写在前面:

  • 本篇文章,远程主机系统为Ubuntu 18
  • 使用Git进行程序部署;虚拟环境采用pyenv管理、配置,这里不进行详细说明;
  • 关于迁移工具、日志等不进行说明;

安装Gunicorn、Nginx、Supervisor

切换到项目使用的虚拟环境下:

  1. 安装项目依赖

    1
    $ pip install -r requirements.txt
  2. 安装Gunicorn

    1
    2
    3
    $ pip install gunicorn
    # 如果想要使用异步worker,如gevent,则需要进行安装(本次部署采用gevent运行gunicorn)
    $ pip install gevent
  3. 安装Nginx

    1
    2
    3
    4
    # 第一次部署,我使用系统二进制源方式安装即可
    $ sudo apt-get install nginx
    # 检查是否安装成功
    nginx -v

    更多关于Linux下安装Nginx的内容,可以查看这篇博客

  4. 安装Supervisor

    1
    $ pip install supervisor

创建程序实例(入口)

在项目根目录下创建一个名为wsgi.py的脚本(命名只是约定,可以使用其他名称),代码如下:

1
2
3
4
5
6
7
8
9
10
11
# wsgi.py
import os
from dotenv import load_dotenv

# 载入环境变量
dotenv_path = os.path.join(os.path.dirname(__file__), '.env')
if os.path.exists(dotenv_path):
load_dotenv(dotenv_path, override=True) # load_dotenv默认不会更新已经存在的配置项, 因此使用override参数

from xthonblog import create_app
app = create_app('production')

此程序实例仅在部署时运行。如果在生产环境下,需要使用生产服务器运行程序实例时,可以从本文件导入此程序实例:from wsgi import app

从Git拉取代码并初始化程序环境

拉取代码

将代码上托管在Github上,并在远程服务器上通过git拉取项目代码,是比较方便的一种方式:

1
2
$ cd # 你打算存放项目代码的目录路径
$ git clone # 你的项目仓库地址

初始化程序环境

项目通过工厂函数创建程序实例,在项目根目录/__init__.py中,使用click注册了多个初始化用的命令行命令,依次执行它们:

  1. 初始化数据库:

    1
    $ flask initdb
  2. 初始化项目管理员:

    1
    $ flask init
  3. 生成虚拟填充数据:

    1
    $ flask forge

配置并使用Gunicorn运行程序

Gunicorn运行一个WSGI程序时,使用的命令模式:

1
$ gunicorn [OPTION] 模块名:变量名

这里的变量名即要运行的WSGI可调用对象,也就是我们使用Flask 创建的程序实例,而模块名即包含程序实例的模块,在本篇文章中,模块名即wsgi,变量名即app

常用的几个OPTION

1
2
3
4
-k # 指定worker类,默认为同步worker,可采用异步worker,如:gevent、eventlet、tornado,但需要另外安装
-w # 指定worker的数量,“通常来说,worker的数量建议为(2×CPU核心数)+1“
-b # 指定绑定服务器套接字,如:gunicorn -b 127.0.0.1:8000 模块名:变量名
-c # 指定配置文件路径,路径为字符串格式,如:gunicorn -c gun.conf

以下是本次部署时使用的配置文件gun.conf

1
2
3
4
5
6
7
8
# gun.conf
import os
bind = '127.0.0.1:8000' # 绑定的ip及端口号
workers = 2 #进程数
worker_class = "gevent" # 使用gevent模式,还可以使用sync模式,默认的是sync模式
debug = True # 开启debug项后,在启动gunicorn的时候可以看到所有可配置项的配置
chdir = '' # 项目的根目录
proc_name = 'gunicorn.proc' # 设置进程名字

因此,使用gunicorn运行时:

1
$ gunicorn -c gun.conf wsgi:app

更多gunicorn的配置参数,可以查看博客

使用Nginx提供反向代理

在前面的步骤中,我们已经安装了Nginx,现在对其进行配置。

先说明一下安装好后的文件位置:

1
2
3
4
/usr/sbin/nginx:主程序
/etc/nginx:存放配置文件
/usr/share/nginx:存放静态文件
/var/log/nginx:存放日志

我们可以在Nginx的默认配置文件(/etc/nginx/nginx.conf)中写入程序配置,但通常情况下,为了便于组织,我们可以在/etc/nginx/sites- enabled/或是/etc/nginx/conf.d/目录下为我们的Flask程序创建单独的Nginx 配置文件。

– 《Flask Web开发实战》

Nginx配置的常用指令,见图:

Nginx配置的常用指令

其他的语法规则包括:块通过花括号“{}”指定;每一行指令以“;”结尾;以“#”开头的是注释。

以下是本次部署使用的nginx的具体配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
server {
listen 80; # 监听80端口
server_name your_ip; # HOST机器的外部域名,用地址也行
# 未设置日志,所以这里先不进行配置

location / {
proxy_pass http://127.0.0.1:8000; # 转发地址, 即Gunicorn运行的地址
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;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

注意:Nginx安装后会自动运行,可以通过访问服务器的IP地址,会看到Nginx提供的测试页面。

配置并使用Supervisor管理进程

安装Supervisor后,它会自动在/etc/supervisor目录下生成一个包含全局配置的配置文件,名为supervisord.conf的配置文件(INI风格语法) 来定义进程相关的命令等信息。

为了便于管理,我们可以为程序配置创建单独的配置文件。这个全局配置默认会将/etc/supervisor/conf.d目录下的配置文件也包含在全局配置文件中。

– 《Flask Web开发实战》

本次部署,我们先备份/etc/supervisor/conf.d/default,再对其进行编辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# xthonblog.conf
[program:xthonblog]
environment=PYTHONPATH=$PYTHONPATH:/root/.pyenv/versions/blog-v377/bin/ ; 指定程序使用的python环境
directory=/root/projects/2020/xthonblog ; 程序的启动目录
command=/root/.pyenv/versions/blog-v377/bin/gunicorn -c /root/projects/2020/xthonblog/gun.conf wsgi:app ; 启动命令
user=root ; 用哪个用户启动
autostart=true ; 在 supervisord 启动的时候也自动启动
autorestart=true ; 自动重启
stopasgroup=true ; 与killasgroup一同开启,确保在关闭程序时停止所有相关的子进程
killasgroup=true ; 通过这两项配置来确保所有子进程都能正确停止
stdout_logfile_maxbytes=5MB ; stdout 日志文件大小
stdout_logfile_backups=2 ; stdout 日志文件备份数
stdout_logfile=/root/projects/2020/xthonblog/supervisor-log/xthon_stdout.log ; stdout输出路径
stderr_logfile=/root/projects/2020/xthonblog/supervisor-log/xthon_stderr.log ; stderr输出路径

其中 [program:usercenter] 中的 usercenter 是应用程序的唯一标识,不能重复。对该程序的所有操作(start, restart 等)都通过名字来实现。

如果python环境没有配置正确(包括gunicorn的路径、配置文件路径等),supervisor启动时,会出现FATAL、BACKOFF等错误;

有两种方式指定程序使用的 Python 环境:

  1. command 使用绝对路径。本项目使用 pyenv 来管理 Python 环境,上面例子中的 gunicorn 路径可以替换为 /root/.pyenv/versions/blog-v377/bin/gunicorn. 这种方式一目了然,推荐使用。
  2. 通过 environment 配置 PYTHONPATH.
    xthonblog.conf中那样,这个配置项非常有用,可以用来给程序传入环境变量。

编辑完后通过下面的命令重新启动supervisor服务以便让配置生效:

1
$ sudo service supervisor restart

配置中的xthonblog程序会在后台被自动执行,可以通过supervisor提供的命令行工具supervisorctl来查看和操作相关程序:

supervisor-RUNNING运行状态

可以看到,程序已经在运行了,现在通过访问远程服务器的IP地址,即可成功访问项目页面。

除了命令行工具supervisorctl,Supervisor还提供了Web客户端,这里就不进一步说明了。


感谢阅读~٩(๑òωó๑)۶

------ 本文结束 ------