如何在Ubuntu 14.04上设置uWSGI和Nginx以服务Python应用程序

介绍

在本教程中,我们将设置一个由uWSGI提供服务的简单WSGI应用程序。我们将使用Nginx Web服务器作为应用程序服务器的反向代理,以提供更强大的连接处理。我们将在Ubuntu 14.04服务器上安装和配置这些组件。

要完成本教程,您需要具备一台已经设置好可以使用sudo命令的非root账号的Ubuntu服务器,并且已开启防火墙。没有服务器的同学可以在这里购买,不过我个人更推荐您使用免费的腾讯云开发者实验室进行试验,学会安装后再购买服务器

定义和概念

澄清一些条款

在我们进入之前,我们应该解决一些与我们将要处理的相互关联的概念相关的令人困惑的术语。这三个单独的术语看似可以互换,但实际上有不同的含义:

  • WSGIPython规范,定义了应用程序或框架与应用程序/ 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服务器上安装必要的组件。我们主要可以使用aptpip来完成。

首先,刷新apt包索引,然后安装Python开发库和头文件,pipPython包管理器,以及Nginx Web服务器和反向代理:

sudo apt-get update
sudo apt-get install python-dev python-pip nginx

程序包安装完成后,您将可以访问pipPython程序包管理器。我们可以使用它来安装virtualenv包,我们将用它来隔离我们的应用程序的Python环境与系统上可能存在的任何其他环境:

sudo pip install virtualenv

一旦完成,我们就可以开始为我们的应用程序创建一般结构。我们将创建上面讨论的虚拟环境,并将在此环境中安装uWSGI应用程序服务器。

设置App Directory和Virtualenv

我们将首先为我们的应用程序创建一个文件夹。这可以在更完整的应用程序中保存包含实际应用程序代码的嵌套文件夹。出于我们的目的,这个目录将简单地保存我们的虚拟环境和WSGI入口点:

mkdir ~/myapp/

接下来,进入目录,以便我们可以为我们的应用程序设置环境:

cd ~/myapp

使用virtualenv命令创建虚拟环境。我们将myappenv简单地称之为:

virtualenv myappenv

将在名为myappenv的目录下设置新的Python环境。我们可以通过输入以下命令激活此环:

source myappenv/bin/activate

您的提示应更改为表明您现在正在虚拟环境中运行。它看起来像这样:

(myappenv)username@host:~/my_app$

如果您希望随时离开此环境,只需键入:

deactivate

如果您已停用环境,请重新将其重新激活以继续使用教程。

在此环境处于活动状态时,安装的任何Python包都将包含在此目录层次结构中。它们不会干扰系统的Python环境。考虑到这一点,我们现在可以使用pip将uWSGI服务器安装到我们的环境中。调用uwsgi包(这仍然是uWSGI服务器而不是uwsgi协议):

pip install uwsgi

您可以通过键入以下内容来验证它现在是否可用:

uwsgi --version

如果它返回版本号,则uWSGI服务器可供使用。

创建WSGI应用程序

接下来,我们将使用前面讨论过的WSGI规范要求创建一个非常简单的WSGI应用程序。重申一下,我们必须提供的应用程序组件应具有以下属性:

  • 它必须通过可调用(可以调用的函数或其他语言结构)提供接口
  • callable必须将包含类似环境变量的键值对的字典和可在服务器上访问的可调用字符(uWSGI)作为参数。
  • 应用程序的可调用应该返回一个迭代,它将生成发送客户端的主体。
  • 应用程序应使用HTTP状态和请求标头调用Web服务器的可调用对象。

我们将在应用程序目录中调用的文件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,是应用程序将在内部使用的名称,用于引用发送的Web服务器(uWSGI)可调用。这两个参数名称都被简单选择,因为它们用于定义的PEP 333规范中的示例WSGI交互。

我们的应用程序必须获取此信息并执行两项操作。首先,它必须使用HTTP状态代码和它想要发回的任何头来调用它收到的可调用对象。在这种情况下,我们发送“200 OK”响应并将Content-Type标头设置为text/html

其次,它需要返回一个iterable来用作响应体。在这里,我们刚刚使用了一个包含单个HTML字符串的列表。字符串也是可迭代的,但是在列表内部,uWSGI将能够通过一次迭代处理整个字符串。

在现实世界中,此文件可能会用作其他应用程序代码的链接。例如,Django项目默认包含一个文件wsgi.py,用于将来自Web服务器(uWSGI)的请求转换为应用程序(Django)。无论实际应用程序代码有多复杂,简化的WSGI接口都保持不变。这是界面的优势之一。

完成后保存并关闭文件。

要测试代码,我们可以启动uWSGI。我们将告诉它暂时使用HTTP并监听端口8080。我们将传递脚本的名称(后缀已删除):

uwsgi --socket 0.0.0.0:8080 --protocol=http -w wsgi

现在,如果您在Web浏览器中访问以:8080结尾的服务器的IP地址或域名,则应该看到我们在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可以写入它(我们将www-data使用Nginx使用的组启动uWSGI 。我们还将添加vacuum选项,这将在进程停止时删除套接字:

[uwsgi]
module = wsgi:application
​
master = true
processes = 5
​
socket = myapp.sock
chmod-socket = 664
vacuum = true

我们需要一个最终选项,因为我们将创建一个Upstart文件以在启动时启动我们的应用程序。关于SIGTERM信号应该对应用程序做什么,Upstart和uWSGI有不同的想法。为了解决这种差异,以便可以使用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实例,以便我们的应用程序始终可用。我们将它放在Upstart检查的/etc/init目录中。我们会称之为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,但您应该替换您自己的用户)。我们希望将组设置为Nginx使用的www-data用户。这是必要的,因为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),并启动指向我们.ini文件的uWSGI实例:

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服务器的前面,我们设置了一个Nginx反向代理,它可以使用uwsgi有线协议与uWSGI进程通信。

在设置实际生产环境时,您可以轻松了解如何扩展它。例如,uWSGI能够使用称为“emperor模式”的东西管理多个应用程序。您可以扩展Nginx配置以在uWSGI实例之间进行负载平衡,或者为您的应用程序处理静态文件。在为多个应用程序提供服务时,根据您的需要,全局安装uWSGI而不是虚拟环境可能符合您的最佳利益。这些组件都非常灵活,因此您应该能够调整其配置以适应许多不同的场景。

想要了解更多关于设置uWSGI和Nginx以服务Python应用程序的相关教程,请前往腾讯云+社区学习更多知识。


参考文献:《How To Set Up uWSGI and Nginx to Serve Python Apps on Ubuntu 14.04》

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏云计算教程系列

如何使用Prometheus监控CentOS 7服务器

Prometheus是由SoundCloud开发的开源监控系统。与其他监控系统(如InfluxDB和Graphite)一样,Prometheus将其所有数据存储...

9080
来自专栏BestSDK

37个TOP实例命令,超过一半你肯定都没见过

1. Top 命令输出 首先,让我们了解一下输出。top命令会显示系统的很多信息。我们需要理解不同部分输出的意义:默认运行时,top命令会显示如下输出: ? 前...

3276
来自专栏君赏技术博客

我和flow.ci的第一次亲密接触

这不是第一次听说flow.ci,记得当时fir.im新出这个服务的时候,我也是心情十分激动的去尝试,结果是只支持安卓,我可以iOS的程序员呀!

1071
来自专栏十月梦想

node读取html文件

node和Apache是没有web容器的,node的目录下的同级文件是无法使用/filename进行访问的,因为node没有根目录门也没用web容器!

1732
来自专栏Samego开发资源

Linux自定义命令指令 | alias

2107
来自专栏云计算教程系列

如何在CentOS 7上使用InfluxDB分析系统指标

InfluxDB是一个时间序列,指标和分析数据库。时间序列数据库旨在解决存储在一段时间内进行的连续测量所产生的数据的问题。此数据可能包含系统指标(如CPU和内存...

1771
来自专栏小程序之家

如何在小程序中实现文件上传下载

在如何实现小程序登录鉴权这篇文章中,我们实现了小程序的wx.request请求操作,除了request之外,小程序还有文件下载wx.downloadFile和文...

13.4K7
来自专栏云计算教程系列

CentOS 7如何设置uWSGI和Nginx提供Python应用服务

在本指南中,我们将设置一个由uWSGI提供服务的简单WSGI应用程序。我们将使用Nginx Web服务器作为应用程序服务器的反向代理,以提供强大的连接处理。我们...

2164
来自专栏ml

JavaScript基础知识(1)

表单的确认 :       客户端确认         --减少服务器负载         --缩短用户等待时间         --兼容性难       服务...

2853
来自专栏老马寒门IT

08Vue.js快速入门-Vue综合实战项目

8.1. 前置知识学习 npm 学习 官方文档 推荐资料 npm入门 npm介绍 需要了解的知识点 package.json 文件相关配置选项 ...

4307

扫码关注云+社区

领取腾讯云代金券