CentOS下實現Flask + Virtualenv + uWSGI + Nginx部署


一、項目簡介

  在本文中,將一步一步搭建一個簡單的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=8888)

   <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=2                        # worker進程個數

threads=2                         # 每個進程的線程數

procname-prefix-spaced=mysite          # uwsgi的進程名稱前綴 ,使用 ps -ef | grep mysite查看

#############————————  注釋掉的一些配置 ————————##############
#chmod-socket=666                    # socket文件的訪問權限(socket字段配置的是文件的情況)

#logfile-chmod=644                  #log權限

#uid=zhangqi                         # 啟動uwsgi的用戶名

#gid=zhangqi                        # 啟動uwsgi的用戶組

#py-autoreload=1                    # py文件修改,自動加載

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

#harakiri=30                       # 設置自中斷時間

#post-buffering=4096                # 設置緩沖

#touch-reload=%(chdir)               # 動態監控文件變化
###########################################################
 
         


############————————  設置uWSGI的socket連接  ————————############
#
# 方式一: socket文件,配置nginx時候使用。socket文件需要使用socket函數編寫。本文中沒有使用此方式
#socket=%(chdir)/uwsgi/uwsgi.sock
#
# 方式二:綁定地址+端口
socket=:8001
#
# 方式三:監聽http端口,測試時候使用。如果不使用Nginx,瀏覽器是http協議,無法使用socket直接通信
#http=0.0.0.0:8001 
#
################################################################
    

############————————  設置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。

  

 

六、收尾

  整個項目下來並不是很復雜,主要是熟悉配置流程,並且根據搭好的基礎框架,升級業務功能。

  在調試過程中如果出現問題,可以查看各個日志,根據 上文: 三、訪問過程 進行逐步排查解決。

  最后,后端領域還有很多東西需要學習,如有錯誤之處還望大家多多指教,本文多以做技術交流和配置備忘之用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM