【Flask】 利用uWSGI和Nginx发布Flask应用
【Flask】 利用uWSGI和Nginx发布Flask应用
默认已经准备好python环境并且已经安装好了flask
一 安装uwsgi
二 安装nginx
https://www.cnblogs.com/wyd168/p/6636529.html
因为Flask比较容易上手,之前也拿flask写过几个小项目,不过当时天真地以为只要在服务器上nohup跑一个python脚本就算是成功发布了这个flask项目。实际上这还面临很多问题,比如并发性不好,不支持异步(虽然也可以在run里面加上threaded之类的参数来解决,但终究不是正途)等等。真正通用的做法应该是用某些web容器来启动项目。接下来说明做法,整个过程主要参考了这篇文章(https://segmentfault.com/a/1190000004294634)
我测试部署的系统是CentOS7 x86_64,环境搭建部分(包括安装python,安装flask以及flask相关依赖)的工作就跳过了。从安装uWSGI开始讲起。
■ uwsgi的安装和配置
uWSGI是一个由python实现的web容器,可以兼容性比较好地发布Django,Flask等pythonweb框架的应用。因为本质上来说uwsgi是python的一个模块,所以可以用pip install uwsgi直接来安装它。
安装完成之后可以在一个合适的目录建立一个uwsgi服务器的配置文件。比如我选择在项目的根目录建立了一个uwsgiconfig.ini的文件。顺便一提,除了ini格式的配置,uwsgi还支持json,xml等多种多样的配置格式。这里以ini格式为例。
一个典型的配置文件如下:
[uwsgi] socket = 127.0.0.1:5051 pythonpath = /home/wyz/flask module = manage wsgi-file = /home/wyz/flask/manage.py callable = app processes = 4 threads = 2 daemonize = /home/wyz/flask/server.log
依次解释一下这些配置项。socket指出了一个套接字,相当于为外界留出一个uwsgi服务器的接口。需要注意的是,socket不等于http。换句话说用这个配置起来的uwsgi服务器是无法直接通过http请求成功访问的,这一点后面还会提到,是遇到的一个坑。
pythonpath指出了项目的目录,module指出了项目启动脚本的名字而紧接着的wsgi-file指出了真正的脚本的文件名。callable指出的是具体执行.run方法的那个实体的名字,一般而言都是app=Flask(__name__)的所以这里是app。processes和threads指出了启动uwsgi服务器之后,服务器会打开几个并行的进程,每个进程会开几条线程来等待处理请求,显然这个数字应该合理,太小会使得处理性能不好而太大则会给服务器本身带来太大负担。daemonize项的出现表示把uwsgi服务器作为后台进程启动,项的值指向一个文件表明后台中的所有输出都重定向到这个日志中去。
以上这些配置项都是一些最为常见的配置项,实际上uwsgi还有很多很多配置。。除了写一个配置文件的启动方式之外,还有命令行的启动方式,这里就不多说了。请需要的自己百度。。【抱歉】
此外上面也说到这次碰到的一个坑,就是关于socket和http的差别。从概念上来说,socket本身不是协议而是一种具体的TCP/IP实现方式,而HTTP是一种协议且基于TCP/IP。具体到这个配置这里来,如果我只配了socket = 127.0.0.1:5051的话,通过浏览器或者其他HTTP手段是无法成功访问的。而在uwsgi这边的日志里会提示请求包的长度超过了最大固定长度。另一方面,如果配置的是http = 127.0.0.1:5051的话,那么就可以直接通过一般的http手段来访问到目标。但这会引起nginx无法正常工作。正确的做法应该是,如果有nginx在uwsgi之前作为代理的话应该配socket,而如果想让请求直接甩给uwsgi的话那么就要配http。
配置完成之后就可以键入 uwsgi 配置文件.ini来启动uwsgi,再查看日志(如果配置了daemonize的话)如果最终没有报错,ps也能看到processes指定个数的uwsgi进程在跑的话说明成功启动。如果直接把uwsgi作为留给外部的连接接口发布应用的话当然也可以,但是一般而言我们肯定还要在uwsgi前面再加上一个nginx。nginx的好处在于可以进行安全过滤,防DDOS攻击,多台机器的负载均衡等工作。
关于uwsgi服务器的停止,官方文档说可以uwsgi -HUP之类的命令操作,但是这需要找到这个uwsgi的pid,目前为止我都还是很粗暴地killall -9 uwsgi了。。
■ nginx的安装和配置
最开始用yum install nginx装了好多此还是报缺少libpcre.so.0的错,网上搜了一通发现可能是因为我用的是CentOS7版本的系统而yum源中还是适用于CentOS6的包。所以不如去网上找个rpm包或者直接下个源码包来编译安装。。。
nginx常用命令:
nginx 启动nginx
nginx -s stop/reload 停止nginx/重载配置文件
nginx -v 查看版本
nginx -t 测试配置文件是否有语法上的错误等
安装完成后默认的nginx的配置文件位于/etc/nginx/conf.d/default.conf,我直接修改了这个文件。在修改之前可以考虑先备个份。如果需要指定配置文件开启nginx可以加入-c参数。其实nginx默认读取的文件是/etc/nginx/nginx.conf,打开这个文件看看可以看到在其http块中有些include /etc/nginx/conf.d/*.conf,所以在那里的default.conf可以直接写server块。
之前也了解过一点关于nginx的配置问题,其要义大概就是nginx的配置文件格式比较要紧,比如要有大括号,句尾有分号等等。另外以#开头的行都是注释,都可以不用管。在nginx的这个配置中我们主要修改以下内容:
server { listen 80; //默认的web访问端口 server_name xxxxxx; //服务器名 #charset koi8-r; access_log /home/wyz/flask/logs/access.log; //服务器接收的请求日志,logs目录若不存在需要创建,否则nginx报错 error_log /home/wyz/flask/logs/error.log; //错误日志 location / { include uwsgi_params; //这里是导入的uwsgi配置 uwsgi_pass 127.0.0.1:5051; //需要和uwsgi的配置文件里socket项的地址 //相同,否则无法让uwsgi接收到请求。 uwsgi_param UWSGI_CHDIR /home/wyz/flask; //项目根目录 uwsgi_param UWSGI_SCRIPT manage:app; //启动项目的主程序(在本地上运行 //这个主程序可以在flask内置的 //服务器上访问你的项目) } }
这样配置完后,当外部有一个80端口的请求送到本机时,先让nginx开始处理。nginx进行一些处理之后转发给这里配置的uwsgi_pass地址,刚好传送给uwsgi处理。再由uwsgi来调用项目中的代码处理请求返回。再来回味一下上面那个坑,如果当时仅仅配了一个http项而没有配置socket的话,就会导致一切容器启动都顺利,但是当我把请求发送给80端口的时候迟迟不来响应,直到超时。
* 经网友提醒,这其实是一个Nginx和uWSGI之间配置协同的一个问题。如果uWSGI直接通过HTTP方式对外提供服务,那么nginx中需要配置proxy_pass,指出HTTP服务具体套接字,从而实现请求的转发(参考zabbix安装时的nginx配置就是这样的)。而如果将uWSGI配置为socket,通过socket对外提供服务(由于socket不涉及具体的协议,外部没法直接通过uWSGI端口访问服务也更加安全一些。比如可以在nginx中配置一些URL的拒接防止sql注入之类的),那么nginx配置就应该得是uwsgi_pass来实现请求的转发。 proxy_pass配置的时候写http://,即表示是走http协议的;uwsgi_pass的时候未指出协议,表示走socket。