你好!欢迎阅读个人博文,你能够跳转到个人我的博客网站,会有更好的排版效果和功能。
此外,本篇博文为本人Pushy原创,如需转载请注明出处:https://pushy.site/posts/1519817202html
我在不少的博客中都看过有关Flask
应用的部署,也有不少博主在开博后都记录了部署的教程,由于其中的坑能够说很多。一开始我在网上看到相比较与Ubuntu
,CentOS
由于更新少做为服务器的操做系统会更加稳定。因此在第一次购买云服务器时,我选择了CentOS
,后来因为CentOS
不一样发行版的Nginx
缘故,我又换成了Ubuntu
的镜像前端
首先呢,咱们先来了解下关于Web服务器与Web应用还有WSGI之间的联系python
WSGI
(Web Server Gateway Interface),翻译为Python web
服务器网关接口,即Python
的Web
应用程序(如Flask
)和Web
服务器(如Nginx
)之间的一种通讯协议。也就是说,若是让你的Web
应用在任何服务器上运行,就必须遵循这个协议。nginx
那么实现WSGI
协议的web服务器有哪些呢?就好比uWSGI
与gunicorn
。二者均可以做为Web服务器。可能你在许多地方看到的都是采用Nginx
+ uWSGI
(或gunicorn
)的部署方式。实际上,直接经过uWSGI
或gunicorn
直接部署也是可让外网访问的,那你可能会说,那要Nginx
何用?别急,那么接来下介绍另外一个Web服务器——Nginx
git
Nginx
做为一个高性能Web服务器,具备负载均衡、拦截静态请求、高并发...等等许多功能,你可能要问了,这些功能和使用Nginx
+ WSGI
容器的部署方式有什么关系?github
首先是负载均衡,若是你了解过OSI模型的话,其实负载均衡器就是该模型中4~7层交换机中的一种,它的做用是可以仅经过一个前端惟一的URL访问分发到后台的多个服务器,这对于并发量很是大的企业级Web站点很是有效。在实际应用中咱们一般会让Nginx
监听(绑定)80
端口,经过多域名或者多个location分发到不一样的后端应用。web
其次是拦截静态请求,简单来讲,Nginx
会拦截到静态请求(静态文件,如图片),并交给本身处理。而动态请求内容将会经过WSGI
容器交给Web
应用处理;flask
Nginx
还有其余不少的功能,这里便不一一介绍。那么前面说了,直接经过uWSGI
或gunicorn
也可让外网访问到的,可是鉴于Nginx
具备高性能、高并发、静态文件缓存、及以上两点、甚至还能够作到限流与访问控制,因此选择Nginx
是颇有必要的;后端
这里能够说明,若是你选择的架构是:Nginx + WSGI容器 + web应用,WSGI容器至关于一个中间件;若是选择的架构是uWSGI + web应用,WSGI容器则为一个web服务器浏览器
该篇部署的教程是在你已经购买好虚拟主机,而且已经搭建好开发环境的前提下进行的,若是你尚未搭建好开发环境,能够参考我写的文档:
广泛的部署方式都是经过让Nginx
绑定80
端口,并接受客户端的请求将动态内容的请求反向代理给运行在本地端口的uWSGI
或者Gunicorn
,因此既能够经过Nginx
+ uWSGI
也能够经过Nginx
+ Gunicorn
来部署Flask
应用,这篇教程中都将一一介绍这两种方法
固然采用不一样的WSGI
容器,Nginx
中的配置也会有所不一样
咱们如今虚拟环境下安装好uWSGI
:
(venv) $ pip install uwsgi
安装完成以后咱们在项目的目录下(即你实际建立的Flask项目目录,在本文所指的项目目录都假设为/www/demo)建立以.ini
为扩展名的配置文件。在设置与Nginx
交互的时候有两种方式:
第一种是经过配置网络地址,第二种是经过本地的.socket
文件进行通讯。须要注意的是,不一样的交互方式下,Nginx
中的配置也会有所不一样
若是采用的是第一种网络地址的方式,则将以前建立uwsgi.ini
配置文件添加以下的配置内容:
[uwsgi] socket = 127.0.0.1:8001 //与nginx通讯的端口 chdir = /www/demo/ //你的Flask项目目录 wsgi-file = run.py callable = app //run.py文件中flask实例化的对象名 processes = 4 //处理器个数 threads = 2 //线程个数 stats = 127.0.0.1:9191 //获取uwsgi统计信息的服务地址
这里的wsgi-file
参数所指的run.py
实际上是启动文件,你也可使用manage.py
。不过我一般习惯建立一个这样的文件,能够直接运行该文件来启动项目:
from app import app if __name__ == '__main__': app.run()
保存好配置文件后,就能够经过以下的命令来启动应用了:
(venv) $ uwsgi uwsig.ini
若是你采用的是第二种本地socket
文件的方式,则添加以下的配置内容:
[uwsgi] socket = /www/demo/socket/nginx_uwsgi.socket //与nginx通讯的socket文件 chdir = /www/demo/ wsgi-file = run.py callable = app processes = 4 threads = 2 stats = 127.0.0.1:9191
能够看到,其实与网络地址的配置方式只有socket
参数的配置不一样,在这里填写好路径名和文件名并启动uWSGI
后,将会自动在改目录下生成nginx_uwsgi.socket
文件,这个文件就是用来与Nginx
交互的。
首先咱们来经过apt
安装Nginx
:
$ sudo apt-get install nginx
安装完成以后,咱们cd
到/etc/nginx/
的目录下(可能因为不一样系统致使不一样的Nginx发行版缘故,目录有所差异,在此只针对Ubuntu
中的发行版的Nginx),能够看到Nginx
的全部配置文件。
其中nginx.conf
文件为主配置文件,能够用来修改其全局配置;sites-available
存放你的配置文件,可是在这里添加配置是不会应用到Nginx
的配置当中,须要软链接到同目录下的sites-enabled
当中。可是在我实际操做的过程当中中,当我在sites-available
修改好配置文件后,会自动更新到sites-enabled
。若是没有的话,则须要像上述的操做那样,将修改好的配置文件软连接到sites-enabled
当中
在上边说到,配置uWSGI
有两种与Nginx
交互的方式,那么选择不一样的方式的话在Nginx
的配置也会有所不一样:
第一种:网络配置方式:
这里的proxy_set_header
设置的三个参数的做用都是可以直接得到到客户端的IP
,若是你感兴趣能够参考:Nginx中proxy_set_header 理解
用include uwsgi_params
导入uWSGI
所引用的参数,经过uwsgi_pass
反向代理给在localhost:8001
运行的uWSGI
:
server { listen 80; # 监听的端口号 root /www/demo; #Flask的项目目录 server_name xxx.xx.xxx.xxx; # 你的公网ip或者域名 location / { proxy_set_header x-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; include uwsgi_params; uwsgi_pass localhost:8001; } # 配置static的静态文件: location ~ ^\/static\/.*$ { root /www/demo; # 注意!这里不须要再加/static了 } }
在每次完Nginx配置文件内容后,须要经过以下的命令来重启Nginx:
$ nginx -s reload
第二种:socket文件方式:
与上边的配置内容大致相同,只是在配置uwsgi_pass
不是反向代理给网络地址,而是经过socket
文件进行交互,咱们只须要指定以前设置的路径和文件名便可:
server { listen 80; root /www/demo; server_name xxx.xx.xxx.xxx; location / { proxy_set_header x-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; include uwsgi_params; uwsgi_pass unix:/www/demo/socket/nginx_uwsgi.socket; } location ~ ^\/static\/.*$ { root /www/demo; } }
首先先在虚拟环境下安装Gunicorn
:
(venv) $ pip install gunicorn
安装完成后,咱们来建立以.py
结尾的配置文件,这里我参考了Jiyuankai的GitHub关于Gunicorn
的配置文件内容:
from gevent import monkey monkey.patch_all() import multiprocessing debug = True loglevel = 'debug' bind = '127.0.0.1:5000' //绑定与Nginx通讯的端口 pidfile = 'log/gunicorn.pid' logfile = 'log/debug.log' workers = multiprocessing.cpu_count() * 2 + 1 worker_class = 'gevent' //默认为阻塞模式,最好选择gevent模式
须要注意的是要在配置文件的同层目录下建立log
文件,不然运行gunicorn
将报错。添加完配置内容并保存为gconfig.py
文件后,咱们就也能够经过gunicorn
来运行Flask
应用了:
(venv)$ gunicorn -c /www/demo/gconfig.py run:app
和uWSGI
的任意一种配置方法相似,只是在location
中的配置有所不一样:
server { listen 80; root /www/demo; server_name xxx.xx.xxx.xxx; location / { proxy_set_header x-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_pass http://localhost:5000/; # gunicorn绑定的端口号 } # 配置static的静态文件: location ~ ^\/static\/.*$ { root /www/demo; } }
经过Gunicorn的Nginx配置中,咱们只须要经过proxy_pass
参数反向代理给运行在http://localhost:5000/
上的Gunicorn
若是你采起如上的任意一种部署方式,在Nginx与uWSGI或Gunicorn同时运行,而且配置无误的状态下,那么你如今应该是能够经过你的公网ip
或者域名访问到你的网站了。
可是还有一个问题,到目前为止,uWSGI和gunicorn都是直接经过命令行运行,并不可以在后台运行,也是当咱们关闭了xShell(或者你使用的是Putty及其余SSH链接的软件),将没法再访问到你的应用。因此咱们须要让uWSGI或gunicorn在后台运行,也就是所谓的daemon(守护进程)。
若是你熟悉Linux命令,你应该知道在Linux中后台运行能够经过nohup
命令,例如咱们要让gunicorn在后台运行,咱们只须要运行nohup
命令:
(venv) $ nohup gunicorn -c gconfig.py run:app &
运行后你能够经过ps -e | grep gunicorn
指令来查看到当前gunicorn的运行状态:
若是你选择的是uWSGI,一样也能够经过nohup
命令来实现守护进程:
(venv) $ nohup uwsgi uwsgi.ini &
这样你就能够关闭链接服务器的终端,还能经过你的浏览器访问到你的Flask
应用了!
可是nohup
运行的后台程序并不可以可靠的在后台运行,咱们最好让咱们的后台程序可以监控进程状态,还能在乎外结束时自动重启,这就可使用一个使用Python开发的进程管理程序supervisor。
首先咱们经过apt
来安装supervisor:
$ sudo apt-get install supervisor
安装完成后,咱们在/etc/supervisor/conf.d/
目录下建立咱们控制进程的配置文件,并以.conf结尾,这样将会自动应用到主配置文件当中,建立后添加以下的配置内容:
[program:demo] command=/www/demo/venv/bin/gunicorn -c /pushy/blog/gconfig.py run:app directory=/www/demo //项目目录 user=root autorestart=true //设置自动重启 startretires=3 //重启失败3次
在上面的配置文件中,[program:demo]
设置了进程名,这与以后操做进程的状态名称有关,为demo
;command
为进程运行的命令,必须使用绝对路径,而且使用虚拟环境下的gunicorn
命令;user
指定了运行进程的用户,这里设置为root
保存配置文件以后,咱们须要经过命令来更新配置文件:
$ supervisorctl update
命令行将显示:demo: added process group
,而后咱们来启动这个demo
进程:
$ supervisorctl start demo
固然你也直接在命令行输入supervisorctl
进入supevisor的客户端,查看到当前的进程状态:
demo RUNNING pid 17278, uptime 0:08:51
经过stop
命令即可以方便的中止该进程:
supervisor> stop demo
参考资料: