1. Introduction

本文主要系翻译自digitalocean的教程How To Serve Flask Applications with uWSGI and Nginx on Ubuntu 16.04,部分进行了修改。

主要介绍了在nginx服务器上利用uWSGI部署Flask应用的步骤。

之前写过的相关内容:

uwsgi配置https以及python2无法使用supervisor

nginx配置https

2. 准备工作

在开始之前,先确保有一个非root的用户部署在你的服务器上,这个用户必须使用sudo才能执行管理员命令。

FindHao注:非root用户是为了安全性考虑,但是由于购买的vps系统一般默认root用户,通过lnmp.org一键安装lnmp之后,会创建www用户和www用户组,因此下文的配置是以root用户配置为例,但是期间会插入修改目录权限的步骤。

3. 安装必要的软件

我们将尽量通过piporpip3来安装包,而非使用发行版源里的工具,避免源里工具版本过低造成的问题。

更新源,并安装python。

python2:

apt update
apt install python-pip python-dev

python3:

apt update
apt install python3-pip python3-dev

4. 创建python虚拟环境

4.1 安装virtualenv

为了将我们的Flask应用与系统里的其他python文件项目隔离开,接下来配置python虚拟环境。

使用pip安装virtualenv

# python2
pip install virtualenv
# python3
pip3 install virtualenv

现在,为我们的Flask应用创建目录:

mkdir ~/myproject
cd ~/myproject

或者直接在lnmp的目录里,clone你的项目:

cd /home/wwwroot/
git clone XXXX/myproject.git
# 或者直接拷贝你的项目到对应的域名目录下

FindHao注:

由于我们是在root下操作的,因此应该将项目的文件所属权都移交给www

bash chown -R www.www ./*

由于lnmp会在域名目录下创建一个.user.ini的文件,导致你无法删除lnmp创建的目录,运行下面代码后删除即可:

chattr -i ``/home/wwwroot/yoursite/``.user.ini

如果是需要修改文件,记得修改完以后运行:

chattr +i ``/home/wwwroot/yoursite/``.user.ini

4.2 创建并激活虚拟环境

创建虚拟环境的目录:

virtualenv myenv

myenv的目录是用来存放本地python的镜像,以及后面通过pip安装的包将安装到myenv目录里,而不是系统的目录里。

在安装之前,需要先激活刚刚建立的虚拟环境:

source myenv/bin/activate

你的命令行前面会多个提示,表明你是在虚拟环境操作:

(myenv)user@host:~/myproject#.

5. 设置Flask应用

5.1 安装Flaks和uWSGI

注意,无论你使用的哪个python版本,进入虚拟环境以后,应该使用pip,而不是pip3

(myenv) # pip install uwsgi flask

5.2 建立sample

现在我们创建一个简单的样例程序来测试flask和uwsgi是否正常运行。

(myenv) # vim index.py

FindHao注:

修改文件权限:

bash chown www.www index.py

内容如下:

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "<h1 style='color:blue'>Hello There!</h1>"

if __name__ == "__main__":
    app.run(host='0.0.0.0')

如果你开启了防火墙,要在你防火墙规则里关闭对5000端口的禁用。

运行我们的flask sample:

(myenv) # python index.py

在浏览器里访问你的vps ip+:5000端口:

http://server_domain_or_IP:5000

如果看到如下内容表示运行正常,可以CTRL C终止sample的运行继续下一步了。

Flask sample app

6. 配置uWSGI

6.1 测试uWSGI

首先我们需要测试uWSGI运行正常:

(myenv) # uwsgi --socket 0.0.0.0:5000 --protocol=http -w wsgi:app

你应该再次看到上面的hell there的提示。

CTRL C终止,并deactivate退出虚拟环境

6.2 创建uWSGI配置文件

为了让我们的项目启动和配置更灵活,我们创建uWSGI配置文件:

# vim myproject.ini

内容如下:

[uwsgi]
module = wsgi:app

master = true
processes = 5

socket = myproject.sock
chmod-socket = 660
vacuum = true

die-on-term = true

stats = 127.0.0.1:1234

logto = /var/log/myproject.log

[uwsgi]头表示我们这是个uwsgi的配置。module指向wsgi.py文件,文件里的回调是app。

接下来的部分表明项目运行在master mode,并且有五个worker进程处理请求。

在上面测试的时候,我们的uWSGI是通过网络端口暴露出来的,但是由于后面我们将使用nginx来处理实际的client连接,然后传递给uwsgi,而由于这些操作都是在一个机器上运行的,因此这里我们改成socket的模式更安全快速。我们指定socket文件是当前项目目录下的myproject.sock

我们还必须改变socket的权限。待会我们会迁移uWSGI进程的所属组到nginx的组,因此我们必须确保socket的所属组用户能从它那里读写信息。同时在进程结束的时候,也需要清理socket(vacuum)。

die-on-term,可以确保init system和uWSGI有相同的环境。

logto是保存日志文件。

stats监控程序的url,只有设置了这个参数以后才能用 uwsgitop :1234来观看监控,类似于linux的top命令

你可能会注意到,我们没有像前面命令行一样指定一个协议,这是因为uWSGI默认使用uwsgi协议,一个快速的二进制协议,nginx内置了这个协议,用这个协议比http协议更快。

6.3 uwsgitop

前面的配置文件定义了stats参数,则可以安装pip3 install uwsgitop并通过uwsgitop :1234来像top一样查看前面项目的运行情况。

6.4 日志

前面我们指定了logto来保存日志,但是www用户对日志的目录没有写权限,因此需要手动建立这个log文件,并chown给www。

同时由于默认日志是一直在写入,文件会不停的增长,因此还需要使用系统的logrotate日志工具对其进行处理。

创建一个日志的配置文件

# vim /etc/logrotate.d/myproject-log-file

内容如下:

/var/log/myproject.log {
    monthly
    rotate 5
    compress
    delaycompress
    missingok
    notifempty
    create 644 www www
    postrotate
        /usr/bin/killall -HUP rsyslogd
    endscript
}
  • monthly: 日志文件将按月轮循。其它可用值为‘daily’,‘weekly’或者‘yearly’。
  • rotate 5: 一次将存储5个归档日志。对于第六个归档,时间最久的归档将被删除。
  • compress: 在轮循任务完成后,已轮循的归档将使用gzip进行压缩。
  • delaycompress: 总是与compress选项一起用,delaycompress选项指示logrotate不要将最近的归档压缩,压缩将在下一次轮循周期进行。这在你或任何软件仍然需要读取最新归档时很有用。
  • missingok: 在日志轮循期间,任何错误将被忽略,例如“文件无法找到”之类的错误。
  • notifempty: 如果日志文件为空,轮循不会进行。
  • create 644 www www: 以指定的权限创建全新的日志文件,同时logrotate也会重命名原始日志文件。
  • postrotate/endscript: 在所有其它指令完成后,postrotate和endscript里面指定的命令将被执行。在这种情况下,rsyslogd 进程将立即再次读取其配置并继续运行。

7. 创建systemd文件

Systemd 是 Linux 系统工具,用来启动守护进程,已成为大多数发行版的标准配置。

接下来我们将创建一个service文件来保证系统自动启动uWSGI和我们的Flask应用。

以Debian为例,创建一个myproject.service文件:

# vim /lib/systemd/system/myproject.service

内容如下:

[Unit]
Description=uWSGI instance to serve myproject
After=network.target

[Service]
User=www
Group=www
WorkingDirectory=/home/sammy/myproject
Environment="PATH=/home/sammy/myproject/myprojectenv/bin"
ExecStart=/home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini

PIDFile=/run/findhao.net.pid
ExecReload=/home/wwwroot/www.findhao.net/ftbenv/bin/uwsgi --reload /run/findhao.net.pid
ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/findhao.net.pid
TimeoutStopSec=3
KillMode=mixed

[Install]
WantedBy=multi-user.target

7.1 Unit字段

[Unit]区块通常是配置文件的第一个区块,用来定义 Unit 的元数据,以及配置与其他 Unit 的关系。

  • Description:简短描述
  • After:如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之前启动

7.2 Service字段

[Service]区块用来 Service 的配置,只有 Service 类型的 Unit 才有这个区块。

  • ExecStart:启动当前服务的命令
  • ExecReload:重启当前服务时执行的命令
  • ExecStop:停止当前服务时执行的命令
  • Environment:指定环境变量
  • KillMode: mixed:主进程将收到 SIGTERM 信号,子进程收到 SIGKILL 信号

user和group用来指定进程所属用户和组。lnmp默认是www.www。设置working directory和path来告诉init system我们的项目在哪里,虚拟环境是怎样的。然后执行uwsgi开启Flask应用。

FindHao注:

在这个service文件里,我添加了PIDFileExecReloadExecStop等几个字段,因为如果没有reload和stop字段,要重启我们的Flask应用,只能通过重启vps或者杀掉uwsgi进程的方式。

PIDFile指定了我们Flask应用的进程文件,可以传给后面stop和reload用。

reload使用uwsgi自带的reload。

stop则通过进程文件的防止找到指定进程并结束掉它。

7.3 Install 字段

[Install]通常是配置文件的最后一个区块,用来定义如何启动,以及是否开机启动。

  • WantedBy:它的值是一个或多个 Target,当前 Unit 激活时(enable)符号链接会放入/etc/systemd/system目录下面以 Target 名 + .wants后缀构成的子目录中

7.4 运行

保存上面的配置文件后,常用的systemd命令有:

systemctl start myproject # 开启应用
systemctl enable myproject # 添加开机自启动
systemctl disable myproject # 取消开机启动
systemctl restart myproject # 重启应用
systemctl reload myproject # 重新加载配置
systemctl stop myproject # 停止应用
systemctl status myproject # 查看应用状态

开启应用后,查看应用状态,如果是active,表明成功启动运行,如果failed,可以通过journalctl查看运行日志,并G(vim的查看形式,即Shift + g到最后一行)看看启动的错误是什么。

8. 配置Nginx来处理请求

如果是lnmp安装的nginx,则nginx的配置目录为/usr/local/nginx/conf/vhost

如果之前没有安装,则可以通过apt直接安装nginx,但是源里的nginx可能版本比较老,对于一些新特性不支持,建议添加nginx官方源里安装,参考 《nginx配置https》 3.6 nginx 支持HTTP2。单独安装的nginx配置文件目录一般为/etc/nginx/sites-available

在nginx的配置目录新建一个nginx的配置文件myproject,内容如下:

server {
    listen 80;
    server_name server_domain_or_IP;

    location / {
        include uwsgi_params;
        uwsgi_pass unix:/home/sammy/myproject/myproject.sock;
    }
}

listen表示监听80端口,server_name则是你的域名或者ip。

localtion /则表示对于域名或者ip/的请求处理方式。首先通过包含uwsgi_params来加载一些默认的uWSGI参数。然后uwsgi_pass转发请求给我们定义的socket。

这只是创建了可用的配置文件,如果要启用,还需要将其软连接到enable目录:

# ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled

检查我们的配置文件是否编写正确:

# nginx -t

如果提示ok,则重启nginx:

systemctl restart nginx

访问我们的域名或者ip,可以看成已经正常运行。

Reference

lnmp无法删除目录,目录包含.user.ini

How To Serve Flask Applications with uWSGI and Nginx on Ubuntu 16.04

uwsgi配置https以及python2无法使用supervisor

Systemd 入门教程:命令篇

Linux日志文件总管——logrotate

python uwsgi 部署以及优化

uWSGI 简介


文章版权归 FindHao 所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明作者 FindHao 和本文原始地址:
https://findhao.net/easycoding/2218.html

Comments