flask+uwsgi+supervisor+nginx在局域网服务器上部署实践

flask可以快速的搭建http服务,但是为了搭建网站还是需要web服务器和相关监控管理操作,一套flask、uwsgi、supervisor、nginx是较好的完整解决方案。

本文对自己学习做一个记录,以一个简单的显示‘Hello Flask!’程序来测试,跑通整个流程,方式是在局域网服务器上部署,在个人电脑上访问。

服务器系统是centos7
安装了pyenv
pyenv 切换到python3.5版本,不懂版本切换的可以参考我这边文章https://www.jianshu.com/p/492853d0e683

新建一个简单程序test_flask.py

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello Flask!'

if __name__ == '__main__':
    app.run(host='0.0.0.0',port=8080)

测试局域网访问

在服务器上运行# python test_flask.py,出现如下:


flask

此时,在个人电脑浏览器输入10.12.28.27:8080,(10.12.28.27是我服务器ip),出现如下错误:


连接不上

ok,此时原因可能是服务器防火墙打开了,需要关闭,在服务器上输入关闭防火墙命令(注意系统不同命令也不同):
centos7关闭防火墙

关闭后,在个人电脑浏览器输入10.12.28.27:8080,出现hello,Flask!(注意web进程一定要设置ip:0.0.0.0,公网才能访问到)


访问成功返回

搭建uWSGI服务

Flask 是一个 Web 应用框架,框架的作用在于处理 request 和 reponse,使用的是 Python 自带的 simple HTTPServer 创建的,在安全性和效率上都是不行的,而uWSGI 是一个全功能的 HTTP 服务器,他要做的就是把 HTTP 协议转化成语言支持的网络协议。比如把 HTTP 协议转化成 WSGI 协议,让 Python 可以直接使用。 uwsgi 是一种 uWSGI 的内部协议,使用二进制方式和其他应用程序进行通信。
现在,我们结束上面的flask服务,在服务器上安装uWSGI,直接输入如下命令

pip install uwsgi

安装完,直接输入启动命令:

uwsgi --http 0.0.0.0:8080 --home env --wsgi-file test_flask.py --callable app --master

出现如下错误

Fatal Python error: Py_Initialize: Unable to get the locale encoding
ImportError: No module named 'encodings'

原因是--home参数,以前uwsgi需要这个参数来指定python环境变量的目录,现在不需要这个参数,直接:

uwsgi --http 0.0.0.0:8080 --wsgi-file test_flask.py --callable app --master

运行成功:


uwsgi

在个人电脑浏览器输入10.12.28.27:8080,出现Hello,Flask!(注意uwsgi配置ip:0.0.0.0,公网才能访问到)
当然,为了减少输入命令麻烦,可以用配置文件来启动uwsgi, 在当前目录新建 vi uwsgi_config.ini:

[uwsgi]
# uwsgi 启动时所使用的地址与端口
# socket = 0.0.0.0:8080 
# 外网访问端口,如果直接用uWSGI外网,这里由于使用了Nginx,故注释掉
http= 0.0.0.0:8080
# 指向项目地址
chdir = /root/zlw/web_flask/
# python 启动程序文件,应该在上面的目录中
wsgi-file = test_flask.py 
# python 程序内用以启动的 application 变量名
# app 是 manage.py 程序文件内的一个变量,这个变量的类型是 Flask的 application 类
callable = app 
# 处理器数
processes = 4
# 线程数
threads = 2
#状态检测地址
stats = 127.0.0.1:9191

配置文件启动uwsgi(这里uwsgi_config.ini是在当前目录下):

uwsgi uwsgi_config.ini

ok,此时,你的应用已经获得了高并发的处理能力,但对于静态文件的处理uwsgi比较笨拙,并且这种方式安全性也不高,所以要加上Nginx反向代理服务。

在增加Nginx服务之前,我们还有一个事情要做,考虑一下:我现在有一个进程需要每时每刻不断的跑,但是这个进程又有可能由于各种原因有可能中断。当进程中断的时候我希望能自动重新启动它,此时,我就需要使用到了Supervisor,supervisor管理进程,是通过fork/exec的方式将这些被管理的进程当作supervisor的子进程来启动,所以我们只需要将要管理进程的可执行文件的路径添加到supervisor的配置文件中就好了。此时被管理进程被视为supervisor的子进程,若该子进程异常中断,则父进程可以准确的获取子进程异常中断的信息,通过在配置文件中设置autostart=ture,可以实现对异常中断的子进程的自动重启。

搭建supervisor进程管理

没有supervisor之前启动uwsgi服务是这样:uwsgi uwsgi_config.ini
现在我准备使用Supervisor,故uwsgi启动命令仅供测试的时候用。
安装supervisor:

yum install supervisor

打开全局配置文件(先找到配置文件路径:find / -name supervisord.conf)

vi /etc/supervisord.conf

在末尾加入:

[program:Test-flask]
# 启动命令入口
command=uwsgi /root/zlw/web_flask/uwsgi_config.ini

# 命令程序所在目录
directory=/root/zlw/web_flask
#运行命令的用户名
user=root

autostart=true   # supervisor启动的时候是否随着同时启动
autorestart=true  # 当程序跑出exit的时候,这个program会自动重启
startsecs=3   # 程序重启时候停留在runing状态的秒数
#日志地址
stdout_logfile=/root/zlw/web_flask/uwsgi_supervisor.log

supervisor 相关操作:

启动:supervisord
打开命令行: supervisorctl
命令行中查看命令: help
命令行中查看状态: status

或者
supervisorctl status //查看状态
supervisorctl stop [进程名] //停止
supervisorctl start [进程名]

输入命令supervisord启动,子程序uwsgi服务将随之启动。
这个时候输入: ps -ef | grep uwsgi
能看到运行的uwsgi程序:


uwsgi已经启动

在个人电脑浏览器输入10.12.28.27:8080,出现Hello,Flask!(注意uwsgi配置ip:0.0.0.0,公网才能访问到)
supervisor搭建完毕。

搭建Nginx服务

从上面的讲解中,我们知道,uWSGI 可以起到 Web 服务器的作用,那么为什么有了 uWSGI 还需要 Nginx 呢?

最普遍的说法是 Nginx 对于处理静态文件更有优势,性能更好。其实如果是小网站,没有静态文件需要处理,只用 uWSGI 也是可以的,但加上 Nginx 这一层,优势可以很具体:

  • 对于运维来说比较方便,如果服务器被某个 IP 攻击,在 Nginx 配置文件黑名单中添加这个 IP 即可,如果只用 uWSGI,那么就需要在代码中修改了。另一方面,Nginx 是身经百战的 Web 服务器了,在表现上 uWSGI 显得更专业,比如说 uWSGI 在早期版本里是不支持 https 的,可以说 Nginx 更安全。

  • Nginx 的特点是能够做负载均衡和 HTTP 缓存,如果不止一台服务器,Nginx 基本就是必选项了,通过 Nginx,将资源可以分配给不同的服务器节点,只有一台服务器,也能很好地提高性能,因为 Nginx 可以通过 headers 的Expires or E-Tag,gzip 压缩等方式很好地处理静态资源,毕竟是 C 语言写的,调用的是 native 的函数,针对 I/O做了优化,对于动态资源来说,Nginx 还可以实现缓存的功能,配合 CDN 优化(这是 uWSGI 做不到的)。Nginx 支持epoll/kqueue 等高效网络库,能够很好地处理高并发短连接请求,性能比 uWSGI 不知道高到哪里去了。

  • 如果服务器主机上运行了PHP,Python 等语言写的多个应用,都需要监听80端口,这时候 Nginx 就是必选项了。因为我们需要一个转发的服务。
    安装:

yum install nginx

打开全局配置文件(先找到配置文件路径:find / -name nginx.conf)

vi /etc/nginx/nginx.conf

修改配置:(注意先备份一份)

server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  10.12.28.27;  # 这里是服务域名,请求的url必须包含该字段Nginx才能响应。
        #root         /usr/share/nginx/html;

        # Load configuration files for the default server block.
        # include /etc/nginx/default.d/*.conf;

        access_log /root/zlw/web_flask/nginx_access.log;  # 服务器接收的请求日志
        error_log /root/zlw/web_flask/nginx_error.log;  # 错误日志
        location / {
            include  uwsgi_params;
            uwsgi_pass 0.0.0.0:8080;  # 指向uwsgi 所应用的内部地址,所有请求将转发给uwsgi 处理
            uwsgi_param UWSGI_CHDIR  /root/zlw/web_flask; # 指向网站根目录
            uwsgi_param UWSGI_SCRIPT test_flask:app;  # 指定启动程序

nginx一些操作:

验证配置是否正确:nginx -t
启动: nginx
重启: nginx -s reload
停止: nginx -s quit

启动后,在个人电脑浏览器输入10.12.28.27:80,出现很卡的想象,一直出不来结果,等好久提示如下:


nginx配置错误

分析原因:配置出现问题。
重新设置配置,将默认配置/etc/nginx/nignx.conf还原为原来的配置。并且默配置文件内有如下配置

include /etc/nginx/conf.d/*.conf;

ok,新建一个配置:

vi /etc/nginx/conf.d/my_nginx.conf

输入如下内容:

server {
    listen      80;
    server_name  10.12.28.27;  # 服务器ip,
    charset    utf-8;

    client_max_body_size 100M;

    location / {
        include uwsgi_params;
        #uwsgi_pass  unix:/root/zlw/web_flask/flask_uwsgi.sock;  # sock方式跑不通,原因未知
        uwsgi_pass 127.0.0.1:8080;
    }
}

同时,修改之前的uwsgi_config.ini配置文件(注意自己的文件路径):

vi /root/zlw/web_flask/uwsgi_config.ini
修改为:

[uwsgi]

# uwsgi 启动时所使用的地址与端口
 socket = 127.0.0.1:8080
#socket = /root/zlw/web_flask/flask_uwsgi.sock  # 通过sock文件的方式行不通,原因未知

#permissions for the socket file
#chmod-socket    = 666


# 外网访问端口,如果直接用uWSGI外网,这里由于使用了Nginx,故注释掉
#http= 127.0.0.1:8080

# 指向项目地址
chdir = /root/zlw/web_flask/

# python 启动程序文件
wsgi-file = test_flask.py

# python 程序内用以启动的 application 变量名
# app 是 manage.py 程序文件内的一个变量,这个变量的类型是 Flask的 application 类
callable = app

# 处理器数
processes = 1

# 线程数
threads = 2

#状态检测地址
stats = 127.0.0.1:9191

保存好,重启supervisor,重启nginx

在个人电脑浏览器输入10.12.28.27:80,出现Hello,Flask!
输入10.12.28.27:8080将出现无法访问情况。因为uwsgi 服务ip设置为127.0.0.1了,其他电脑无法访问,只能通过nginx的监听端口80进行访问。若uwsgi 服务指定ip:0.0.0.0:8080,则,其他电脑输入10.12.28.27:8080也能重新hello,flask,当然10.12.28.27:80也能(uwsgi配置ip要和nginx配置一致)


到此能跑通也算大功告成了,但是不能满足,当我们服务器运行了多个flask时该怎么处理呢,下面我们就继续尝试管理多个进程时的相关配置操作。


启动多个Flask进程

我们分别建立两个测试项目:

  • /root/web_flask
  • /root/zlw

每个项目目录下分别有文件:

  • test_flask1.py,uwsgi_config1.ini,logs/
  • test_flask2.py,uwsgi_config2.ini,logs/

test_flask1.py 和test_flask2.py是和上面简单测试程序一样的,uwsgi配置启动端口和检测端口分别不一样。

uwsgi配置
uwsgi_config1.ini:

[uwsgi]
# uwsgi 启动时所使用的地址与端口
 socket = 127.0.0.1:8080 
# 指向项目地址
chdir = /root/web_flask/
# python 启动程序文件
wsgi-file = test_flask1.py
# python 程序内用以启动的 application 变量名
# app 是 manage.py 程序文件内的一个变量,这个变量的类型是 Flask的 application 类
callable = app 
# 处理器数
processes = 1
# 线程数
threads = 2
#状态检测地址
stats = 127.0.0.1:9191

uwsgi_config2.ini:

[uwsgi]
# uwsgi 启动时所使用的地址与端口
 socket = 127.0.0.1:7070 
# 指向项目地址
chdir = /root/zlw/
# python 启动程序文件
wsgi-file = test_flask2.py
# python 程序内用以启动的 application 变量名
# app 是 manage.py 程序文件内的一个变量,这个变量的类型是 Flask的 application 类
callable = app 
# 处理器数
processes = 1
# 线程数
threads = 2
#状态检测地址
stats = 127.0.0.1:7171

此时测试一下,uwsgi分别启动项目(注意只能单个分别启动,ctrl+c结束)
uwsgi /root/web_flask/uwsgi_config1.ini
uwsgi /root/zlw/uwsgi_config2.ini
分别都能启动成功,进行supervisor配置,通过supervisor来同时启动两个项目。

supervisor配置
我的supervisor默认配置是/etc/supervisor.conf,打开会找到类似这样的配置

[include]
files = supervisord.d/*.ini

因此可以在/etc/supervisord.d/目录下的构建两个进程的配置文件.ini各式。当然也可以直接在默认配置文件中增加进程配置。
以下是我的配置(增加两个进程配置文件,同时记得将默认配置文件原来设置的进程配置删除掉):
/etc/supervisord.d/my_flask1.ini

[program:Test-Flask1]
command=uwsgi /root/web_flask/uwsgi_config1.ini
stdout_logfile=/root/web_flask/logs/supervisor.log
autostart=true
autorestart=true
startsecs=5  # 启动5秒内没异常说明启动成功。
priority=1  # 启动优先级
stopasgroup=true  # 程序被终止是否通知用户组
killasgroup=true  #被kill是否通知用户组

/etc/supervisord.d/my_flask2.ini

[program:Test-Flask2]
command=uwsgi /root/zlw/uwsgi_config2.ini
stdout_logfile=/root/zlw/logs/supervisor.log
autostart=true
autorestart=true
startsecs=5  # 启动5秒内没异常说明启动成功。
priority=1  # 启动优先级
stopasgroup=true  # 程序被终止是否通知用户组
killasgroup=true  #被kill是否通知用户组

启动supervisord,打开supervisorctl能看到启动成功。


两个进程启动成功

此时,已经可以在服务器电脑上分别访问127.0.0.1:8080和127.0.0.1:7070,都将返回Hello Flask。

配置Nginx
分别为每个进程配置一个nginx配置文件,文件目录/etc/nginx/conf.d/
有如下文件:
web_flask1.conf:(监听80端口指向127.0.0.1:8080)

server {
    listen      80;
    server_name  10.12.28.27;
    charset    utf-8;
 
    client_max_body_size 100M;

    access_log /root/web_flask1/logs/nginx_access.log;  # 服务器接收的请求日志
    error_log /root/web_flask1/logs/nginx_error.log;  # 错误日志
 
    location / {
        include uwsgi_params;
        #uwsgi_pass  unix:/root/web_flask/flask_uwsgi.sock;
        uwsgi_pass 127.0.0.1:8080;
    }
}

web_flask2.conf:(监听70端口指向127.0.0.1:7070)

server {
    listen      70;
    server_name  10.12.28.27;
    charset    utf-8;
 
    client_max_body_size 100M;

    access_log /root/web_flask2/logs/nginx_access.log;  # 服务器接收的请求日志
    error_log /root/web_flask2/logs/nginx_error.log;  # 错误日志
 
    location / {
        include uwsgi_params;
        #uwsgi_pass  unix:/root/web_flask/flask_uwsgi.sock;
        uwsgi_pass 127.0.0.1:7070;
    }
}

好了,配置结束。重启nginx

在个人电脑浏览器输入10.12.28.27:80,出现Hello,Flask!
在个人电脑浏览器输入10.12.28.27:70,出现Hello,Flask!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容