flask项目线上环境部署

线上环境部署flask,nginx+uWSGI 和nginx+gunicorn,这两种方案,应该如何选择?

前者,高并发稳定一点,部署麻烦一些,坑略多。后者高并发差一点,部署简单,坑少。我的项目是个人的小项目,没有高并发的需求,所以就选择了后者这个方案。在部署方案解说之前我们先来补补课。

一、补课

1. 平时开发直接启动项目,没有任何配置依然可以访问?

因为djaong或者flask自带了一个实现了WSGI协议的server 和 application, 各个web框架也基本上都有自己实现的WSGI server, 但这个server基本上只能用来调试,不能用于生产环境,性能没保障。

2.WSGI,uwsgi,uWSGI

WSGI:全称是Web Server Gateway Interface,WSGI不是服务器,python模块,框架,API或者任何软件,只是一种规范,描述web server如何与web application通信的规范。server和application的规范在PEP 3333中有具体描述。要实现WSGI协议,必须同时实现web server和web application,当前运行在WSGI协议之上的web框架有Bottle, Flask, Django。

WSGI协议主要包括server和application两部分:

  • WSGI server负责从客户端接收请求,将request转发给application,将application返回的response返回给客户端;
  • WSGI application接收由server转发的request,处理请求,并将处理结果返回给server。application中可以包括多个栈式的中间件(middlewares),这些中间件需要同时实现server与application,因此可以在WSGI服务器与WSGI应用之间起调节作用:对服务器来说,中间件扮演应用程序,对应用程序来说,中间件扮演服务器。

WSGI协议其实是定义了一种server与application解耦的规范,即可以有多个实现WSGI server的服务器,也可以有多个实现WSGI application的框架,那么就可以选择任意的server和application组合实现自己的web应用。例如uWSGI和Gunicorn都是实现了WSGI server协议的服务器(他们把HTTP协议转化成WSGI协议,让Python可以直接使用),Django,Flask是实现了WSGI application协议的web框架,同时他们也都有自己实现的简单的WSGI server(一般用于服务器调试,生产环境下建议用其他WSGI server),因此,实际生产环境中,可以选取最合适的server和application组合来实现自己的应用。

uwsgi:与WSGI一样是一种通信协议,是uWSGI服务器的独占协议,用于定义传输信息的类型(type of information),每一个uwsgi packet前4byte为传输信息类型的描述,与WSGI协议是两种不同的东西。
uWSGI:是一个web服务器,实现了WSGI协议、uwsgi协议、http协议等。

3.代理

正向代理(Forward Proxy)

正向代理是一个位于客户端和原始服务器之间的服务器。为了从原始服务器取得内容,客户端向代理发送一个请求并制定目标(原始服务器),然后代理向原始服务器转发请求获得内容,然后将获得的内容返回给客户端。我们平常说的代理通常都是指的正向代理。

可以举个形象的例子来说明:有一天,A君看到C君有巧克力(资源),然后A君就想吃C君的巧克力。可是怎么办,A君和C君不熟吖,不能直接向C君要巧克力吃(访问受限)。这时A君就很苦恼,要怎样做才能吃到C君的巧克力呢?于是A君想啊想啊终于想到了一个办法,就是找和C君关系好的B君(代理),找他去和C君要巧克力,然后再从B君那里拿到巧克力吃。这样,A君就吃到C君的巧克力了,即使C君可能永远不会知道A君吃了TA的巧克力。

正向代理主要有以下应用:

  • 访问原来无法访问的资源。
  • 用作缓存,加快访问速度。
  • 对客户端访问授权,上网进行认证。
  • 代理可以记录用户访问记录(上网行为管理),对外隐藏用户信息。

反向代理(Reverse Proxy)

反向代理则是以代理服务器来接受Internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给Internet上请求的客户端。这个时候的代理服务器对外表现就是一个反向代理服务器。在用户看来,他只是访问了代理服务器而已,实际访问的服务器他并不知道,也无需关心。

同样举个例子来说明:有一天,A君想吃巧克力了,就打电话给B君,B君也没有巧克力,可是却不告诉A君,而是悄悄去向C君要了巧克力,然后给A君送了过去。A君只会以为巧克力是B君的,永远不知道C君的存在。实际上,A君只要知道B君能给到TA巧克力就足够了,至于巧克力是怎么来的,其实一点都不重要。

反向代理主要有以下应用:

  • 保护内网安全。
  • 负载均衡。
  • 缓存,减少服务器压力。

正向代理和反向代理的区别 

正向代理和方向代理的区别,主要在代理对象、服务器架设位置、用途和安全性几个方面。

1.代理对象不同

  • 正向代理的代理对象是客户端,服务端不知道实际发起请求的客户端。还是上面的举例,C君(服务端)不会知道A君(客户端)通过B君(代理)吃到了TA的巧克力,只会知道B君拿了TA的巧克力。简单理解就是,B君(代理)是站在A君(客户端)这边的。
  • 反向代理的代理对象是服务端,客户端不知道实际提供服务的服务端。同样上面的举例,A君(客户端)不会知道巧克力是B君(代理)从C君(服务端)那里拿来给TA的,只会知道是B君给TA的。简单理解就是,B君(代理)是站在C君(服务端)这边的。

2.服务器架设位置不同

  • 正向代理的服务器是架设在客户机和目标主机之间的。
  • 反向代理的服务器是架设在服务器端的。
  • 从代理对象的不同上可以很好理解为什么服务器架设位置不同。

3.用途不同

  • 正向代理的主要用途,是为在防火墙内的局域网客户端提供访问Internet的途径。
  • 反向代理的主要用途,是将防火墙后面的服务器提供给Internet访问。

4.安全性不同

  • 正向代理允许客户端通过代理服务器访问任意网站,并且可以隐藏客户端自身,因此必须采取安全措施以确保仅为已授权的客户端提供服务。
  • 反向代理对外都是透明的,访问者并不知道自己访问的是哪一个代理。

4.为什么还要加nginx?

  • 静态文件支持,经过配置之后,nginx可以直接处理静态文件请求而不用经过应用服务器,避免占用宝贵的运算资源;还能缓存静态资源,使访问静态资源的速度提高。
  •  抗并发压力。可以吸收一些瞬时的高并发请求,让nginx先保持住连接(缓存http请求),然后后端慢慢消化。如果让Gunicorn直接提供服务,浏览器发起一个请求,鉴于浏览器和网络情况都是未知的,http请求的发起过程可能比较慢,而Gunicorn只能等待请求发起完成后,才去真正处理请求,处理完成后,等客户端完全接收请求后,才继续下一个。
  • HTTP 请求缓存头处理得也比 gunicorn和uWSGI 完善。
  • 多台服务器时,可以提供负载均衡和反向代理。

大意如图:

flask项目线上环境部署_第1张图片
值得一提的是:如果你选择的架构是:Nginx + uWSGI或者gunicorn+ web应用,uWSGI或者gunicorn相当于一个中间件;如果选择的架构是uWSGI或者gunicorn + web应用,uWSGI或者gunicorn则为一个web服务器,同一个东西的作用是不能一概而论的,要根据实际来看我们用到它的什么功能,实事求是,一切从实际出发!(升华主题)所以不要问我哪些是web服务器,哪些是应用服务器。

二、部署

就不从创建环境等基础操作开始说了,我现在的步骤基于已经存在一个线上的环境开始

1.配置gunicorn

1.安装gunicorn

pip install gunicorn

2.将gunicorn 加入到代码中,

if __name__ == '__main__':
    from werkzeug.middleware.proxy_fix import ProxyFix
    app.wsgi_app = ProxyFix(app.wsgi_app)
    app.run()

3.运行

在  入口文件.py   路径下,一定要记住是当前路径下!!

gunicorn app:app  #gunicorn 入口文件名:app 

提示说到:监听127.0.0.1:8000,所以我们去试一试

curl http://127.0.0.1:8000

为处理高并发则要开多个进程  或者 你有修改监听端口的需求:

gunicorn -w 4 -b 127.0.0.1:5000 app:app

#  -w 4表示4个进程 -b 127.0.0.1:5000表示监听该端口 
#  app:app 前者代表启动程序文件名, 后者为实例化对象命名即 app = Flask(__name__)

flask项目线上环境部署_第2张图片

通过执行如下命令,可以获取Gunicorn进程树:

pstree -ap|grep gunicorn

本机测试成功了,那接下来我们就进行外网访问的配置

其实很简单,就是把上边命令里的127.0.0.1改成内网的ip ,然后用外网ip加相应的端口就访问到了。

如果你没有成功,那么请检查一下安全组设置,防火墙设置。

我还遇到一个坑:就是用了云服务器那边推荐的模板安全组,大致是把最常用的22,80,443等端口外网准入,内网放通等等,然后我想既然443和80都已经开了,于是就用这两个端口来绑定我的后台,结果一直不成功。(虽然这些端口没有被占用)

排除了各种失败的可能,我猜难道是这些端口太特殊,腾讯那边做了什么处理吗?也不知道对不对,反正就重设了安全组,加了一个5000,然后,用5000端口我的程序就起来了hhh,用浏览器也能访问到了。

到现在我也不知道是服务器的问题还是我程序的问题,如果哪位大佬知道的话,还请不吝赐教。

至此,如上所示,不加上nginx也可以运行

加上nginx的话,gunicorn的配置要再改一下,讲到下边就懂了

2. 配置nginx

1.装nginx

sudo apt-get install nginx

过程会让选一个Y同意占用内存

2.如果出现无法定位nginx包,进行如下操作

sudo apt-get update

3.更新完成之后,安装nginx

sudo apt-get install nginx

4.Ubuntu安装之后的文件结构大致为:

    1)所有的配置文件都在/etc/nginx下,并且每个虚拟主机已经安排在了/etc/nginx/sites-available下

    2)程序文件在/usr/sbin/nginx

    3)日志放在了/var/log/nginx中

    4)并已经在/etc/init.d/下创建了启动脚本nginx

    5)默认的虚拟主机的目录设置在了/var/www/nginx-default (有的版本默认的虚拟主机的目录设置在了/var/www, 请参考/etc/nginx/sites-available里的配置)

5.配置文件
编辑文件:/etc/nginx/sites-available/default(建议先备份,万一崩了)

server {
    listen 8088;#绑定的服务器的端口
    server_name 49.235.***.**; # 这是HOST机器的外部域名,用地址也行(外网ip)

    location / {
       #这里是指向 gunicorn host 的服务地址,是Gunicorn与Ningx通信的端口。和Gunicorn的配置相同
        proxy_pass http://127.0.0.1:5000; 
        proxy_set_header   Host    $host;
        proxy_set_header   X-Real-IP   $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
gunicorn -w 4 -b 127.0.0.1:5000 app:app

启动后 开启另一个服务器链接,输入:

sudo service nginx start

这样你便可以在互联网上 用  你的服务器外网ip地址:8088  访问到你的flask项目了。

原理:通过外网ip地址:8088 访问nginx,nginx反向代理到本机的5000端口,这时候,flask监听在5000端口,然后就访问到flask,响应再一步一步传回来

此时安全组只放通8088给nginx就好,其他端口(如5000)不必外露。

下边科普一下nginx相关命令

启动:sudo service nginx start
重启:sudo service nginx restart
停止:sudo service nginx stop
# 完全卸载nginx
$ sudo apt-get remove --purge nginx
$ sudo apt-get autoremove --purge

# 更新nginx,保留配置文件
# 亲测nginx.conf不会被删除和覆盖,但保险起见还是建议先备份
$ sudo apt-get remove nginx
$ sudo apt-get autoremove
$ sudo apt update
$ sudo apt-get install nginx

# 安装软件包
# sudo apt-get install 软件包名称`
# eg: 
$ sudo apt-get install nginx

# 卸载软件包
# sudo apt-get remove 软件包名称
# eg: 
$ sudo apt-get remove nginx

# 卸载软件包且不保留配置文件
# sudo apt-get remove --purge 软件包名称
# eg:
$ sudo apt-get remove --purge nginx

# 卸载自动安装的软件包且不保留配置文件
# sudo apt-get autoremove --purge

# 列出本地软件包列表
# dpkg --get-selections [| grep 筛选关键字]
# eg:(列出本地所有软件包)
$ dpkg --get-selections
# eg:(列出本地与ngnix有关的软件包)
$ dpkg --get-selections | grep nginx

# 查看进程信息
# ps -ef [| grep 筛选关键字]
# eg:(列出所有进程信息)
$ ps -ef
# eg:(列出与nginx有关的进程信息)
$ ps -ef | grep nginx

# 查看端口占用信息
$ sudo netstat -nlp

至此,nginx和gunicorn的配置都ok了,

但是还有一个问题,到目前为止,gunicorn都是直接通过命令行运行,并不能够在后台运行,也是当我们关闭了xShell(或者你使用的是Putty及其他SSH连接的软件),将无法再访问到你的应用。所以我们需要让gunicorn在后台运行,也就是所谓的daemon(守护进程)。

三、守护进程

1. nohup

如果你熟悉Linux命令,你应该知道在Linux中后台运行可以通过nohup命令,例如我们要让gunicorn在后台运行,我们只需要运行nohup命令:

nohup gunicorn -w 2 -b 127.0.0.1:5000 app:app &

运行后你可以通过如下指令来查看到当前gunicorn的运行状态: 

ps -e | grep gunicorn

这样你就可以关闭连接服务器的终端,还能通过你的浏览器访问到你的Flask应用了!

2. supervisor

但是nohup运行的后台程序并不能够可靠的在后台运行,我们最好让我们的后台程序能够监控进程状态,还能在意外结束时自动重启,这就可以使用一个使用Python开发的进程管理程序supervisor。

首先我们通过apt来安装supervisor:

 sudo apt-get install supervisor

安装完成后,我们在/etc/supervisor/conf.d/目录下创建我们控制进程的配置文件,并以.conf结尾,这样将会自动应用到主配置文件当中,创建后添加如下的配置内容:

[program:WilliamFlaskGunicornSupervisor]
command=/home/william/anaconda3/envs/py36/bin/gunicorn -w 4 -b 127.0.0.1:5000 app:app
directory=/home/william/NJUST_Postgraduate_Curriculum_Flask  ; 项目目录
user=william     ; 执行的用户
autostart=true   ; 设置为随 supervisord 启动而启动
autorestart=true ; 设置为随 supervisord 重启而重启
startretires=5   ; supervisord尝试启动一个程序时尝试的次数。默认是3
startsecs=3      ; 自动重启时间间隔(s)
stderr_logfile=/var/log/WilliamFlaskGunicornSupervisor.err.log ; 错误日志文件
stdout_logfile=/var/log/WilliamFlaskGunicornSupervisor.out.log ; 输出日志文件

在上面的配置文件中,

[program:WilliamFlaskGunicornSupervisor]设置了进程名,这与之后操作进程的状态名称有关,为WilliamFlaskGunicornSupervisor;

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

directory=/home/william/NJUST_Postgraduate_Curriculum_Flask  //项目目录

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

其他的supervisor的操作详细见  https://www.cnblogs.com/Dicky-Zhang/p/6171954.html

保存配置文件之后,我们需要通过命令来更新配置文件:

sudo supervisorctl update

然后我们来启动这个WilliamFlaskGunicornSupervisor进程:

sudo supervisorctl start WilliamFlaskGunicornSupervisor

当然你也直接在命令行输入以下命令进入supevisor的客户端,查看到当前的进程状态

sudo supervisorctl

通过stop命令便可以方便的停止该进程:

supervisor> stop WilliamFlaskGunicornSupervisor

四、https配置

因为目前的项目是微信小程序,有https的需求,于是还要配置nginx的https

1.申请证书

从腾讯云,阿里云等都能找到免费的申请渠道,这个我就不多说了,有的是教程。

2.下载证书之后得到

flask项目线上环境部署_第3张图片

Nginx目录下是这样的

3.把Nginx目录下的文件传到服务器,找个目录放好

我是放在了/etc/nginx/cert/目录

4.配置文件

重新配置/etc/nginx/sites-available/default

server {
	listen 443;                 # 绑定的服务器的端口
	server_name 49.235.***.**;  # 这是HOST机器的外部域名,用地址也行(外网ip)
	ssl on;                     # 启用 SSL 功能
	# 证书文件名称
	ssl_certificate /etc/nginx/cert/1_www.k8rh.top_bundle.crt; 
	# 私钥文件名称
	ssl_certificate_key /etc/nginx/cert/2_www.k8rh.top.key; 

	ssl_session_timeout 5m;
	# 请按照以下协议配置
	ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 
	# 请按照以下套件配置,配置加密套件,写法遵循 openssl 标准。
	ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; 
	ssl_prefer_server_ciphers on;
	location / {
        # 这里是指向gunicorn host的服务地址,是Gunicorn与Ningx通信的端口
		proxy_pass http://127.0.0.1:5000; 
		proxy_set_header   Host    $host;
		proxy_set_header   X-Real-IP   $remote_addr;
		proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
	}
}
server {
	listen 80;
	# 填写绑定证书的域名
	server_name 49.235.***.**; 
	# 把http的域名请求转成https
	rewrite ^(.*)$ https://$host$1 permanent; 
}


规范起见,不用8088了,把安全组的8088删了,改用443,然后把对应http的80也做了转安全的处理。重启nginx如下图,万事大吉!!

flask项目线上环境部署_第4张图片

鸣谢 

借鉴自:

做python Web开发你要理解:WSGI & uwsgi - 简书

nginx+uwsgi 和nginx+gunicorn区别、如何部署 - 简书

非常抱歉,全站内容审核中... - 博客园团队 - 博客园

为什么要使用gunicorn和nginx部署项目?_Aifore的博客-CSDN博客_为什么使用gunicorn

你可能感兴趣的:(Web,云服务器,flask,python)