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

介绍

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

定义和概念

澄清一些术语

在我们跳进之前,我们应该解决一些与我们正在处理的相互关联概念相关的混淆术语,这些三个单独的术语看起来是可互换的,但实际上有不同的含义:

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 服务器代理它们。

安装组件

要开始,我们需要在我们的CentOS 7服务器上安装必要的组件,我们主要可以使用yumpip来做到这一点。

首先,我们需要安装EPEL存储库,以便我们可以访问更广泛的包,我们可以通过键入一个单一的yum命令轻松做到这一点:

1sudo yum install epel-release

现在,我们可以安装我们的组件,我们需要获得Python开发库和标题,Python包管理器pip,以及NginxWeb服务器和反向代理。

1sudo yum install python-pip python-devel nginx gcc

一旦包安装完成,您将可以访问pipPython包管理器,我们可以使用它来安装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 文件中看到我们通过的第一级标题文本:

wsgi application example

停止服务器使用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插槽。

我们将指定我们自己的用户名来运行uwsgi服务器并拥有接口文件. 我们将创建一个目录在/run下,以便将接口文件放置到 uWSGI 和 Nginx 都可以访问它。我们将将接口本身称为myapp.sock。我们将更改权限为664以便 Nginx 可以写入它(我们将开始 uWSGI 与 Nginx 使用的www-data组。我们还将添加真空选项,在过程停止时将接口移除:

 1[uwsgi]
 2module = wsgi:application
 3
 4master = true
 5processes = 5
 6
 7uid = user
 8socket = /run/uwsgi/myapp.sock
 9chown-socket = user:nginx
10chmod-socket = 660
11vacuum = true

我们需要一个最后的选项,因为我们将创建一个 systemd 文件,以便在启动时启动我们的应用程序。Systemd 和 uWSGI 对 SIGTERM 信号应该对应用程序做什么有不同的想法。

 1[uwsgi]
 2module = wsgi:application
 3
 4master = true
 5processes = 5
 6
 7uid = user
 8socket = /run/uwsgi/myapp.sock
 9chown-socket = user:nginx
10chmod-socket = 660
11vacuum = true
12
13die-on-term = true

完成后保存并关闭文件. 此配置文件现在已设置为与 Upstart 脚本一起使用。

创建一个 Systemd Unit 文件来管理应用程序

我们可以在启动时启动一个 uWSGI 实例,以便我们的应用程序始终可用。 为了做到这一点,我们可以创建一个 systemd 单元文件。 我们会将此置于 /etc/systemd/system 目录中,这是用户创建单元文件的最佳位置。

1sudo nano /etc/systemd/system/uwsgi.service

首先,我们从[单位]部分开始,在那里我们可以加快我们的元数据。

1[Unit]
2Description=uWSGI instance to serve myapp

接下来,我们将打开[服务]部分,因为我们正在使用虚拟环境,我们的服务启动命令将比传统上更复杂。我们将使用一个ExecStartPre命令,以确保我们的插件目录被创建并由正确的各方拥有。

对于实际的ExecStart命令,该命令将启动 uWSGI,我们还将实际的命令传输到bash。这使我们能够执行几个不同的命令,因为只有一个命令(在这种情况下bash)可以由这个指令运行。

1[Unit]
2Description=uWSGI instance to serve myapp
3
4[Service]
5ExecStartPre=-/usr/bin/bash -c 'mkdir -p /run/uwsgi; chown user:nginx /run/uwsgi'
6ExecStart=/usr/bin/bash -c 'cd /home/user/myapp; source myappenv/bin/activate; uwsgi --ini myapp.ini'

现在,只剩下要做的是制定[安装]部分,这将决定当我们启用设备时会发生什么。 基本上,它指定了该设备应该自动启动的状态。

1[Unit]
2Description=uWSGI instance to serve myapp
3
4[Service]
5ExecStartPre=-/usr/bin/bash -c 'mkdir -p /run/uwsgi; chown user:nginx /run/uwsgi'
6ExecStart=/usr/bin/bash -c 'cd /home/user/myapp; source myappenv/bin/activate; uwsgi --ini myapp.ini'
7
8[Install]
9WantedBy=multi-user.target

一旦你有上面的配置写出来,保存和关闭文件。

现在,我们可以通过键入开始服务:

1sudo systemctl start uwsgi

通过键入检查它是否开始没有问题:

1systemctl status uwsgi

如果没有错误,请启用该服务,以便在启动时通过键入:

1sudo systemctl enable uwsgi

您可以随时停止服务,键入:

1sudo systemctl stop uwsgi

配置 Nginx 到 proxy 到 uWSGI

此时,我们有一个 WSGI 应用程序,并验证了 uWSGI 能够读取和服务它. 我们创建了配置文件和 Systemd 单元文件. 我们的 uWSGI 流程将通过插槽收听并使用uwsgi协议进行通信。

现在我们可以将 Nginx 配置为反向代理程序, Nginx 可以使用 uwsgi 协议来与 uWSGI 进行通信,这是比 HTTP 更快的协议,而且性能会更好。

我们将设置的 Nginx 配置非常简单. 我们将修改现有 nginx.conf 文件并添加一个新的服务器块。

1sudo nano /etc/nginx/nginx.conf

在默认服务器封锁之前,我们将添加自己的服务器封锁:

 1http {
 2
 3    . . .
 4
 5    include /etc/nginx/conf.d/*.conf;
 6
 7    server {
 8    }
 9
10    server {
11        listen 80 default_server;
12        server_name localhost;
13
14        . . .

我们创建的区块将保留我们uWSGI代理的配置。下面的其他配置项目都放置在这个区块中。服务器区块应该听到端口80并响应您的服务器的域名或IP地址:

1server {
2    listen 80;
3    server_name server_domain_or_IP;
4}

之后,我们可以打开一个单一的位置块,以处理所有请求. 在这个块中,我们将包含在 /etc/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:/run/uwsgi/myapp.sock;
8    }
9}

这实际上是简单的应用程序所需的一切。对于一个更完整的应用程序,可以做一些改进,例如,我们可能在这个块之外定义了一些上游的uWSGI服务器,然后将其传递给它。

我们不需要我们三行应用中的任何这些功能,所以我们可以保存和关闭文件。

您可以通过输入测试确保您的 Nginx 配置有效:

1sudo nginx -t

如果返回没有任何错误,请通过键入开始服务:

1sudo systemctl start nginx

在启动时启动 Nginx 服务:

1sudo systemctl enable nginx

您应该能够访问您的服务器的域名或IP地址(没有端口号码),并查看您配置的应用程序:

full WSGI app

结论

如果你已经做到了,你已经创建了一个简单的WSGI应用程序,并有一些洞察力如何更复杂的应用程序需要设计。我们已经安装了uWSGI应用程序容器/服务器到一个专门的虚拟环境来服务我们的应用程序。我们已经创建了一个配置文件和一个Systemd单元文件来自动化这个过程。

例如,uWSGI 具有使用所谓的温度模式来管理多个应用程序的能力。您可以扩展 Nginx 配置,以便在 uWSGI 实例之间进行负载平衡,或者为您的应用程序处理静态文件。 服务多个应用程序时,您可能最感兴趣的是在全球范围内安装 uWSGI 而不是在虚拟环境中,取决于您的需求。 所有组件都相当灵活,因此您应该能够调整其配置以适应许多不同的场景。

Published At
Categories with 技术
comments powered by Disqus