一、项目简介

  在本文中,将一步一步搭建一个简单的Flask + Virtualenv + uWSGI + Nginx 架构的Web服务,可以作为新手的学习也可作为记录备忘。

  如果你安装好了环境并有一定基础可以直接从第五节开始部署。

  项目中只是演示了浏览器访问地址,获得文本返回的过程,本人尽量把配置解释的清晰。基于搭建好的架构,后续可以将业务层(Python)进行扩展,本文不做研究 ,比如:

  1、扩展业务代码:实现json、静态资源等等的请求响应。

  2、基于业务的数据库查询和部署。

  3、服务器端的部署完备(优化):域名、缓存、负载均衡、安全、备份、防火墙、异步IO等。

  4、项目代码管理。

二、框架介绍

1、Virtualenv

  • virtualenv可以创建新的Python环境,独立的虚拟环境之间互不干扰,在有些场景下非常有用,例如:

  (1)同时拥有两个python项目,一个是python2.7的,另一个是python3的,可以创建两个虚拟环境。

  (2)同时拥有两个python项目,都依赖一个module(模块)的不同版本,可以创建两个不同的虚拟环境,分别安装这个module的不同版本。

(3)同时拥有两个python项目,各自依赖不同的module,可以在两个不同的虚拟环境里安装模块并开发项目。

  • virtualenvwrapper工具:在virtualenv的基础上提供了一些更方便的命令,本文只介绍通过此工具管理虚拟环境。

2、Flask

  Flask是一个Python的轻量级web框架,是基于Python开发并且依赖jinja2模板(模板语言)和 Werkzeug WSGI(WSGI工具集)服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后触发Flask框架,开发人员基于Flask框架提供的功能对请求进行相应的处理,并返回给用户,如果要返回给用户复杂的内容时,需要借助jinja2模板来实现对模板的处理,即:将模板和数据进行渲染,将渲染后的字符串返回给用户浏览器。

  Werkzeug的补充:Werkzeug是WSGI工具包,他可以作为一个Web框架的底层库。它不是一个web服务器,也不是一个web框架,而是一个工具包,官方的介绍说是一个 WSGI 工具包,它可以作为一个 Web 框架的底层库,因为它封装好了很多 Web 框架的东西( python web WSGI 开发相关的功能),例如 :

  • 路由处理:如何根据请求 URL 找到对应的视图函数
  • request 和 response 封装: 提供更好的方式处理request和生成response对象
  • 自带的 WSGI server: 测试环境运行WSGI应用

3、uWSGI

(1)WSGI

  全称 Web Server Gateway Interface ,是为 Python 语言定义的 Web 服务器和 Web 应用程序或框架之间的一种简单而通用的接口(协议)。WSGI是Web 服务器(uWSGI)与 Web 应用程序或应用框架(Flask,Django)之间的一种低级别的接口。可以参考阅读 PEP3333

  WSGI 分为两个部分

  • Server/Gateway: 即是HTTP Server, 负责从客户端(Nginx、apache、IIS)接收请求,将 request 转发给 application, 并将 application(可能是个Flask应用) 返回的response 返回给客户端。
  • Application/Framework: 一个python web 应用或 web 框架接收由 server 转发的request,处理请求,并将处理结果返回给 server。

(2)uWSGI

  uWSGI是一个Web服务器,C语言编写,它实现了WSGI协议、uwsgi、http等协议。它要做的就是把HTTP协议转化成语言支持的网络协议。比如把HTTP协议转化成WSGI协议,让Python可以直接使用。

(3)uwsgi

  与WSGI一样,是uWSGI服务器的独占通信协议,用于定义传输信息的类型(type of information)。每一个uwsgi packet前4byte为传输信息类型的描述。

4、Nginx

  Nginx ("engine x") 是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器 。可以作为一个HTTP服务器进行网站的发布处理,另外nginx可以作为反向代理进行负载均衡的实现。因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。

三、访问过程

1、描述一:web客户端->web服务器->业务代码的访问过程 (通过协议通信)

2、描述二:不同用户场景->服务器->不同应用的访问过程(简单架构,不包括复杂的部署,缓存等)

(1) 部署多个APP,采用单个Nginx,多个uwsgi+Flask,每个uWSGI监听不同端口。(标准)

(2) 部署多个APP,采用单个Nginx,单个uWSGI,多个Flask路由,Nginx和uwsg通过一个端口通信。(不好)

  注意:这种模式不是标准方式,“转发”任务应该是由Nginx实现,通过多个端口和uWSGI通信,每个端口对应一个应用,如同描述一。这里靠路由区分,是不好的。

四、环境准备

 1、基本环境

 (1)阿里ECS服务器 CentOS7.4 ,如需用户密钥部署可以参考https://www.cnblogs.com/cleven/p/10899171.html

 (2)Python环境:Python3.7,pip ,安装过程省略。

 2、虚拟环境:

 (1)安装  

sudo pip3 install virtualenv
sudo pip3 install virtualenvwrapper

 (2)创建虚拟环境

mkvirtualenv -p python3 env1

  -p 后面的参数指定了python3(也有可能要换成python3.2/python3.4,具体要看你系统里面/use/bin/里面的文件是什么名字),如果去掉这个参数,就会使用系统默认的python。最后一个参数env1是创建的这个环境的名字。

 (3)管理虚拟环境

deactivate            # 退出当前虚拟环境
workon env1 # 使用虚拟环境env1
rmvirtualenv env1 # 删除某个虚拟环境
lsvirtualenv # 列出所有虚拟环境
cdvirtualenv      # 进入虚拟环境存储目录

 (4)在服务器上同步本地的虚拟环境包

  在开发机器上执行下面这个命令,来列出所有的包并保存到packages.txt,其中-l参数是只列出当前虚拟环境的包:

pip3 freeze -l > packages.txt

  然后在部署到生产环境的时候,把packages.txt也复制到每个机器,并在每个机器上执行:

pip3 install -r packages.txt

 (5)注意点

  安装完虚拟环境,重启shell后,workon等命令就无法使用了,这是因为没有添加环境变量:

export WORKON_HOME=/home/.virtualenv  #虚拟环境所放置的目录,可以自行指定
source /usr/local/bin/virtualenvwrapper.sh

  配置完上面,使用 source ~/.bashrc 命令就可以了

 3、web环境

 (1)Flask ,虚拟环境下安装

pip3 install  flask

   检验一下Flask和虚拟环境的安装情况:

   <1>  创建项目目录

mkdir webtest 

     <2>  进入虚拟环境

workon env1

   <3> 进入webtest,创建hello.py

from flask import Flask
app = Flask(__name__) @app.route("/app/flask/")
def hello_flask():
return "Hello Flask!" if __name__ == "__main__": #Flask 开启监听所有地址的8888端口
app.run(host='0.0.0.0', port=)

   <4> 启动服务,并测试。 Flask是有内置web server的(一般只是测试时使用,不安全,可控性差,线上还是使用uWSGI部署)

python3 hello.py

    在浏览器访问 [服务器的ip地址]:8888/app/flask/ ,浏览器中如果显示“Hello Flask”,则Flask配置正常。

 (2)uWSGI,虚拟环境下安装

pip3 install uwsgi

 (3)Nginx:不用在虚拟环境下安装

sudo yum install nginx

五、部署步骤

 1、创建uWSGI项目目录 

在/home/project/mysite目录下创建如下结构

 

 2、编写run.py 启动脚本

from flask import Flask
app = Flask(__name__) @app.route("/app/uwsgi/")
def hello_flask():
return "Hello uWSGI!"

 3、配置uWSGI:

 (1)进入项目目录,编辑uwsgi.ini

vim uwsgi.ini

 (2)下面给出配置文件的详细说明(有些字段注释掉了,毕竟我们是简单的搭建uWSGI服务)

[uwsgi]

chdir=/home/project/mysite/               # 项目目录

home=/home/zhangqi/.virtualenvs/env1      # 虚拟环境的路径

wsgi-file=%(chdir)/run.py                 # 项目的启动脚本文件路径
#module=run                               # 项目的启动脚本名字,不能是路径,和wsgi-file功能类似
callable=app       # 程序内启用的application变量名,一般而言都是app=Flask(__name__),所以这里是app

master=true                        # 启用主进程

processes=                        # worker进程个数

threads=                         # 每个进程的线程数

procname-prefix-spaced=mysite          # uwsgi的进程名称前缀 ,使用 ps -ef | grep mysite查看
#############————————  注释掉的一些配置 ————————##############
#chmod-socket=                    # socket文件的访问权限(socket字段配置的是文件的情况)

#logfile-chmod=                  #log权限

#uid=zhangqi                         # 启动uwsgi的用户名

#gid=zhangqi                        # 启动uwsgi的用户组

#py-autoreload=                    # py文件修改,自动加载

#vacuum=true                        # 退出uwsgi是否清理中间文件,包含pid、sock和status文件

#harakiri=                       # 设置自中断时间

#post-buffering=                # 设置缓冲

#touch-reload=%(chdir)               # 动态监控文件变化
###########################################################


############————————  设置uWSGI的socket连接  ————————############
#
# 方式一: socket文件,配置nginx时候使用。socket文件需要使用socket函数编写。本文中没有使用此方式
#socket=%(chdir)/uwsgi/uwsgi.sock
#
# 方式二:绑定地址+端口
socket=:
#
# 方式三:监听http端口,测试时候使用。如果不使用Nginx,浏览器是http协议,无法使用socket直接通信
#http=0.0.0.0:
#
################################################################ ############———————— 设置uWSGI的管理文件 ————————############
#
# status文件,可以查看uwsgi的运行状态
# 命令:uwsgi --connect-and-read uwsgi/uwsgi.status
stats=%(chdir)/uwsgi/uwsgi.status
#
# pid文件,通过该文件可以控制uwsgi的重启和停止
# 命令:uwsgi --reload uwsgi/uwsgi.pid
# 命令:uwsgi --stop uwsgi/uwsgi.pid
pidfile=%(chdir)/uwsgi/uwsgi.pid
#
# 日志文件,通过该文件查看uwsgi的日志
daemonize=%(chdir)/uwsgi/uwsgi.log
#
#############################################################

  

 (3)启动uWSGI,注意是虚拟环境。  

uwsgi --ini uwsgi.ini

 (4)调试uWSGI

  • 查看uWSGI进程
ps -ef | grep mysite
#或者
netstat -antp |grep 8001

  显示如下,uWSGI启动正常  

  • 查看uWSGI状态。

  会以json格式显示出完整内容,包括每个总的状态,每个work是状态,响应时间等,非常全面。

uwsgi --connect-and-read uwsgi/uwsgi.status

  也有一些开源的监控工具可以使用:uwsgitop

# pip3 install uwsgitop
# uwsgitop uwsgi/uwsgi.status
  • 控制uWSGI服务器
uwsgi --ini uwsgi.ini             # 启动
uwsgi --reload uwsgi.pid # 重启
uwsgi --stop uwsgi.pid # 关闭

  

4、配置Nginx:

(1)编辑配置文件 nginx.conf(主):

vim /etc/nginx/nginx.conf 

  内容如下

########### 每个指令必须有分号结束 #################

user nginx;              #配置用户或者组,默认为nobody nobody
worker_processes auto;        #允许生成的进程数,默认为1
pid /run/nginx.pid;          #指定nginx进程运行文件存放地址
include /usr/share/nginx/modules/*.conf; #加载动态模块 #制定日志路径和级别。这个设置可以放入全局块,http块,server块
#级别依次为:debug|info|notice|warn|error|crit|alert|emerg
error_log /var/log/nginx/error.log; events {
worker_connections 1024; #最大连接数,默认为512
#use epoll; #事件驱动模型,select|poll|kqueue|epoll|resig|/dev/poll|eventport
#accept_mutex on; #设置网路连接序列化,防止惊群现象发生,默认为on
#multi_accept on; #设置一个进程是否同时接受多个网络连接,默认为off
} http { default_type application/octet-stream; #默认文件类型,默认为text/plain
keepalive_timeout 65;#连接超时时间,默认为75s,可以在http,server,location块配置
include /etc/nginx/conf.d/*.conf; #虚拟主机配置,引入不同server的配置(uWSGI)
include /etc/nginx/mime.types; #引入文件类型 #sendfile_max_chunk 100k; #每个进程每次调用传输数量最大值,默认为0(无上限) ################## 日志 #########################
#自定义日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'; #接入日志设置
access_log /var/log/nginx/access.log main;
#access_log off; #取消服务日志
#
#################################################### #################### SSL证书加密 ###################
#
#ssl_protocols TLSv1 TLSv1.1 TLSv1.2 SSLv3;#启动特定的加密协议
#ssl_prefer_server_ciphers on;#设置协商加密算法时,优先使用服务端的加密套件,而不是客户端浏览器
#
#################################################### #################### 缓存性能优化 ###################
#
# 1、open_file_cache :配置可以存储的缓存
# max设置缓存中的最大元素数; 在缓存溢出时,删除最近最少使用(LRU)的元素;
# inactive是指经过多长时间文件没被请求后删除缓存。
# inactive设置20s,等到至少20s不访问这个文件,相应缓存的这个文件的更改信息才会被删除。
# 例:
# open_file_cache max=1000 inactive=20s;
#
#
# 2、open_file_cache_valid:多长时间检查一次缓存的有效信息。
# 设置为30s,也就是说即使一直访问这个文件,30s后会检查此文件的更改信息是否变化,发现变化就更新
# 例:
# open_file_cache_valid 30s;
#
#
# 3、open_file_cache_min_uses :
# 在上面open_file_cache 的 inactive时间内文件的最少使用次数。如果超过这个数字,文件更改信息一直是在缓存中打开的。
# 例:
# open_file_cache_min_uses 2;
#
# 4、文件错误是否也同样缓存
# open_file_cache_errors on;
#
#################################################### ################# 数据传输优化 ###################
#
# 允许sendfile( )方式传输文件,提高传输性能,默认为off
# 可以在http块,server块,location块配置
sendfile on;
#
# 设置调用tcp_cork方法,数据包不会马上传送出去,等到数据包最大时,一次性的传输出去,这样有助于解决网络堵塞。默认on,
# tcp_nopush on;
#
# 打开tcp_nodelay ,禁用Nagle的缓冲算法,并在数据可用时立即发送,优化传输效率,默认on
# tcp_nodelay on;
#
#
#################################################### ################### 散列表大小 ########################
# Nginx使用散列表来存储MIME type与文件扩展名。
# types_hash_bucket_size 设置了每个散列表占用的内存大小,其影响散列表的冲突率。
# 值越大,就会消耗更多的内存,但散列key的冲突率会降低,检索速度就更快。
# 值越小,消耗的内存就越小,但散列key的冲突率可能上升。
# 默认1024。
types_hash_max_size 2048;
#################################################### ################# Nginx负载均衡 (本文中没有使用)################
# 负载均衡算法:
# 1、热备
# 2、轮询
# 3、加权轮询
# 4、ip_hash(相同的客户端ip请求相同的服务器)
#
# 使用服务器列表:
# 1、定义服务器列表 mysvr
# 2、server的location模块中将请求转向mysvr 定义的服务器列表
#
# server { #服务器访问信息的配置
# .....
# location ~*^.+$ { #访问路由的配置
# proxy_pass http://mysvr; #请求转向mysvr 定义的服务器列表
# }
#
#
# 写法举例:
# 1、热备
# upstream mysvr { //服务器列表
# server 127.0.0.1:7878;
# server 192.168.10.121:3333 backup; #热备
# }
#
# 2、轮询
# upstream mysvr {
# server 127.0.0.1:7878;
# server 192.168.10.121:3333;
# }
#
# 3、加权(参数)
# upstream mysvr {
# server 127.0.0.1:7878 weight=2 max_fails=2 fail_timeout=2;
# server 192.168.10.121:3333 weight=1 max_fails=2 fail_timeout=1;
# }
#
# 4、ip_hash
# upstream mysvr {
# server 127.0.0.1:7878;
# server 192.168.10.121:3333;
# ip_hash;
# }
#
# nginx负载调优总结 :https://www.jianshu.com/p/4fa08f2a04ed
#
################################################# }

(2)Flask站点对应的server配置:

  上面的主配置中,有此句“include /etc/nginx/conf.d/*.conf;”  ,我们将Flask对应的server模块,单独写在一个文件里(当然也可以直接写在上面的主配置中),一个server中又通过多个location指向不同应用。

  理论上,一个Nginx对应多个站点,一个站点对应一个server,一个server又可以对应多个location(应用)。

  • 进入conf.d文件夹,并创建flask.conf
$ sodu touch /etc/nginx/conf.d/flask.conf
  • 内容如下
server {
listen 81;           #监听外部端口(浏览器)
server_name 39.xxx.xxx.xxx;    #服务器地址
charset utf-8;
client_max_body_size 5M;
root /usr/share/nginx/html; #默认根目录
include /etc/nginx/default.d/*.conf;

  #配置路由
location / { #对根目录的访问都匹配,此处没有做正则匹配讲解
include uwsgi_params; #引入uwsgi
uwsgi_pass localhost:8001; #通过localhost:8001端口和uWSGI通信(这是绑定的IP和端口,对应上文中uWSGI.ini里面的配置)
# uwsgi_pass unix:/home/project/mysite/uwsgi/uwsgi.sock; #本文没有使用socket文件进行演示。
}
location /static { #静态文件,直接访问路径,不用进入uWSGI进行处理
alias /home/project/mysite/static/;
} error_page 404 /404.html;
location = /40x.html {
    #可以更改错误页面路径
} error_page 500 502 503 504 /50x.html;
location = /50x.html {
#可以更改错误页面路径
}
}

(2)控制Nginx:

  • 启动
$nginx
或者
$systemctl start nginx
  • 重启 
nginx -s reload   #热启动,配置文件重装载
kill -HUP 主进程号或进程号文件路径 #平滑重启
systemctl restart nginx
  • 停止
system stop nginx
nginx -s stop #快速关闭
nginx -s quit #正常关闭
或者通过进程控制
ps -ef | grep nginx
kill -QUIT 主进程号 #从容停止
kill -TERM 主进程号 #快速停止
kill -9 主进程号 #强制停止

(3)查看Nginx状态:  

  • ps -ef | grep nginx

  • systemctl status nginx

  5、测试服务

 (1)方法一:

  浏览器输入 39.xxx.xxx.xxx:81/app/uwsgi/ ,如果页面显示  “Hello uWSGI!” ,大功告成!

(2)方法二:

  curl http://39.xxx.xxx.xxx:81/app/uwsgi/ ,终端输出 “Hello uWSGI!”,OK。

  

六、收尾

  整个项目下来并不是很复杂,主要是熟悉配置流程,并且根据搭好的基础框架,升级业务功能。

  在调试过程中如果出现问题,可以查看各个日志,根据 上文:三、访问过程进行逐步排查解决。

  最后,后端领域还有很多东西需要学习,如有错误之处还望大家多多指教,本文多以做技术交流和配置备忘之用。

CentOS下实现Flask + Virtualenv + uWSGI + Nginx部署的更多相关文章

  1. [服务器部署] Flask + virtualenv + uWSGI + Nginx 遇到的问题

    1.配置好了Flask + virtualenv +uWSGI,启动uWSGI并调试,网页显示 Internal Server Error 参考:https://www.cnblogs.com/cle ...

  2. 使用virtualenv, uwsgi, nginx来布署flask

    本文讲述了怎样使用virtualenv, uwsgi, nginx来布署flask的步骤. 升级软件包 运行下面命令,保证你的机器安装了最新的软件包. sudo apt-get update sudo ...

  3. Flask采用Virtualenv+Supervisor+Nginx部署应用

    Flask采用Virtualenv+Supervisor+Nginx部署应用 -- 首先是概念解释 WSGI服务器,负责我们的app与服务器的交互,常用的有Gunicorn Web服务器,是个HTTP ...

  4. Linux 集群概念 , wsgi , Nginx负载均衡实验 , 部署CRM(Django+uwsgi+nginx), 部署学城项目(vue+uwsgi+nginx)

    Linux 集群概念 , wsgi , Nginx负载均衡实验 , 部署CRM(Django+uwsgi+nginx), 部署学城项目(vue+uwsgi+nginx) 一丶集群和Nginx反向代理 ...

  5. centosflask+uWSGI+nginx部署

    centosflask+uWSGI+nginx部署 1.      概念 Flask自带webserver--Werkzeug,可以搭建服务,运行网站.但在开发时,一般会用专业的--uWSGI. 另外 ...

  6. 使用uWSGI+nginx部署Django项目

    最近使用django写了一些项目,不过部署到服务器上碰到一些问题,还有静态文件什么的一堆问题,这里总结一下碰到的问题和解决方案,总体思路是按照官方文档走的. 原文地址:http://uwsgi-doc ...

  7. vue+uwsgi+nginx部署路飞学城

    vue+uwsgi+nginx部署路飞学城   有一天,老男孩的苑日天给我发来了两个神秘代码,听说是和mjj的结晶 超哥将这两个代码,放到了一个网站上,大家可以自行下载 路飞学城django代码 ht ...

  8. linux vue uwsgi nginx 部署路飞学城 安装 vue

    vue+uwsgi+nginx部署路飞学城 有一天,老男孩的苑日天给我发来了两个神秘代码,听说是和mjj的结晶 超哥将这两个代码,放到了一个网站上,大家可以自行下载 路飞学城django代码#这个代码 ...

  9. virtualvenv+django+uWSGI+nginx 部署

    原创博文 转载请注明出处! 1. virtualvenv 2. django 3. uWSGI 4. nginx 5. 踩坑记录 1. virtualvenv virtualvenv install ...

随机推荐

  1. 集训第四周(高效算法设计)G题 (贪心)

    G - 贪心 Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Desc ...

  2. Fiddler基本用法:手机抓包1

    Fiddler基本用法以及如何对手机抓包 一.Fiddler是什么? ·一种Web调试工具. ·可以记录所有客户端和服务器的http和https请求. ·允许监视.设置断点.修改输入输出数据. 官方文 ...

  3. myeclipse通过数据表生成jpa或hibernate实体---https://blog.csdn.net/partner4java/article/details/8560289

    myeclipse通过数据表生成jpa或hibernate实体-----https://blog.csdn.net/partner4java/article/details/8560289

  4. CMM

    CMM CMM的基本概念 CMM(Capability Maturity Model for Software) 它是对于软件组织在定义,实施,度量,控制和改善其软件过程的实践中各个发展阶段的描述.其 ...

  5. 【HDOJ3047】Zjnu Stadium(带权并查集)

    题意:浙江省第十二届大学生运动会在浙江师范大学举行,为此在浙师大建造了一座能容纳近万人的新体育场. 观众席每一行构成一个圆形,每个圆形由300个座位组成,对300个座位按照顺时针编号1到300,且可以 ...

  6. Linux下C编程入门(7)

    Linux下项目同步工具介绍git和github 一.远程仓库工具github 1. 一.本地操作工具git 1.

  7. UVA 116_ Unidirectional TSP

    题意: 给定整数矩阵,从第一列的任何一个位置出发,每次可以向右.右上.右下走一个格,将最后一行和第一行看成是邻接的,最终到达最后一列,路径长度为所经过格中的整数之和,求最小路径,答案不唯一,输出字典序 ...

  8. delphi调用oracle存储过程(ODAC)

    CREATE OR REPLACE PACKAGE p_lee01ISTYPE cur_lee01 IS REF CURSOR;END; CREATE OR REPLACE PROCEDURE pro ...

  9. dubbo服务的group和version

    group 当一个接口有多种实现时,可以用group区分 <!-- dubbo group 使用示例 --> <bean id="demoA" class=&qu ...

  10. 积累——SQLCommand命令

    SQLcommand表示要对SQL数据库运行的一个 T-SQL 语句或存储过程.以便运行大量操作或处理数据库结构. 在对数据库訪问的时候,就经经常使用到这个.看看它是怎么做到的吧! 一.属性 Comm ...