一、项目简介

  在本文中,将一步一步搭建一个简单的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. JS数组添加元素的三种方式

    1.push() 结尾添加 数组.push(元素) 参数 描述 newelement1 必需.要添加到数组的第一个元素. newelement2 可选.要添加到数组的第二个元素. newelement ...

  2. 数据库SQL实战练习

    http://blog.csdn.net/iamyvette/article/details/77151925

  3. [luoguP1033] 自由落体(模拟?)

    传送门 这不能算是数论题... 卡精度这事noip也做的出来.. 代码 #include <cmath> #include <cstdio> int n, ans; doubl ...

  4. 安装K/3 Cloud过程中发现的两个新问题。

    卸载掉K/3 Cloud然后重装时出现下面的错误提示: 可能原因: 1.安装目录下的Setup.exe会检查操作系统版本.有些操作系统可能是被串改过注册信息,所以取不到版本信息(有些是因为盗版的原因) ...

  5. 【ZJOI2017 Round1练习】D8T3 stone(Nim游戏)

    题意: 思路:与其类似的题是HDU5996 HDU5996为判定性问题,稍加改动就可以用来统计方案数 ..]of longint; v,cas,i,j,ans,tmp,n,s,k:longint; b ...

  6. Memory Ordering in Modern Microprocessors

    Linux has supported a large number of SMP systems based on a variety of CPUs since the 2.0 kernel. L ...

  7. Linux下keepalived下载安装与配置

    一.下载(原文链接:http://www.studyshare.cn/blog-front//software/details/1158/0 ) 网盘下载:https://pan.baidu.com/ ...

  8. 洛谷 P1318 积水面积

    P1318 积水面积 题目描述 一组正整数,分别表示由正方体迭起的柱子的高度.若某高度值为x,表示由x个正立方的方块迭起(如下图,0<=x<=5000).找出所有可能积水的地方(图中蓝色部 ...

  9. Linux MariaDB 遗忘密码后重置密码

    Linux MariaDB 遗忘密码后重置密码 MariaDB 是 MySQL 的一个分支数据库.处理的办法和 MySQL 相同. 修改 MySQL 配置文件 在 [mysqld] 追加配置项: [r ...

  10. Vue.js父子通信之所有方法和数据共享

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...