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

1、項目簡介html

  在本文中,將一步一步搭建一個簡單的Flask + Virtualenv + uWSGI + Nginx 架構的Web服務,能夠做爲新手的學習也可做爲記錄備忘。node

  若是你安裝好了環境並有必定基礎能夠直接從第五節開始部署。python

  項目中只是演示了瀏覽器訪問地址,得到文本返回的過程,本人儘可能把配置解釋的清晰。基於搭建好的架構,後續能夠將業務層(Python)進行擴展,本文不作研究 ,好比:nginx

  一、擴展業務代碼:實現json、靜態資源等等的請求響應。git

  二、基於業務的數據庫查詢和部署。web

  三、服務器端的部署完備(優化):域名、緩存、負載均衡、安全、備份、防火牆、異步IO等。算法

  四、項目代碼管理。shell

 

2、框架介紹數據庫

一、Virtualenvapache

  • virtualenv能夠建立新的Python環境,獨立的虛擬環境之間互不干擾,在有些場景下很是有用,例如:

  (1)同時擁有兩個python項目,一個是python2.7的,另外一個是python3的,能夠建立兩個虛擬環境。

  (2)同時擁有兩個python項目,都依賴一個module(模塊)的不一樣版本,能夠建立兩個不一樣的虛擬環境,分別安裝這個module的不一樣版本。

      (3)同時擁有兩個python項目,各自依賴不一樣的module,能夠在兩個不一樣的虛擬環境裏安裝模塊並開發項目。

  • virtualenvwrapper工具:在virtualenv的基礎上提供了一些更方便的命令,本文只介紹經過此工具管理虛擬環境。

 

二、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應用

 

三、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爲傳輸信息類型的描述。

 

四、Nginx

  Nginx ("engine x") 是一個高性能的HTTP和反向代理服務器,也是一個IMAP/POP3/SMTP服務器 。能夠做爲一個HTTP服務器進行網站的發佈處理,另外nginx能夠做爲反向代理進行負載均衡的實現。因它的穩定性、豐富的功能集、示例配置文件和低系統資源的消耗而聞名。

 

 

3、訪問過程

一、描述一:web客戶端->web服務器->業務代碼的訪問過程 (經過協議通訊)

 

 

二、描述二:不一樣用戶場景->服務器->不一樣應用的訪問過程(簡單架構,不包括複雜的部署,緩存等)

  (1) 部署多個APP,採用單個Nginx,多個uwsgi+Flask,每一個uWSGI監聽不一樣端口。(標準)

 

  (2) 部署多個APP,採用單個Nginx,單個uWSGI,多個Flask路由,Nginx和uwsg經過一個端口通訊。(很差)

  注意:這種模式不是標準方式,「轉發」任務應該是由Nginx實現,經過多個端口和uWSGI通訊,每一個端口對應一個應用,如同描述一。這裏靠路由區分,是很差的。

 

 

 

4、環境準備

 一、基本環境

 (1)阿里ECS服務器 CentOS7.4 ,如需用戶密鑰部署能夠參考https://www.cnblogs.com/cleven/p/10899171.html

 (2)Python環境:Python3.7,pip ,安裝過程省略。

 

 二、虛擬環境:

 (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 命令就能夠了

 

 三、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

 

 

 

5、部署步驟

 一、建立uWSGI項目目錄 

 在/home/project/mysite目錄下建立以下結構

 

 二、編寫run.py 啓動腳本

from flask import Flask
app = Flask(__name__)

@app.route("/app/uwsgi/")
def hello_flask():
    return "Hello uWSGI!"

 

 三、配置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            # 關閉

   

  四、配置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;#設置協商加密算法時,優先使用服務端的加密套件,而不是客戶端瀏覽器
    #
    ####################################################




    ####################    緩存性能優化 ###################
    #
    #  一、open_file_cache :配置能夠存儲的緩存
    #  max設置緩存中的最大元素數; 在緩存溢出時,刪除最近最少使用(LRU)的元素;
    #  inactive是指通過多長時間文件沒被請求後刪除緩存。
    #  inactive設置20s,等到至少20s不訪問這個文件,相應緩存的這個文件的更改信息纔會被刪除。
    #  例:
    #  open_file_cache max=1000 inactive=20s;
    #
    #
    #  二、open_file_cache_valid:多長時間檢查一次緩存的有效信息。
    # 設置爲30s,也就是說即便一直訪問這個文件,30s後會檢查此文件的更改信息是否變化,發現變化就更新
    #  例:
    #  open_file_cache_valid 30s;
    #
    #
    # 三、open_file_cache_min_uses :
    # 在上面open_file_cache 的 inactive時間內文件的最少使用次數。若是超過這個數字,文件更改信息一直是在緩存中打開的。
    # 例:
    #  open_file_cache_min_uses 2;
    #
    # 四、文件錯誤是否也一樣緩存
    #  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負載均衡 (本文中沒有使用)################
    #    負載均衡算法:
    #    一、熱備
    #    二、輪詢
    #    三、加權輪詢
    #    四、ip_hash(相同的客戶端ip請求相同的服務器)
    #
    #    使用服務器列表:
    #    一、定義服務器列表 mysvr
    #    二、server的location模塊中將請求轉向mysvr 定義的服務器列表
    #
    #    server {                      #服務器訪問信息的配置
    #        .....
    #            location  ~*^.+$ {             #訪問路由的配置
    #        proxy_pass  http://mysvr;      #請求轉向mysvr 定義的服務器列表
    #                }
    #
    #
    #    寫法舉例:
    #    一、熱備
    #     upstream mysvr { //服務器列表
    #          server 127.0.0.1:7878;
    #          server 192.168.10.121:3333 backup;  #熱備
    #       }
    #
    #    二、輪詢
    #    upstream mysvr {
    #          server 127.0.0.1:7878;
    #          server 192.168.10.121:3333;
    #        }
    #
    #    三、加權(參數)
    #    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;
    #        }
    #
    #    四、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

 

  五、測試服務

 (1)方法一:

  瀏覽器輸入 39.xxx.xxx.xxx:81/app/uwsgi/ ,若是頁面顯示  「Hello uWSGI!」 ,大功告成!

   (2)方法二:

  curl http://39.xxx.xxx.xxx:81/app/uwsgi/ ,終端輸出 「Hello uWSGI!」,OK。

  

 

6、收尾

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

  在調試過程當中若是出現問題,能夠查看各個日誌,根據 上文: 3、訪問過程 進行逐步排查解決。

  最後,後端領域還有不少東西須要學習,若有錯誤之處還望你們多多指教,本文多以作技術交流和配置備忘之用。

相關文章
相關標籤/搜索