如何设置uWSGI和Nginx的对CentOS 7即成Python应用程序

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

介绍

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

定义和概念

澄清一些条款

在我们进入之前,我们应该解决与我们将要处理的相互关联的概念相关的一些混乱的术语。 这三个单独的术语出现可互换,但实际上具有不同的含义:

  • 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服务器。

安装组件

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

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

sudo yum install epel-release

现在,我们可以安装我们的组件。 我们需要让Python开发库和头文件,该pip Python包管理器,Nginx的Web服务器和反向代理。 我们还需要一个编译器来短暂地构建uWSGI二进制:

sudo yum install python-pip python-devel nginx gcc

一旦软件包安装完成后,您将有机会获得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-Typetext/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文件:

wsgi应用程序示例

当您验证此工作原理时,使用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套接字。 这更安全,更快。

我们将指定要运行我们自己的用户名uwsgi服务器和拥有套接字文件。 根据我们将创建一个目录/run放置套接字文件,以便uWSGI和Nginx的都可以访问它。 我们将调用Socket本身myapp.sock 我们将权限更改为“664”,这样的Nginx可以写入(我们将与首发uWSGI www-data是Nginx的使用群体。我们也将添加vacuum选项,这将删除插座时,进程停止:

[uwsgi]
module = wsgi:application

master = true
processes = 5

uid = user
socket = /run/uwsgi/myapp.sock
chown-socket = user:nginx
chmod-socket = 660
vacuum = true

我们需要一个最终选项,因为我们将创建一个systemd文件来启动我们的应用程序。 Systemd和uWSGI对于SIGTERM信号应该对应用程序执行的操作有不同的想法。 理清这种差异,使得进程可以与Systemd预期来处理,我们只需要添加一个名为选项die-on-term这样uWSGI将终止进程,而不是重新加载它:

[uwsgi]
module = wsgi:application

master = true
processes = 5

uid = user
socket = /run/uwsgi/myapp.sock
chown-socket = user:nginx
chmod-socket = 660
vacuum = true

die-on-term = true

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

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

我们可以在启动时启动uWSGI实例,以便我们的应用程序始终可用。 为此,我们可以创建一个systemd单元文件。 我们将在此放置/etc/systemd/system这对于用户创建的单元文件的最佳场所目录。 我们将调用单元文件uwsgi.service

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

首先,我们开始了与[Unit]节,在这里我们可以踱步我们的元数据。 我们唯一要介绍的是我们的服务描述:

[Unit]
Description=uWSGI instance to serve myapp

接下来,我们将打开[Service]部分。 因为我们使用虚拟环境,我们的服务启动命令将比他们传统的更复杂。 我们将使用ExecStartPre命令以确保我们的插座目录中创建和正确的方所有。 这将允许失败(通过把一个-等号之后),他们已经建立的情况下。 这将被传递到一个单一的呼叫bash

对于实际ExecStart命令,它会开始uWSGI,我们也将通过实际的命令bash 这让我们因为只有一个命令(执行几个不同的命令bash在这种情况下)可以通过这个指令运行。 我们将利用这个改变对我们的应用程序目录,激活虚拟环境,并与开始uWSGI .ini我们创建的文件:

[Unit]
Description=uWSGI instance to serve myapp

[Service]
ExecStartPre=-/usr/bin/bash -c 'mkdir -p /run/uwsgi; chown user:nginx /run/uwsgi'
ExecStart=/usr/bin/bash -c 'cd /home/user/myapp; source myappenv/bin/activate; uwsgi --ini myapp.ini'

现在,所有剩下要做的就是制定[Install]部分。 这将决定我们何时会发生什么enable单位。 基本上,它指定单元应该自动启动的哪些状态。 我们要指定启用时,该服务器处于多用户模式时,该单元应该启动:

[Unit]
Description=uWSGI instance to serve myapp

[Service]
ExecStartPre=-/usr/bin/bash -c 'mkdir -p /run/uwsgi; chown user:nginx /run/uwsgi'
ExecStart=/usr/bin/bash -c 'cd /home/user/myapp; source myappenv/bin/activate; uwsgi --ini myapp.ini'

[Install]
WantedBy=multi-user.target

一旦你写出了上面的配置,保存并关闭文件。

现在,我们可以通过键入以下内容启动服务:

sudo systemctl start uwsgi

键入以下内容以检查其是否正常启动:

systemctl status uwsgi

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

sudo systemctl enable uwsgi

您可以随时通过键入以下内容停止服务:

sudo systemctl stop uwsgi

将Nginx配置为代理到uWSGI

在这一点上,我们有一个WSGI应用程序,并已验证uWSGI可以读取和服务它。 我们已经创建了一个配置文件和Systemd单元文件。 我们uWSGI进程将监听套接字,并使用通信uwsgi协议。

现在我们可以开始配置Nginx作为反向代理。 Nginx的具有使用能力的代理uwsgi与uWSGI通信协议。 这是一个比HTTP更快的协议,性能更好。

我们将要设置的Nginx配置是非常简单的。 我们将修改现有nginx.conf文件和添加新的服务器块。 打开该文件sudo编辑:

sudo nano /etc/nginx/nginx.conf

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

http {

    . . .

    include /etc/nginx/conf.d/*.conf;

    server {
    }

    server {
        listen 80 default_server;
        server_name localhost;

        . . .

我们创建的块将保存我们的uWSGI代理的配置。 下面的其余配置项目放置在此块中。 服务器块应侦听端口80,并响应您的服务器的域名或IP地址:

server {
    listen 80;
    server_name server_domain_or_IP;
}

之后,我们可以打开一个位置块来处理所有请求。 在此块中,我们将包括uwsgi信中参数/etc/nginx/uwsgi_params文件,我们将通信传递到uWSGI监听套接字:

server {
    listen 80;
    server_name server_domain_or_IP;

    location / {
        include uwsgi_params;
        uwsgi_pass unix:/run/uwsgi/myapp.sock;
    }
}

这实际上是我们需要一个简单的应用程序。 可以对一个更完整的应用程序做一些改进。 例如,我们可以在该块之外定义一些上游uWSGI服务器,然后将它们传递给它。 我们可能包括一些uWSGI参数。 我们还可以直接处理Nginx的任何静态文件,并只向uWSGI实例传递动态请求。

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

您可以通过键入以下内容进行测试以确保您的Nginx配置有效:

sudo nginx -t

如果返回没有任何错误,请通过键入以下内容启动服务:

sudo systemctl start nginx

启动服务时启动Nginx:

sudo systemctl enable nginx

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

完整的WSGI应用程序

结论

如果你已经做到了这一点,你已经创建了一个简单的WSGI应用程序,并有一些洞察如何更复杂的应用程序将需要设计。 我们已将uWSGI应用程序容器/服务器安装到一个特定的虚拟环境中,以便为我们的应用程序提供服务。 我们已经创建了一个配置文件和一个Systemd单元文件来自动化这个过程。 在uWSGI服务器的前面,我们已经设置了可使用的uWSGI进程的讲话Nginx的反向代理uwsgi线协议。

您可以轻松地了解在设置实际生产环境时如何扩展这一功能。 例如,uWSGI有能力使用称为“皇帝模式”的东西管理多个应用程序。 您可以扩展Nginx配置以在uWSGI实例之间实现负载平衡,或者为应用程序处理静态文件。 当服务多个应用程序时,根据您的需要,在全球安装uWSGI而不是在虚拟环境中安装uWSGI可能符合您的最佳利益。 组件都相当灵活,因此您应该能够调整其配置以适应许多不同的方案。