The value of knowledge lies not in possession, but in share.

0%

云服务器部署Python Web环境(Flask+Nginx+Gunicorn+Supervisor)

Flask 是一个使用 Python 编写的轻量级Web 应用框架。Flask的目的是要建立一个非常稳定和可靠的Web应用的基础系统,我们可以使用Flack再加上各种插件,扩展和其他模块,能够构建功能强大的网站和应用。根据2019年的使用情况数据可看出,主流 Python Web 框架包括:django、Flask、Tornado、Web2Py 等,web.py由于其原作者的仙逝,近些年表现出颓疲的状态,令人惋惜不已。

本教程在云服务器上安装了WSGI (Web Server Gateway Interface )接口 及 Http Sever (如 Apache、Nginx等)。

Python Web环境 -> Flask+ Nginx + Gunicorn + Supervisor

Flask是Web框架、Nginx 提供对外的服务、Gunicorn为WSGI服务器、Supervisor来守护进程。

注:本教程在Python3.x版本运行,安装可参考:Python3.x的安装及相关设置

此前基于云服务器部署Python Web环境(Nginx+Spawn-fcgi+web.py)的教程可以按需参阅。

安装VirtualEnv

  1. Ubuntu下安装VirtualEnv:

    1
    sudo pip install virtualenv
  2. 创建venv文件夹,并安装虚拟环境:

    1
    2
    3
    4
    5
    6
    7
    8
    # 创建文件夹,或者进入自己的项目文件夹
    mkdir project
    # 进入该文件夹
    cd project
    # 安装虚拟环境
    virtualenv venv
    # 会提示如下的信息
    >> created virtual environment CPython3.7.5.final.0-64 in 546ms ...
  1. 激活虚拟环境:

    1
    2
    3
    # 激活虚拟环境
    source venv/bin/activate
    # 退出虚拟环境:deactivate

    启用虚拟环境后,命令行状态进入虚拟环境的状态,如下:

    1
    (venv) ~/project#

安装Flask

通用安装方法:

  1. 在激活的虚拟环境中安装Flask

    1
    2
    # 在激活的虚拟环境中安装Flask
    (venv) ~/project$ pip install Flask
  2. 测试Flask,新建hello.py内容如下:

    hello.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-

    from flask import Flask

    app = Flask(__name__)

    @app.route('/hello')
    def hello():
    return 'Hello World!'

    if __name__ == "__main__":
    app.run() # 启动应用

    运行该代码:

    1
    2
    python hello.py
    # 提示:* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

另开一个终端,输入curl 127.0.0.1:5000,其中端口号与上方一致,显示结果为:

Hello, World!

修改Flask的默认端口:

1
env FLASK_APP=hello.py flask run -p 5001

安装Nginx

  1. Ubuntu下可使用下述命令:

    1
    sudo apt-get install nginx

    安装好的文件位置:

    /usr/sbin/nginx:主程序

    /etc/nginx:存放配置文件

    /usr/share/nginx:存放静态文件

    /var/log/nginx:存放日志

    其实从上面的根目录文件夹可以知道,Linux系统的配置文件一般放在/etc,日志一般放在/var/log,运行的程序一般放在/usr/sbin或者/usr/bin。

    如果要更清楚Nginx的具体配置项,可以打开/etc/nginx/nginx.conf

    对于其他Linux系统可参照官网链接:https://www.nginx.com/resources/wiki/start/topics/tutorials/install/

  2. 启动Nginx:

    1
    2
    # 启动Nginx
    sudo /etc/init.d/nginx start

    其他相关命令:

    1
    2
    3
    4
    # 关闭Nginx
    sudo /etc/init.d/nginx stop
    # 重启Nginx
    sudo /etc/init.d/nginx restart
  3. 访问xx.xx.xx.xx(其中xx.xx.xx.xx更换为云服务器的公网IP),显示结果为:

    Welcome to nginx!

    If you see this page, the nginx web server is successfully installed and working. Further configuration is required.

    For online documentation and support please refer to nginx.org.
    Commercial support is available at nginx.com.

    Thank you for using nginx.

安装Gunicorn

  1. 安装Gunicorn

    1
    pip install gunicorn
  2. 配置 nginx.conf 支持 Gunicorn

    1
    2
    # 编辑配置文件
    vim /etc/nginx/nginx.conf

    http内如下之处:

    1
    2
    3
    4
    http
    {
    server{}
    }

    添加以下代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    server{
    listen 80;
    server_name xx.xx.xx.xx; # 其中xx.xx.xx.xx更换为云服务器的公网IP
    index index.html index.php;

    location /hello {
    proxy_pass http://127.0.0.1:9001; # 把请求通过gunicorn传送给本机的9001端口
    proxy_redirect off;
    proxy_set_header Host $host:80;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    location /static/ { # 配置静态文件的访问
    if (-f $request_filename) { # 如果请求文件名是一个文件
    rewrite ^/static/(.*)$ /static/$1 break; # 直接跳转到对应的资源,中断fastcgi的传输
    }
    }
    }

特别注意:【此处尤为重要,一开始始终无法正常显示,我花费了一下午的时间才解决相关问题】

  • 在云服务器【安全组】的入站规则出站规则分别添加80、90、50端口;
  • 重启Nginx:sudo /etc/init.d/nginx restart
  • nginx.confproxy_pass http://127.0.0.1:5000端口号可以更改,但是需要保持与启动Gunicorn进程中的相同,同事注意修改端口号后要重启Nginx

启动应用

  1. 启动一个Gunicorn进程:

    1
    2
    # 启动进程
    gunicorn -D -w 5 -b 127.0.0.1:9001 hello:app

-D: 后台运行
-w: 代表启动5个进程(worker),可以通过ps -ef | grep 9001 可以看到四个PID;

-b: 打标绑定的IP和端口号,0.0.0.1表示不仅仅能在本台机器上访问,外网也可以访问,绑定的为9001端口

main:app**, wsgi代表文件名,app为对应到该文件中创建的Flask对象
此外还有其他参数:

-log-level LEVEL:表示日志级别,测试可以用DEBUG

-timeout: 超时时间,单位是秒

—access-logfile access.log:访问日志

—error-logfile error.log:错误日志

注:可以随意填写地址和端口信息,但是一定需要和Nginx配置文件相匹配。

  1. 启动Nginx

    1
    2
    # 启动Nginx
    sudo /etc/init.d/nginx start
  2. 查看9001端口是否存在

    1
    netstat -ano |grep 9001

    若存在则显示:

    tcp 0 0 127.0.0.1:9001 0.0.0.0:* LISTEN off (0.00/0/0)

  3. 访问xx.xx.xx.xx/hello(其中xx.xx.xx.xx云服务器的公网IP),显示结果为:

    Hello, world!

关闭/重启应用

  1. 查看Gunicorn进程树:

    1
    pstree -ap|grep gunicorn

    显示如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    |-gunicorn,24610 /root/cong/venv/bin/gunicorn -D -w 5 -b 127.0.0.1:9001 hello:app
    | |-gunicorn,24613 /root/cong/venv/bin/gunicorn -D -w 5 -b 127.0.0.1:9001 hello:app
    | |-gunicorn,24614 /root/cong/venv/bin/gunicorn -D -w 5 -b 127.0.0.1:9001 hello:app
    | |-gunicorn,24615 /root/cong/venv/bin/gunicorn -D -w 5 -b 127.0.0.1:9001 hello:app
    | |-gunicorn,24616 /root/cong/venv/bin/gunicorn -D -w 5 -b 127.0.0.1:9001 hello:app
    | `-gunicorn,24622 /root/cong/venv/bin/gunicorn -D -w 5 -b 127.0.0.1:9001 hello:app
    |-gunicorn,25266 /root/cong/venv/bin/gunicorn -D -w 5 -b 127.0.0.1:5000 hello:app
    | |-gunicorn,25269 /root/cong/venv/bin/gunicorn -D -w 5 -b 127.0.0.1:5000 hello:app
    | |-gunicorn,25270 /root/cong/venv/bin/gunicorn -D -w 5 -b 127.0.0.1:5000 hello:app
    | |-gunicorn,25271 /root/cong/venv/bin/gunicorn -D -w 5 -b 127.0.0.1:5000 hello:app
    | |-gunicorn,25272 /root/cong/venv/bin/gunicorn -D -w 5 -b 127.0.0.1:5000 hello:app
    | `-gunicorn,25273 /root/cong/venv/bin/gunicorn -D -w 5 -b 127.0.0.1:5000 hello:app
    | | |-grep,26544 --color=auto gunicorn
  2. 退出一个Gunicorn进程:

    1
    2
    # 如退出上方的24610进程
    kill -9 24610
  3. 重启进程:

    1
    2
    # 如重启上方的25266进程
    kill -HUP 25266

安装 Supervisor

Supervisor是一个使用Python开发的进程管理程序

  1. 安装supervisor:

    1
    pip install supervisor
  2. 生成配置文件

    1
    2
    3
    4
    5
    6
    # 创建 /etc/supervisor 文件夹
    mkdir /etc/supervisor
    # 生成 supervisord.conf 文件
    echo_supervisord_conf > /etc/supervisor/supervisord.conf
    # 为supervisord.conf增加执行权限
    chmod +x /etc/supervisor/supervisord.conf

    修改supervisord.conf最后的[include]部分配置:

    1
    2
    [include]
    files = /etc/supervisor/conf.d/*.conf

    这样就可以支持子配置文件,而不用改动主配置文件。

  3. /etc/supervisor/conf.d/新增子进程配置文件 hello.conf

    1
    2
    3
    4
    5
    6
    7
    # 创建 /etc/supervisor/conf.d 文件夹
    cd /etc/supervisor
    mkdir conf.d
    # 创建hello.conf 文件
    cd /etc/supervisor/conf.d
    # 为hello.conf增加执行权限
    chomod +x hello.conf

    创建 hello.conf配置文件如下:

    1
    2
    3
    4
    5
    6
    7
    8
    [program:hello]
    command=/root/cong/venv/bin/gunicorn -w 5 -b 127.0.0.1:9001 hello:app
    directory=/root/cong //项目目录
    user=root
    autorestart=true //设置自动重启
    startretires=3 //重启失败3次

    [supervisord]

    在上面的配置文件中,[program:hello]设置了进程名,这与之后操作进程的状态名称有关,为hello;

    command为进程运行的命令,必须使用绝对路径,并且使用虚拟环境下的gunicorn命令;

    user指定了运行进程的用户,这里设置为root

    注意hello.conf中不要有汉字

  4. 启动这个demo进程:

    1
    supervisord -c /etc/supervisor/conf.d/hello.conf
  1. 停止进程

    1
    2
    3
    4
    # 找到supervisord进程编号
    ps -ef | grep supervisord
    # kiil进程
    kiil -9 24918
  2. 因为在虚拟环境中安装了Supervisor,我的supervisorctl无法使用,在虚拟环境之外也另外安装了Supervisor,解决了部分问题。总之Supervisor对Python3.x支持效果不好。

导出pip安装包记录

将虚拟环境中安装的包记录到requirements.txt中:

1
2
3
4
5
6
7
8
9
10
pip freeze > requirements.txt
# 如下所示:
click==7.1.2
Flask==1.1.2
gunicorn==20.0.4
itsdangerous==1.1.0
Jinja2==2.11.2
MarkupSafe==1.1.1
supervisor==4.2.0
Werkzeug==1.0.1

当该项目被迁移到其他机器时,直接运行(或新建一个虚拟环境,再运行该命令):

1
2
# 安装所需要的包
pip install -r requirements.txt

Debug

Bug 1: 出现

1
The 'supervisor==3.3.1' distribution was not found and is required by the application

解决方法:

通过apt-get安装的supervisor,实际上是按照Python2.x版本中。但由于我把ubuntu的python默认环境改成3.7,在Python3使用supervisor其实是借用Python2的环境,所以通过apt-get安装的supervisor显然不可行。

直接用Python3.x版本通过pip安装,会提示:

1
Supervisor requires Python 2.4 or later but does not work on any version of Python 3.  You are using version 3.7.5 (default, Nov  7 2019, 10:50:52)

安装上文中通过pip进行安装,应该不会出现此问题。

Bug 2: 出现

1
2
Error: .ini file does not include supervisord section
For help, use /root/cong/venv/bin/supervisord -h

意思是少了 [supervisrod] 配置项,严格按照上方的流程不会出现此问题,可以参考 [supervisord-section-settings增添其他配置选项。

🍭支持一根棒棒糖吧!