[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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266

推荐阅读更多精彩内容