[Flask] 樹莓派上使用 Nginx 和 uWSGI 部署 Flask 應用

[TOC]

Deploy Flask Application with Nginx and uWSGI

考慮到部署的問題,相信您已經完成了自己Flask應用的開發工作,或者跟我一樣,一個demo 應用已經完成。好奇自己的應用如何發布出去。接下來,通過介紹一些常用的工具來完成我們應用的部署。先簡單介紹下我的環境:

  • 一臺內網中的樹莓派
  • 一個花生棒(98RMB買的硬件)

使用花生棒做了內網的端口映射,對外暴露80端口提供http服務,至于為什么這么做,請參考這里。

好了,接下來進入正題。

0x00 uWSGI 和 Nginx 介紹

uWSGI作為Web服務器使用,nginx做反向代理。

uWSGI

uWSGI做Web服務器

《Flask Web開發:基于Python的Web應用開發實戰》有下面兩段描述:

其一:

Flask自帶的開發Web服務器不夠強健、安全和高效,無法在生產環境中使用。

其二:

Flask自帶的開發Web服務器表現很差,因為它不是為生產環境設計的服務器。有兩個可以在生產環境中使用、性能良好且支持Flask程序的服務器,分別是Gunicorn(http://gunicorn.org/) 和 uWSGI(http://uwsgi-docs.readthedocs.org/en/latest/) 。

先介紹一下WSGI(from:維基百科):

Web服務器網關接口(Python Web Server Gateway Interface,縮寫為WSGI)是為Python語言定義的Web服務器和Web應用程序或框架之間的一種簡單而通用的接口。自從WSGI被開發出來以后,許多其它語言中也出現了類似接口。
以前,如何選擇合適的Web應用程序框架成為困擾Python初學者的一個問題,這是因為,一般而言,Web應用框架的選擇將限制可用的Web服務器的選擇,反之亦然。那時的Python應用程序通常是為CGI,FastCGI,mod_python中的一個而設計,甚至是為特定Web服務器的自定義的API接口而設計的。
WSGI[1] (有時發音作'wiz-gee')是作為Web服務器與Web應用程序或應用框架之間的一種低級別的接口,以提升可移植Web應用開發的共同點。WSGI是基于現存的CGI標準而設計的。

因此我們需要為我們的Flask應用配置一個 Web服務器 。《Flask Web開發》中介紹的部署到Heroku選擇的是Gunicorn。Gunicorn 和 uWSGI 的比較網上很多,主要的問題可能就是誰的坑多坑少。經過比對,這里我選擇uWSGI。

uWSGI 不僅僅是一個協議,同時也是一個應用服務器,可以服務于uWSGI、FastCGI和HTTP協議。uWSGI官方文檔可參考這里 。

支持WSGI的Web應用框架很多,比如:

  • Django
  • Flask
  • web.py
  • web2py
  • Werkzeug
  • Tornado
  • and so on

Nginx

nginx做反向代理

Nginx(發音同engine x)是一個網頁服務器,它能反向代理HTTP, HTTPS, SMTP, POP3, IMAP的協議鏈接,以及一個負載均衡器和一個HTTP緩存。

Nginx是一款面向性能設計的HTTP服務器,相較于Apache、lighttpd具有占有內存少,穩定性高等優勢。與舊版本(<=2.2)的Apache不同,nginx不采用每客戶機一線程的設計模型,而是充分使用異步邏輯,削減了上下文調度開銷,所以并發服務能力更強。整體采用模塊化設計,有豐富的模塊庫和第三方模塊庫,配置靈活。 在Linux操作系統下,nginx使用epoll事件模型,得益于此,nginx在Linux操作系統下效率相當高。同時Nginx在OpenBSD或FreeBSD操作系統上采用類似于epoll的高效事件模型kqueue。

Nginx在官方測試的結果中,能夠支持五萬個平行連接,而在實際的運作中,是可以支持二萬至四萬個平行鏈接。

以上來信息自維基百科

反向代理:

使用代理服務器可以將請求轉發給內部的Web服務器,使用這種加速模式顯然可以提升靜態網頁的訪問速度。因此也可以考慮使用這種技術,讓代理服務器將請求 均勻轉發給多臺內部Web服務器之一上,從而達到負載均衡的目的。這種代理方式與普通的代理方式有所不同,標準代理方式是客戶使用代理訪問多個外部Web 服務器,而這種代理方式是多個客戶使用它訪問內部Web服務器,因此也被稱為反向代理模式。

參考:http://www.bing.com/knows/反向代理負載均衡

雖然你可能不知道Nginx是做什么的,但是你應該聽過,再或者你至少聽過Apache,他們都是HTTP服務器。恕我能力有限,目前為止并不能很好的解釋為什么非得用Nginx,能告訴大家的是:Nginx幫我們處理很多靜態資源,同時將動態請求轉發給不同的Web服務器(負載均衡)。此處留坑,等以后補上。

接下來通過最簡單的配置,將我們的Flask應用部署到我們的樹莓派上,達到對部署的流程有個總體把握的目的。如果你需要更多的配置,可以參考各自部分的官方文檔。

0x01 uWSGI

  • 安裝

    先從安裝說起:pip install uwsgi

  • 配置

    在我們項目的根目錄下,創建 uwsgi.ini 文件, 內容如下:

    [uwsgi]
    socket = 127.0.0.1:5000
    processes = 4
    threads = 2
    plugins = python3
    master = true
    venv = venv
    pythonpath = .
    module = manage
    callable = application
    

配置參數說明:

- socket:應用程序所在地址,IP加端口號,當然,也可以有其他的形式
- processes:開啟的進程數量
- threads:每個進程的線程數
- plugins:加載的插件
- module:加載指定的python WSGI模塊
- callable:在收到請求時,uWSGI加載的模塊中哪個變量將被調用,默認是名字為“application”的變量。

順便貼一下我的Flask項目文件:manage.py
``` python 
#!/usr/bin/env python3
# coding:utf-8
from flask.ext.script import Manager
config = 'development'
application = create_app(config)
manager = Manager(application)
...
if __name__ == '__main__':
        manager.run()
```
  • 操作

    • 啟動:uwsgi uwsig.ini。如果啟動成功,會看到類似下面的log:
(venv)pi@raspberrypi:~/raspi $ uwsgi uwsgi.ini
[uWSGI] getting INI configuration from uwsgi.ini
open("./python3_plugin.so"): No such file or directory [core/utils.c line 3684]
!!! UNABLE to load uWSGI plugin: ./python3_plugin.so: cannot open shared object file: No such file or directory !!!
*** Starting uWSGI 2.0.13.1 (32bit) on [Sun Jul  3 22:35:08 2016] ***
compiled with version: 4.9.2 on 27 May 2016 15:15:57
os: Linux-4.1.19-v7+ #858 樹莓派 Tue Mar 15 15:56:00 GMT 2016
nodename: raspberrypi
machine: armv7l
clock source: unix
detected number of CPU cores: 4
current working directory: /home/pi/raspi
detected binary path: /home/pi/raspi/venv/bin/uwsgi
!!! no internal routing support, rebuild with pcre support !!!
your processes number limit is 6831
your memory page size is 4096 bytes
detected max file descriptor number: 65536
lock engine: pthread robust mutexes
thunder lock: disabled (you can enable it with --thunder-lock)
uwsgi socket 0 bound to TCP address 127.0.0.1:5000 fd 3
Python version: 3.4.2 (default, Oct 19 2014, 14:03:53)  [GCC 4.9.1]
Set PythonHome to venv
Python main interpreter initialized at 0xbaf828
python threads support enabled
your server socket listen backlog is limited to 100 connections
your mercy for graceful operations on workers is 60 seconds
mapped 358400 bytes (350 KB) for 8 cores
*** Operational MODE: preforking+threaded ***
added ./ to pythonpath.
WSGI app 0 (mountpoint='') ready in 5 seconds on interpreter 0xbaf828 pid: 3418 (default app)
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI master process (pid: 3418)
spawned uWSGI worker 1 (pid: 3428, cores: 2)
spawned uWSGI worker 2 (pid: 3429, cores: 2)
spawned uWSGI worker 3 (pid: 3431, cores: 2)
spawned uWSGI worker 4 (pid: 3432, cores: 2)
- 停止

    - 如果還在同一個shell中,我們可以直接按 `Ctrl + C` 
    - 如果不在同一個shell中,可以這樣結束掉 `killall -9 uwsgi`

啟動成功之后就可以訪問我們的Web應用了,默認地址是:http://127.0.0.1:5000 (這個地址和端口號是在我們的Flask應用中配配置的,這里不做介紹)。如果出現 `invalid request block size: 21573 (max 4096)...skip`這個錯誤,請將配置中的 `socket` 改為 `http`,具體可以參考[這里](http://stackoverflow.com/questions/15878176/uwsgi-invalid-request-block-size)。

0x02 Nginx

  • 安裝

    sudo apt-get install nginx

  • 操作

    • 啟動

      sudo /etc/init.d/nginx start
      sudo service nginx start

    • 停止

      sudo /etc/init.d/nginx stop
      sudo service nginx stop

    • 重啟

      sudo /etc/init.d/nginx restart
      sudo service nginx restart

    如果沒問題,這個時候我們就可以打開瀏覽器訪問:127.0.0.1,應該會看到一個靜態頁面。

  • 配置

    nginx 的配置文件時位于 /etc/nginx/sites-available 目錄下的 default 文件,我們復制一份做修改,這里同樣給一份最簡單的配置:

server {
    listen 80;

    server_name ttdevs.vicp.net;

    # access_log logs/access.log compression;

    #默認請求
    location / {
            include uwsgi_params;
            uwsgi_pass 127.0.0.1:5000;
    }
}

配置好這些之后重啟我們的nginx服務:sudo service nginx restart。即可訪問我們的web應用了。

0x03 總結

如果中間沒有出錯,你的Flask應用已經部署成功。到此,我們來梳理下這個流程。首先,我們安裝Nginx,他直接處理用戶發送的HTTP請求(HTTP服務器),并將請求按照我們的配置(nginx中的配置)交給uWSGI服務器(Web服務器),最后uWSGI將請求交給我們的Flask應用,由Flask應用進行邏輯處理,處理完之后再將結果返回給用戶。這些,就是我對這個流程的理解,相信中間肯定有錯誤或者不到位的地方,在對這些知識有更進一步理解的時候我會返回及時更新。同時也歡迎各位指正~~

參考

  1. http://docs.jinkan.org/docs/flask/deploying/uwsgi.html
  2. http://www.cnblogs.com/zhouej/archive/2012/03/25/2379646.html
  3. http://www.cnblogs.com/Ray-liang/p/4173923.html
  4. https://github.com/nginx/nginx/blob/master/conf/uwsgi_params
  5. http://docs.jinkan.org/docs/flask/deploying/wsgi-standalone.html#deploying-proxy-setups
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 學習 Flask,寫完一個 Flask 應用需要部署的時候,就想著折騰自己的服務器。根據搜索的教程照做,對于原理一...
    Cocoa_Coder閱讀 17,225評論 4 56
  • 寫在前面的話: 本文參考了其他人寫的很多文章,在后面的附錄中列舉出來,未能及時列出的引用還望作者理解,本文僅僅作...
    如煙花非花閱讀 4,084評論 0 8
  • 首先說一下系統的選擇問題,先排除掉Windows系統,在Linux系統下,Ubuntu,Debian,CentOS...
    七月尾巴_葵花閱讀 1,181評論 0 3
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,908評論 18 139
  • 以前在部隊院校的時候,說起來又是軍官、又是教員,好像很牛掰的樣子,其實工資少得可憐,每個月都過得緊巴巴的。寒暑假回...
    徐二媽閱讀 485評論 1 5