介绍
在本指南中,我们将设置一个简单的WSGI应用程序,由uWSGI提供服务,我们将使用 Nginx Web 服务器作为应用程序服务器的反向代理,以提供更强大的连接处理。
定义和概念
澄清一些术语
在我们跳进之前,我们应该解决一些与我们正在处理的相互关联概念相关的混淆术语,这些三个单独的术语看起来是可互换的,但实际上有不同的含义:
WSGI:A [Python spec] (https://www.python.org/dev/peps/pep-0333/),定义了应用程序或框架与应用程序/网络服务器之间通信的标准接口. 建立这一系统是为了简化这些组成部分之间的通信并使之标准化,以便实现一致性和可互换性。 这基本上定义了一个可以在其他协议上使用的API接口. (_) ( ) ** uWSGI**:一个应用程序服务器容器,旨在为开发和部署网络应用程序和服务提供一个完整的堆栈。 主要组件是能够处理不同语言应用的应用程序服务器. 它使用WSGI spec所定义的方法与应用程序进行通信,并与其他网络服务器通过多种其他协议进行通信. 这是将常规网络服务器的请求翻译为应用程序可以处理的格式的作品. (_) ( )* uwsgi:由uWSGI服务器执行的快 二进制协议,与更全能的网络服务器通信. 这是[有线协议 (http://en.wikipedia.org/wiki/Wire_protocol),不是运输协议. 它是向代理给 uWSGI 请求的网络服务器说话的首选方式( _) (英语)
WSGI 应用要求
WSGI spec 定义了 Web 服务器和堆栈中的应用程序部分之间的界面,在这种情况下,Web 服务器
是指 uWSGI 服务器,它负责使用 WSGI spec 将客户端请求翻译到应用程序。
网络服务器(uWSGI)必须能够通过触发定义的可调用
来向应用程序发送请求,而可调用只是应用程序的入口点,在那里网络服务器可以调用具有某些参数的函数。
作为回应,应用程序会返回一个可迭代的,它将用于生成客户端响应的体。它还会调用它作为参数接收的 Web 服务器组件的可调用。在触发 Web 服务器可调用时,第一个参数将是 HTTP 状态代码,第二个将是一个列表的 tuples,其中每一个都定义了一个响应标题和值,将其发送回客户端。
在这种情况下,使用 uWSGI 提供的Web 服务器
组件,我们只需要确保我们的应用程序具有上面描述的特性,我们还会设置 Nginx 来处理实际的客户端请求,并向 uWSGI 服务器代理它们。
安装组件
要开始,我们需要在Ubuntu 14.04服务器上安装必要的组件,我们主要可以使用apt
和pip
来做到这一点。
首先,刷新你的apt
包索引,然后安装Python开发库和标题,Python的pip
包管理器,以及NginxWeb服务器和反向代理:
1sudo apt-get update
2sudo apt-get install python-dev python-pip nginx
一旦包安装完成,您将可以访问pip
Python包管理器,我们可以使用它来安装virtualenv
包,我们将使用它来将我们的应用程序的Python环境与系统上可能存在的任何其他环境隔离:
1sudo pip install virtualenv
一旦完成,我们可以开始为我们的应用程序创建总体结构,我们将创建上面讨论的虚拟环境,并在这个环境中安装uWSGI应用程序服务器。
创建一个App目录和一个Virtualenv
我们将开始为我们的应用程序创建一个文件夹,这可以包含一个包含实际应用程序代码的嵌套文件夹在一个更完整的应用程序中。
1mkdir ~/myapp/
接下来,进入目录,这样我们就可以为我们的应用程序设置环境:
1cd ~/myapp
使用virtualenv
命令创建一个虚拟环境,我们将这个命名为myappenv
来表示简单性:
1virtualenv myappenv
在名为myappenv
的目录下将设置一个新的Python环境,我们可以通过键入来激活这个环境:
1source myappenv/bin/activate
您的提示应更改,以表示您现在在虚拟环境中运行,它将看起来像这样:
1(myappenv)username@host:~/my_app$
如果您想随时离开此环境,您可以简单地键入:
1deactivate
如果您已禁用您的环境,请重新激活它以继续使用指南。
有了这个环境,安装的任何Python包都将包含在这个目录层次中,它们不会干扰系统的Python环境,因此我们现在可以使用pip
将uWSGI服务器安装到我们的环境中,而这个包称为uwsgi
(这仍然是uWSGI服务器而不是uwsgi
协议):
1pip install uwsgi
您可以通过键入来验证它现在可用:
1uwsgi --version
如果返回版本号,则 uWSGI 服务器可供使用。
创建一个WSGI应用程序
接下来,我们将使用我们之前讨论的 WSGI 规范要求创建一个非常简单的 WSGI 应用程序。
- 它必须通过调用器(可调用的函数或其他语言构造)提供界面 *调用器必须作为参数使用包含环境变量类型的关键值对的字典和在服务器上可访问的调用器(uWSGI)。
- 应用程序的调用器应该返回一个迭代器,该器官将发送客户端
- 应用程序应该通过 HTTP 状态和请求标题调用Web服务器的调用器
我们将在我们的应用程序目录中写入名为wsgi.py
的文件:
1nano ~/myapp/wsgi.py
在此文件中,我们将创建我们所能做的最简单的WSGI合规应用程序。
1def application(environ, start_response):
2 start_response('200 OK', [('Content-Type', 'text/html')])
3 return ["<h1 style='color:blue'>Hello There!</h1>"]
上面的代码构成一个完整的 WSGI 应用程序. 默认情况下,uWSGI 会搜索一个称为应用程序
的可调用,这就是为什么我们称我们的函数为应用程序
。
第一个我们称之为environ
,因为它将是一个环境变量类似的关键值字典。第二个被称为start_response
,是应用程序将内部使用的名称,以参考发送的 Web 服务器 (uWSGI) 调用。
我们的应用程序必须收集这些信息并做两件事:首先,它必须用HTTP状态代码和它想要发送的任何标题来呼叫所接收的通话,在这种情况下,我们正在发送一个200OK
响应,并将内容类型
标题设置为文本/html
。
其次,它需要返回一个可迭代,以作为响应体。在这里,我们刚刚使用了一个包含一个HTML字符串的列表. 字符串也是可迭代的,但在列表中,uWSGI将能够用一个迭代处理整个字符串。
在现实世界的情况下,这个文件很可能被用来链接到你的应用程序代码的其余部分,例如,Django项目默认情况下包含一个wsgi.py
文件,它将请求从Web服务器(uWSGI)转换为应用程序(Django)。
保存并关闭文件,当你完成。
要测试代码,我们可以启动uWSGI,我们会告诉它暂时使用HTTP,并倾听端口8080
。
1uwsgi --socket 0.0.0.0:8080 --protocol=http -w wsgi
现在,如果您在浏览器中访问您的服务器的 IP 地址或域名,然后是 :8080
,您应该在我们的 wsgi.py
文件中看到我们通过的第一级标题文本:
停止服务器使用CTRL-C,当您验证了此功能。
我们已经完成了我们实际应用程序的设计,如果您想要的话,您可以禁用我们的虚拟环境:
1deactivate
设置 uWSGI Config 文件
在上面的示例中,我们手动启动了 uWSGI 服务器,并在命令行上传递了一些参数。我们可以通过创建配置文件来避免这种情况。
为了继续我们迄今为止使用的命名,我们将命名文件myapp.ini
,并将其放入我们的应用程序文件夹:
1nano ~/myapp/myapp.ini
内部,我们需要建立一个名为[uwsgi]
的部分。这个部分是我们所有的配置项目将居住的地方。我们将通过识别我们的应用程序开始。 uWSGI 服务器需要知道应用程序的可调用位置。
1[uwsgi]
2module = wsgi:application
我们希望将最初的uwsgi
过程标记为主,然后生成一系列工人过程,我们将从五个工人开始:
1[uwsgi]
2module = wsgi:application
3
4master = true
5processes = 5
当我们测试我们的应用程序时,我们指定了--protocol=http
,以便我们可以从网页浏览器中看到它. 由于我们将在 uWSGI 前配置 Nginx 作为反向代理,我们可以改变这一点。 Nginx 实施了一个uwsgi
代理机制,这是一个快速的二进制协议, uWSGI 可以用来与其他服务器交谈。
由于我们正在设计此配置以使用 Nginx,我们也将更改使用网络端口,而不是使用Unix接口。这更安全,更快。如果我们使用相对路径,接口将创建在当前目录中。我们将称之为myapp.sock。我们将更改权限为664
,以便 Nginx 可以写入它(我们将使用的www-data
组开始使用uWSGI。我们还将添加真空
选项,在过程停止时将接口移除:
1[uwsgi]
2module = wsgi:application
3
4master = true
5processes = 5
6
7socket = myapp.sock
8chmod-socket = 664
9vacuum = true
我们需要一个最后的选项,因为我们将创建一个Upstart文件,以便在启动时启动我们的应用程序。Upstart和uWSGI对SIGTERM信号应该对应用程序做什么有不同的想法。
1[uwsgi]
2module = wsgi:application
3
4master = true
5processes = 5
6
7socket = myapp.sock
8chmod-socket = 664
9vacuum = true
10
11die-on-term = true
完成后保存并关闭文件. 此配置文件现在已设置为与 Upstart 脚本一起使用。
创建一个升级文件来管理应用程序
我们可以在启动时启动一个 uWSGI 实例,以便我们的应用程序始终可用。我们会将此置于 Upstart 检查的 `/etc/init’ 目录中。
1sudo nano /etc/init/myapp.conf
首先,我们可以从服务的描述开始,并选择系统运行级别,在那里它应该自动运行。标准用户运行级别是2到5。我们会告诉Upstart在该组以外的任何运行级别时停止服务(例如当系统重新启动或单用户模式):
1description "uWSGI instance to serve myapp"
2
3start on runlevel [2345]
4stop on runlevel [!2345]
我们希望在自己的帐户下运行应用程序(我们在本指南中使用演示
,但你应该取代自己的用户)。
1description "uWSGI instance to serve myapp"
2
3start on runlevel [2345]
4stop on runlevel [!2345]
5
6setuid demo
7setgid www-data
接下来,我们将运行实际的命令来启动uWSGI. 由于我们在虚拟环境中安装uWSGI,我们还有一些额外的工作要做。
内部,我们将更改到我们的应用目录,激活虚拟环境(我们必须在脚本中使用 .
而不是 source
),并启动 uWSGI 实例,指向我们的 .ini
文件:
1description "uWSGI instance to serve myapp"
2
3start on runlevel [2345]
4stop on runlevel [!2345]
5
6setuid demo
7setgid www-data
8
9script
10 cd /home/demo/myapp
11 . myappenv/bin/activate
12 uwsgi --ini myapp.ini
13end script
有了它,我们的Upstart脚本完成了. 保存和关闭文件,当你完成。
现在,我们可以通过键入开始服务:
1sudo start myapp
我们可以验证它是通过键入开始的:
1ps aux | grep myapp
1demo 14618 0.0 0.5 35868 5996 ? S 15:02 0:00 uwsgi --ini myapp.ini
2demo 14619 0.0 0.5 42680 5532 ? S 15:02 0:00 uwsgi --ini myapp.ini
3demo 14620 0.0 0.5 42680 5532 ? S 15:02 0:00 uwsgi --ini myapp.ini
4demo 14621 0.0 0.5 42680 5532 ? S 15:02 0:00 uwsgi --ini myapp.ini
5demo 14622 0.0 0.5 42680 5532 ? S 15:02 0:00 uwsgi --ini myapp.ini
6demo 14623 0.0 0.5 42680 5532 ? S 15:02 0:00 uwsgi --ini myapp.ini
7demo 15520 0.0 0.0 11740 936 pts/0 S+ 15:53 0:00 grep --color=auto myapp
此功能将在启动时自动启动,您可以通过键入以下方式随时停止服务:
1sudo stop myapp
配置 Nginx 到 proxy 到 uWSGI
此时,我们有一个 WSGI 应用程序,并验证了 uWSGI 能够读取和服务它. 我们创建了一个配置文件和一个 Upstart 脚本. 我们的 uWSGI 流程将通过插槽收听并使用uwsgi
协议进行通信。
现在我们可以将 Nginx 配置为反向代理程序, Nginx 可以使用 uwsgi
协议来与 uWSGI 进行通信,这是比 HTTP 更快的协议,而且性能会更好。
我们将设置的 Nginx 配置非常简单,在 Nginx 配置等级框架内的可用网站
目录中创建一个新文件,我们将我们的文件称为myapp
,以匹配我们一直在使用的应用名称:
1sudo nano /etc/nginx/sites-available/myapp
在此文件中,我们可以指定该服务器块应响应的端口号和域名,在我们的情况下,我们将使用默认端口80:
1server {
2 listen 80;
3 server_name server_domain_or_IP;
4}
由于我们希望将这个域或IP地址的所有请求发送到我们的WSGI应用程序中,我们将为从/
开始的请求创建一个单一的位置块,这应该与一切相匹配。 内部,我们将使用包括
指令,从我们的Nginx配置目录中包含一些合理的默认值的参数。 包含这些的文件被称为uwsgi_params
。 之后,我们将通过uwsgi
协议将流量传输到我们的uWSGI实例。
1server {
2 listen 80;
3 server_name server_domain_or_IP;
4
5 location / {
6 include uwsgi_params;
7 uwsgi_pass unix:/home/demo/myapp/myapp.sock;
8 }
9}
这实际上是简单的应用程序所需的一切。对于一个更完整的应用程序,可以做一些改进,例如,我们可能在这个块之外定义了一些上游的uWSGI服务器,然后将其传递给它。
我们不需要我们三行应用中的任何这些功能,所以我们可以保存和关闭文件。
启用我们刚刚创建的服务器配置,将其链接到网站启用
目录:
1sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled
检查配置文件,查找语法错误:
1sudo service nginx configtest
如果回报没有发现问题,请重新启动服务器以实现更改:
1sudo service nginx restart
一旦 Nginx 重新启动,您应该能够到您的服务器的域名或 IP 地址(没有端口号),并查看您配置的应用程序:
结论
如果你已经做到了,你已经创建了一个简单的WSGI应用程序,并有一些洞察力如何设计更复杂的应用程序。我们已经安装了uWSGI应用程序容器/服务器到一个专门的虚拟环境中服务我们的应用程序。我们已经创建了一个配置文件和一个Upstart脚本来自动化这个过程。
例如,uWSGI 具有使用所谓的温度模式
来管理多个应用程序的能力。您可以扩展 Nginx 配置,以便在 uWSGI 实例之间进行负载平衡,或者为您的应用程序处理静态文件。 服务多个应用程序时,您可能最感兴趣的是在全球范围内安装 uWSGI 而不是在虚拟环境中,取决于您的需求。 所有组件都相当灵活,因此您应该能够调整其配置以适应许多不同的场景。