介绍
在本指南中,我们将设置一个由uWSGI提供的简单的WSGI应用程序。 我们将使用Nginx Web服务器作为应用服务器的逆向代理,以提供更强大的连接处理。 我们将在Ubuntu 14.04服务器上安装和配置这些组件。
定义和概念
澄清一些条款
在我们进入之前,我们应该解决与我们将要处理的相互关联的概念相关的一些混乱的术语。 这三个单独的术语出现可互换,但实际上具有不同的含义:
- WSGI:一个Python的规范 ,它定义了应用程序或框架和应用程序/ Web服务器之间通信的标准接口。 这是为了简化和标准化这些组件之间的通信以实现一致性和可互换性而创建的。 这基本上定义了一个可以在其他协议上使用的API接口。
- uWSGI:应用服务器的容器,旨在为开发和部署Web应用程序和服务的完整的。 主要组件是可以处理不同语言的应用程序的应用程序服务器。 它使用WSGI规范定义的方法与应用程序通信,并通过各种其他协议与其他Web服务器通信。 这是将来自常规Web服务器的请求转换为应用程序可以处理的格式的一部分。
- uwsgi:由uWSGI服务器实现的快速,二进制协议与一个更全功能的Web服务器进行通信。 这是一个有线协议 ,而不是传输协议。 这是与代理uWSGI请求的Web服务器通信的首选方式。
WSGI应用程序要求
WSGI规范定义了Web服务器和的应用程序部分之间的接口。 在此上下文中,“Web服务器”是指uWSGI服务器,负责使用WSGI规范将客户端请求转换为应用程序。 这简化了通信并创建松散耦合的组件,以便您可以轻松地换出任何一侧,而没有太多的麻烦。
Web服务器(uWSGI)必须能够通过触发定义的“可调用”将请求发送到应用程序。 可调用只是进入应用程序的入口点,其中Web服务器可以调用具有一些参数的函数。 期望的参数是环境变量的字典和由web服务器(uWSGI)组件提供的可调用。
作为响应,应用程序返回一个可迭代,将用于生成客户端响应的主体。 它还将调用它作为参数接收的Web服务器组件可调用。 触发web服务器可调用的第一个参数将是HTTP状态代码,第二个参数将是元组列表,每个元组定义响应头和值发送回客户端。
在此实例中,由uWSGI提供的此交互的“Web服务器”组件,我们只需要确保我们的应用程序具有上述的质量。 我们还将设置Nginx处理实际的客户端请求并将它们代理到uWSGI服务器。
安装组件
要开始,我们需要在我们的Ubuntu 14.04服务器上安装必要的组件。 我们主要可以做到这一点使用apt
和pip
。
首先,刷新apt
包索引,然后安装Python开发库和头文件,该pip
Python包管理器,Nginx的Web服务器和反向代理:
sudo apt-get update
sudo apt-get install python-dev python-pip nginx
一旦软件包安装完成后,您将有机会获得pip
Python包管理器。 我们可以用它来安装virtualenv
包,我们将使用我们的应用程序的Python环境免受可能在系统上不存在其他任何隔离:
sudo pip install virtualenv
一旦完成,我们可以开始为我们的应用程序创建一般结构。 我们将创建上述虚拟环境,并在此环境中安装uWSGI应用程序服务器。
设置应用程序目录和Virtualenv
我们将开始为我们的应用程序创建一个文件夹。 这可以在更完整的应用程序中保存包含实际应用程序代码的嵌套文件夹。 为了我们的目的,这个目录将简单地保存我们的虚拟环境和我们的WSGI入口点:
mkdir ~/myapp/
接下来,移动到目录,以便我们可以为我们的应用程序设置环境:
cd ~/myapp
创建与虚拟环境virtualenv
命令。 我们称这个myappenv
为简单:
virtualenv myappenv
一个新的Python环境将一个名为目录下建立myappenv
。 我们可以通过键入以下内容来激活此环境:
source myappenv/bin/activate
您的提示应该更改,以指示您现在在虚拟环境中操作。 它看起来像这样:
(myappenv)username@host:~/my_app$
如果您希望随时离开此环境,可以直接键入:
deactivate
如果已停用环境,请再次重新激活它以继续使用指南。
在此环境处于活动状态时,安装的任何Python软件包都将包含在此目录层次结构中。 它们不会干扰系统的Python环境。 考虑到这一点,我们现在可以在uWSGI服务器使用安装到我们的环境pip
。 该软件包这一被称为uwsgi
(这仍然是uWSGI服务器,而不是uwsgi
协议):
pip install uwsgi
您可以通过键入以下内容来验证其是否可用:
uwsgi --version
如果它返回一个版本号,uWSGI服务器可以使用。
创建WSGI应用程序
接下来,我们将使用前面讨论的WSGI规范要求创建一个非常简单的WSGI应用程序。 重申一下,我们必须提供的应用程序组件应该具有以下属性:
- 它必须通过可调用(可调用的函数或其他语言结构)提供接口,
- 可调用项必须将包含环境变量类键值对的字典和可在服务器(uWSGI)上访问的可调用项作为参数。
- 应用程序的可调用应该返回一个迭代器,它将产生正文发送客户端。
- 应用程序应使用HTTP状态和请求标头调用Web服务器的callable。
我们将写我们在一个名为应用wsgi.py
在我们的应用程序目录:
nano ~/myapp/wsgi.py
在这个文件中,我们将创建最简单的WSGI兼容应用程序。 和所有的Python代码一样,一定要注意缩进:
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return ["<h1 style='color:blue'>Hello There!</h1>"]
上述代码构成一个完整的WSGI应用程序。 默认情况下,uWSGI将寻找一个名为调用application
,这就是为什么我们呼吁我们的功能application
。 如你所见,它需要两个参数。
第一,我们称为environ
因为这将是一个环境变量样键值字典。 第二种称为start_response
并且是名称的应用程序将在内部使用来指代网络服务器(uWSGI)可调用被在发送的。这两种参数名的,因为它们在实施例中使用的是简单地选择PEP 333规格说定义WSGI交互。
我们的应用程序必须采取这些信息,做两件事。 首先,它必须调用它接收到的可调用的HTTP状态代码和它想要发回的任何头。 在这种情况下,我们正在发送“200 OK”响应,并设置Content-Type
头text/html
。
其次,它需要返回一个迭代器作为响应体。 在这里,我们刚刚使用了一个包含单个HTML字符串的列表。 字符串也是可迭代的,但是在列表内部,uWSGI将能够通过一次迭代来处理整个字符串。
在现实世界的情况下,这个文件可能会被用作到你的应用程序代码的其余部分的链接。 例如,Django的项目包括一个wsgi.py
默认文件转换来自web服务器(uWSGI)到应用程序(Django的)请求。 简化的WSGI接口保持相同,而不管实际应用代码是多么复杂。 这是接口的优势之一。
保存并在完成后关闭文件。
为了测试代码,我们可以启动uWSGI。 我们会告诉它使用HTTP暂时并监听端口8080
。 我们将传递脚本的名称(删除Stapling):
uwsgi --socket 0.0.0.0:8080 --protocol=http -w wsgi
现在,如果你访问你的服务器的IP地址或域名在网络浏览器后:8080
,你会看到我们在我们的身体传递的第一级标题文字wsgi.py
文件:
当您验证此工作原理时,使用CTRL-C停止服务器。
我们现在已经完成了设计我们的实际应用程序。 如果您愿意,可以停用我们的虚拟环境:
deactivate
配置uWSGI配置文件
在上面的示例中,我们手动启动uWSGI服务器,并在命令行上传递了一些参数。 我们可以通过创建一个配置文件来避免这种情况。 该uWSGI服务器可以以多种格式读配置,但是我们将使用.ini
格式为简单起见。
要继续,我们一直使用至今的命名,我们将调用文件myapp.ini
并将其放置在我们的应用程序文件夹:
nano ~/myapp/myapp.ini
在内部,我们需要建立一个叫做节[uwsgi]
这一部分是我们所有的配置项。 我们将从确定我们的应用程序开始。 uWSGI服务器需要知道应用程序的可调用位置。 我们可以给文件和函数内:
[uwsgi]
module = wsgi:application
我们要以纪念初始uwsgi
过程作为主,然后产生一个工作进程数。 我们将从五个工人开始:
[uwsgi]
module = wsgi:application
master = true
processes = 5
我们实际上要改变uWSGI用于与外部世界交谈的协议。 当我们在测试应用程序,我们指定--protocol=http
这样我们就可以从Web浏览器看到它。 由于我们将在uWSGI之前配置Nginx作为反向代理,我们可以改变它。 nginx的实现了一个uwsgi
代理机制,这是一种快速二进制协议,uWSGI可以使用与其他服务器交谈。 该uwsgi
协议实际上是uWSGI的默认协议,所以干脆省略一个协议规范,它将回落到uwsgi
。
由于我们正在设计这个配置使用Nginx,我们也将改变从使用网络端口和使用Unix套接字。 这更安全,更快。 如果我们使用相对路径,将在当前目录中创建套接字。 我们叫它myapp.sock
。 我们将权限更改为“664”,这样的Nginx可以写入(我们将与首发uWSGI www-data
是Nginx的使用群体。我们也将添加vacuum
选项,这将删除插座时,进程停止:
[uwsgi]
module = wsgi:application
master = true
processes = 5
socket = myapp.sock
chmod-socket = 664
vacuum = true
我们需要一个最终选项,因为我们将创建一个Upstart文件来启动我们的应用程序。 Upstart和uWSGI对于SIGTERM信号应该对应用程序应该做什么有不同的想法。 理清这种差异,使得进程可以与Upstart预期来处理,我们只需要添加一个名为选项die-on-term
这样uWSGI将终止进程,而不是重新加载它:
[uwsgi]
module = wsgi:application
master = true
processes = 5
socket = myapp.sock
chmod-socket = 664
vacuum = true
die-on-term = true
保存并在完成后关闭文件。 此配置文件现在设置为与Upstart脚本一起使用。
创建一个Upstart文件来管理应用程序
我们可以在启动时启动uWSGI实例,以便我们的应用程序始终可用。 我们将在此放置/etc/init
目录Upstart检查。 我们将调用这个myapp.conf
:
sudo nano /etc/init/myapp.conf
首先,我们可以从服务的描述开始,并选择应该自动运行的系统运行级别。 标准用户运行级别是2到5.我们将告诉Upstart在该组之外的任何运行级别上停止服务(例如,当系统正在重新启动或在单用户模式下):
description "uWSGI instance to serve myapp"
start on runlevel [2345]
stop on runlevel [!2345]
接下来,将告诉Upstart关于哪个用户和组运行该进程。 我们要根据我们自己的帐户运行应用程序(我们使用demo
本指南中,但你应该使用自己的用户)。 我们要组设置为www-data
不过是Nginx的使用用户。 因为web服务器需要能够读取和写入,我们的插座,这是必要.ini
文件将创建:
description "uWSGI instance to serve myapp"
start on runlevel [2345]
stop on runlevel [!2345]
setuid demo
setgid www-data
接下来,我们将运行实际的命令来启动uWSGI。 由于我们将uWSGI安装到虚拟环境中,我们还需要做一些额外的工作。 我们可以只提供uWSGI可执行文件的整个路径,而是激活虚拟环境。 这将使我们更容易,如果我们依靠在环境中安装的额外的软件。
要做到这一点,我们将使用一个script
块。 在内部,我们将改变我们的应用程序目录,激活虚拟环境(我们必须使用.
在脚本中,而不是source
),并启动uWSGI实例在我们指出.ini
文件:
description "uWSGI instance to serve myapp"
start on runlevel [2345]
stop on runlevel [!2345]
setuid demo
setgid www-data
script
cd /home/demo/myapp
. myappenv/bin/activate
uwsgi --ini myapp.ini
end script
有了这个,我们的Upstart脚本就完成了。 保存并在完成后关闭文件。
现在,我们可以通过键入以下内容启动服务:
sudo start myapp
我们可以通过键入以下内容来验证它是否已启动:
ps aux | grep myapp
demo 14618 0.0 0.5 35868 5996 ? S 15:02 0:00 uwsgi --ini myapp.ini
demo 14619 0.0 0.5 42680 5532 ? S 15:02 0:00 uwsgi --ini myapp.ini
demo 14620 0.0 0.5 42680 5532 ? S 15:02 0:00 uwsgi --ini myapp.ini
demo 14621 0.0 0.5 42680 5532 ? S 15:02 0:00 uwsgi --ini myapp.ini
demo 14622 0.0 0.5 42680 5532 ? S 15:02 0:00 uwsgi --ini myapp.ini
demo 14623 0.0 0.5 42680 5532 ? S 15:02 0:00 uwsgi --ini myapp.ini
demo 15520 0.0 0.0 11740 936 pts/0 S+ 15:53 0:00 grep --color=auto myapp
这将在启动时自动启动。 您可以随时通过键入以下内容停止服务:
sudo stop myapp
将Nginx配置为代理到uWSGI
在这一点上,我们有一个WSGI应用程序,并已验证uWSGI可以读取和服务它。 我们已经创建了一个配置文件和一个Upstart脚本。 我们uWSGI进程将监听套接字,并使用通信uwsgi
协议。
现在我们可以开始配置Nginx作为反向代理。 Nginx的具有使用能力的代理uwsgi
与uWSGI通信协议。 这是一个比HTTP更快的协议,性能更好。
我们将要设置的Nginx配置是非常简单的。 创建中的一个新的文件sites-available
的Nginx的配置层次结构中的目录。 我们会打电话给我们的文件myapp
来匹配我们一直使用的应用程序名称:
sudo nano /etc/nginx/sites-available/myapp
在此文件中,我们可以指定此服务器块应响应的端口号和域名。 在我们的示例中,我们将使用默认端口80:
server {
listen 80;
server_name server_domain_or_IP;
}
因为我们希望这个域名或IP地址的所有请求发送到我们的应用程序WSGI,我们将创建开头的请求一个位置块/
,这应该匹配一切。 在内部,我们将使用include
指令来包含一些与我们的Nginx的配置目录中的文件合理的默认参数。 包含这些文件被称为uwsgi_params
。 随后,我们将通信传递给我们的uWSGI实例在uwsgi
协议。 我们将使用我们之前配置的unix套接字:
server {
listen 80;
server_name server_domain_or_IP;
location / {
include uwsgi_params;
uwsgi_pass unix:/home/demo/myapp/myapp.sock;
}
}
这实际上是我们需要一个简单的应用程序。 可以对一个更完整的应用程序做一些改进。 例如,我们可以在该块之外定义一些上游uWSGI服务器,然后将它们传递给它。 我们可能包括一些uWSGI参数。 我们还可以直接处理Nginx的任何静态文件,并只向uWSGI实例传递动态请求。
我们不需要任何这些功能,我们的三行应用程序,所以我们可以保存和关闭文件。
启用,我们只是将其链接到所取得的服务器配置sites-enabled
目录:
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled
检查配置文件是否有语法错误:
sudo service nginx configtest
如果它报告没有检测到问题,请重新启动服务器以实现更改:
sudo service nginx restart
一旦Nginx重新启动,您应该能够去您的服务器的域名或IP地址(没有端口号),并看到您配置的应用程序:
结论
如果你已经做到了这一点,你已经创建了一个简单的WSGI应用程序,并有一些洞察如何更复杂的应用程序将需要设计。 我们已经将uWSGI应用程序容器/服务器安装到一个特定的虚拟环境中来为我们的应用程序提供服务。 我们已经创建了一个配置文件和一个Upstart脚本来自动化这个过程。 在uWSGI服务器的前面,我们已经设置了可使用的uWSGI进程的讲话Nginx的反向代理uwsgi
线协议。
您可以轻松地了解在设置实际生产环境时如何扩展这一功能。 例如,uWSGI有能力使用称为“皇帝模式”的东西管理多个应用程序。 您可以扩展Nginx配置以在uWSGI实例之间实现负载平衡,或者为应用程序处理静态文件。 当服务多个应用程序时,根据您的需要,在全球安装uWSGI而不是在虚拟环境中安装uWSGI可能符合您的最佳利益。 组件都相当灵活,因此您应该能够调整其配置以适应许多不同的方案。