如果你在 Google 或者百度或者某些技术社区上面搜索uwsgi + Flask
,你会发现大量的文章,是教你如何使用uwsgi + Flask + Nginx
搭建网站。如下图所示:
而且这些文章,全部都像是约定俗成一样,一定会首先用命令行启动 uwsgi,测试 uwsgi 与 Flask 运行是否正常,然后写 uwsgi 的配置文件。然后使用Unix 套接字
沟通 uwsgi 与 Nginx。所以 uwsgi 的配置文件里面一定会写成类似于下面这样:
socket = /xxx/yyy/zzz.sock
Nginx 的配置一定有类似于下面这一段:
location / {
include uwsgi_params;
uwsgi_pass unix:///xxx/yyy/zzz.sock;
}
他们为什么要这样写?因为他们看的别的博客上就是这样写的!他们知其然,但是不知其所以然。
这种写法本身没有问题,甚至 Flask 的官方文档里面也是这样写的,如下图所示:
但是他们这样写,有一个基本前提——就是 Flask 程序、uwsgi、Nginx 三个东西运行在同一个服务器上。如果用 Docker,那么这三个东西甚至需要运行到一个容器里面。
如果是一个小网站,服务器资源足够,那么这样写没有问题,Unix 套接字安全性高,速度也快。
那么如果你同一个服务器上有三个 Docker 容器,每一个容器都有一个不同的网站,是不是每个容器里面都需要安装一个 Nginx ?
对于大一些的网站,Nginx 需要做负载均衡,如果把 Nginx 和网站放在同一台服务器上,无论是 Nginx 拖垮了服务器,还是网站拖垮了服务器,都会导致很严重的问题。
能不能实现,一个服务器上直接安装 Nginx,然后服务器上的三个网站分别在三个 Docker 容器里面,每个容器里面只有 Flask 和 uwsgi,没有 Nginx ?
如果你的网站大一些,你在 A 服务器安装 Nginx,在 B、C、D、E、F 服务器上不安装 Nginx,只安装 uwsgi + Flask,又怎么做?
所以进入我们今天的主题,安装 uwsgi + Flask(或者 Django),但是不安装 Nginx ( Deploy Flask with uwsgi but without Nginx )
Unix 套接字,本质上是一个文件( Unix/Linux 哲学:一切皆文件),Nginx 和 uwsgi 通过这个文件来进行通信。所以需要 Nginx 与 uwsgi 放在同一个机器上。
但实际上,uwsgi 本身就是一个服务器,A 服务器上的 Nginx 与 B 服务器上的 uwsgi 之间是可以通过 http 进行通信的。
要让 uwsgi 使用 http 进行通信,我们可以修改 uwsgi 的配置文件 xxx.ini:
[uwsgi]
module = wsgi:app
master = true
process = 5
threads = 100
gevent = 100
async = 100
http-socket = 0.0.0.0:5001
virtualenv = /Users/kingname/.local/share/virtualenvs/ActiveScoreApi-Ax_h-Y5w
其他参数的意义不是本文的重点,我们要关心的是http-socket = 0.0.0.0:5001
。它的作用把网站部署在本机的 5001 端口,并允许外网通过 http 访问。
写了这个配置文件以后,通过以下命令来启动 uwsgi:
uwsgi --ini xxx.ini
然后你使用IP:5001
就可以访问你的网站了。此时,如果你有 Nginx,那么只需要在 Nginx 上设置反向代理,把 80 端口的请求代理到 5001 端口即可。
同理,把 uwsgi 和网站放在 Docker 镜像里面,容器开放 5001 端口。宿主机或者其他机器上的 Nginx 直接通过 IP:端口 就可以访问容器里面的 uwsgi,不再需要设置 Unix 套接字了。
另外,如果你阅读过 uwsgi 的官方文档,你还会发现,除了http-socket = 0.0.0.0:5001
外,你也可以把它改成http = 0.0.0.0:5001
。那么这两种写法是否一样呢?
在官方文档里面特别区分了它们的使用场景:
The http and http-socket options are entirely different beasts. The first one spawns an additional process forwarding requests to a series of workers (think about it as a form of shield, at the same level of apache or nginx), while the second one sets workers to natively speak the http protocol. TL/DR: if you plan to expose uWSGI directly to the public, use --http, if you want to proxy it behind a webserver speaking http with backends, use --http-socket.
简言之,如果你直接把 uwsgi 作为服务器,uwsgi 启动以后,直接就把 IP:端口拿给别人访问,那么你就可以使用http
;如果你的 uwsgi 前面还挡了一个 Nginx,那么你就使用http-socket
。
本文首发于我的微信公众号 未闻 Code ( ID:itskingname )
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.