如何在Nginx后面使用GunicornHTTP服务器部署PythonWSGI应用程序
介绍
也许是 Python Web 服务器比较 上的文章诱使您切换,或者您已经超出了当前应用程序部署堆栈的规模。 您有兴趣了解有关 Gunicorn Web Server 的更多信息,并希望了解如何从一开始就彻底部署 Python 应用程序。
在这篇 DigitalOcean 文章中,我们的目标是帮助您解决上述所有问题,然后是一些。 我们将从扩展我们对优秀 Gunicorn WSGI HTTP 服务器的知识开始,并继续部署基于各种流行框架构建的 Python WSGI Web 应用程序。
词汇表
1. 关于 Gunicorn 和 Nginx
- 独角兽
- 使用 Nginx 部署 Web 应用程序
2. 为生产准备 Droplet
- 更新默认操作系统
- 设置 Python、pip 和 virtualenv
- 创建虚拟 (Python) 环境
- 下载和安装 Gunicorn
- 下载和安装 Nginx
3. 使用 Gunicorn 为 Python Web 应用程序提供服务
- WSGI
- WSGI 应用程序对象(可调用):wsgi.py
- 运行服务器
- 配置和优化 Gunicorn
- 配置 Nginx
- 其他提示和建议
关于 Gunicorn 和 Nginx
独角兽
Gunicorn 是一个独立的 WSGI Web 应用服务器,它提供了很多功能。 它通过其适配器本机支持各种框架,使其成为开发期间使用的许多开发服务器的非常易于使用的替代品。
从技术上讲,Gunicorn 的工作方式与成功的用于 Ruby 应用程序的 Unicorn Web 服务器非常相似。 他们都使用所谓的前叉模型。 从本质上讲,这让中央 [Gunicorn] 主进程负责处理工作人员的管理、套接字和绑定的创建等。
Gunicorn 服务器亮点
- 运行任何 WSGI Python Web 应用程序(和框架)
- 可用作 Paster (Pyramid)、Django 的开发服务器、web2py 等的替代品。
- 配备各种工人类型和配置
- 自动管理工作进程
- 通过同步和异步工作器支持 HTTP/1.0 和 HTTP/1.1 (Keep-Alive)
- 支持 SSL
- 可通过钩子扩展
- Python 2.6+ 和 3.x 支持
使用 Nginx 部署 Web 应用程序
Nginx 是一个非常高性能的 Web 服务器/(反向)代理。 由于重量轻、相对容易使用和易于扩展(使用附加组件/插件),它已达到目前的流行程度。 由于其架构,它能够处理 很多 的请求(几乎无限制),这取决于您的应用程序或网站负载 - 使用其他一些较旧的替代方案可能真的很难解决。
记住:“处理”连接在技术上意味着不丢弃它们,并且能够使用 something 为它们服务。 您仍然需要您的应用程序和数据库运行良好,以便让 Nginx 为客户端提供不是错误消息的响应。
为什么在应用服务器前使用 Nginx 作为反向代理?
许多框架和应用服务器(包括 Gunicorn)可以提供静态文件(例如 javascript、css、图像等)以及响应。 但是,更好的做法是让(反向代理)服务器(例如 Nginx)处理提供这些文件和管理连接(请求)的任务。 这减轻了应用程序服务器的大量负载,为您提供了更好的整体性能。
随着应用程序的增长,您将希望对其进行优化——时机成熟时,将其分布在服务器 (VPS) 上,以便能够同时处理更多连接(并拥有通常更健壮的架构)。 在您的应用程序服务器前面有一个反向代理可以从一开始就帮助您解决这个问题。
Nginx 的可扩展性(例如 本机缓存以及故障转移和其他机制)也是一项伟大的壮举,与(更简单的)应用程序服务器不同,它有利于 Web 应用程序。
基本服务器架构示例:
Client Request ----> Nginx (Reverse-Proxy) | /|\ | | `-> App. Server I. 127.0.0.1:8081 | `--> App. Server II. 127.0.0.1:8082 `----> App. Server III. 127.0.0.1:8083
注意:请参阅配置和优化Gunicorn部分了解要使用的服务器/工作人员的数量。
为生产准备 Droplet
在本节中,我们将为生产准备我们的虚拟机(即 用于部署我们的应用程序)。
我们将从:
- 更新默认操作系统
- 下载和安装常用的 Python 工具(即 点,虚拟环境)
- 创建一个包含应用程序的虚拟环境(其依赖项如 Gunicorn 驻留在其中)
注意: 此处给出的说明保持简短。 要了解更多信息,请查看我们关于 pip 和 virtualenv 的操作指南文章:常用 Python 工具:使用 virtualenv、使用 Pip 安装和管理包。
更新默认操作系统
注意: 我们将使用最新版本的操作系统在新的 Droplet 上执行以下设置和准备工作。 从理论上讲,在您的 VPS 上尝试它们应该不会有问题。 但是,如果您已经在积极使用它,我们强烈建议您切换到新系统。
为确保我们拥有最新可用版本的默认应用程序,我们需要更新我们的系统。
对于基于 Debian 的系统(即 Ubuntu、Debian),运行以下命令:
aptitude update aptitude -y upgrade
对于基于 RHEL 的系统(即 CentOS),运行以下命令:
yum -y update
设置 Python、pip 和 virtualenv
CentOS / RHEL 用户注意事项:
CentOS / RHEL,默认情况下,作为一个非常精简的服务器。 它的工具集很可能已经过时以满足您的需求, 不是 用于运行您的应用程序,而是为服务器的系统工具(例如 百胜)。
为了准备你的 CentOS 系统,需要设置 Python(即 从源代码编译)和 pip / virtualenv 需要使用该解释器进行安装。
要了解 如何在 CentOS 6.4 和 5.8 上使用 pip 和 virtualenv 设置 Python 2.7.6 和 3.3.3,请参阅:如何设置 Python 2.7.6 和 3.3。 3 在 CentOS 上。
在 Ubuntu 和 Debian 上,默认提供最新版本的 Python 解释器,您可以使用它。 它使我们只需要安装有限数量的附加软件包:
- python-dev(开发工具),
- pip(管理包),
- virtualenv(创建隔离的虚拟环境)。
蟒蛇开发:
python-dev 是一个操作系统级别的包,其中包含用于构建 Python 模块的扩展开发工具。
运行以下命令以使用 aptitude 安装 python-dev:
aptitude install python-dev
点:
pip 是一个包管理器,它将帮助我们安装我们需要的应用程序包。
运行以下命令安装 pip:
curl https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py | python - curl https://raw.github.com/pypa/pip/master/contrib/get-pip.py | python - export PATH="/usr/local/bin:$PATH"
您可能需要 sudo 权限。
虚拟环境:
最好在自己的环境中包含 Python 应用程序及其所有依赖项。 可以将环境最好(简单地说)描述为所有内容所在的隔离位置(目录)。 为此,使用了一个名为 virtualenv 的工具。
运行以下命令以使用 pip 安装 virtualenv:
sudo pip install virtualenv
创建自包含的虚拟 (Python) 环境
准备好所有必要的工具后,我们可以创建一个环境来部署我们的应用程序。
记住: 如果您的项目的开发(本地)机器上没有 virtualenv,您应该考虑创建一个并将您的应用程序(及其依赖项)移动到其中。
让我们从创建一个包含虚拟环境和应用程序模块的文件夹开始:
您可以在此处使用任何名称以满足您的需要。
mkdir my_app
我们可以继续进入这个文件夹并在里面创建一个新的虚拟环境:
您还可以为您的虚拟环境选择任何您喜欢的名称。
cd my_app virtualenv my_app_venv
让我们在那里创建一个新文件夹来包含您的 Python 应用程序模块:
这是您的应用程序模块所在的文件夹。
mkdir app
并激活虚拟环境中的解释器以使用它:
如果您选择“my_app_venv”以外的名称,请确保使用您为虚拟环境选择的名称。
source my_app_venv/bin/activate
最后,您的主应用程序部署目录应如下所示:
my_app # Main Folder to Contain Everything Together | |=== my_app_venv # V. Env. folder with the Python Int. |=== app # Your application module |.. |.
下载和安装 Gunicorn
将所有与应用程序相关的元素尽可能多地包含在虚拟环境中始终是推荐的方式。 因此,我们将在那里下载并安装 Gunicorn。
如果您不在环境中工作,Gunicorn 将被全局安装(即 全系统可用)。 这是 不 推荐。 始终选择使用 virtualenv。
要使用 pip 安装 Gunicorn,请运行以下命令:
pip install gunicorn
下载和安装 Nginx
CentOS / RHEL 用户注意事项:
以下说明不适用于 CentOS 系统。 请在此处 参阅 CentOS 的说明 。
运行以下命令以使用默认系统包管理器 aptitude 安装 Nginx:
sudo aptitude install nginx
要运行 Nginx,您可以使用以下命令:
sudo service nginx start
要停止 Nginx,您可以使用以下命令:
sudo service nginx stop
要重启 Nginx,可以使用以下命令:
每次重新配置 Nginx 后,都需要重新启动或重新加载才能使新设置生效。
sudo service nginx restart
注意:想了解更多关于Ubuntu上的Nginx,请参考我们的文章:如何在Ubuntu 12.04上安装Nginx。
使用 Gunicorn 为 Python Web 应用程序提供服务
在本节中,我们将了解 WSGI 应用程序如何与 Gunicorn 一起工作。 这个过程包括为服务器提供一个 WSGI 应用程序 callable(例如 application = (..)
) 作为入口点。
WSGI
简而言之,WSGI 是 Web 服务器和应用程序本身之间的接口。 它的存在是为了确保各种服务器和应用程序(框架)之间以标准化的方式相互工作,在必要时允许互换性(例如 从开发环境切换到生产环境),这是当今的必备需求。
注意:如果您有兴趣了解更多关于WSGI和Python Web服务器的知识,请查看我们的文章:基于Python的Web服务器比较网络应用程序。
WSGI 应用程序对象(可调用):wsgi.py
如上所述,在 WSGI 上运行的 Web 服务器需要一个应用程序对象(即 您的应用程序的)。
对于大多数框架和应用程序,这包括:
- 一个 wsgi.py 包含并提供一个应用程序对象(或可调用对象)以供服务器使用。
我们将从创建一个示例性的 wsgi.py 与 Gunicorn 一起使用开始。
您可以选择任何名称而不是“wsgi.py”。 但是,这些是常用的(例如 由姜戈)。
让我们开始创建一个 wsgi.py 文件来包含一个基本的 WSGI 应用程序。
运行以下命令以使用文本编辑器 nano 创建 wsgi.py:
nano wsgi.py
让我们继续移动(复制/粘贴)内部的基本 WSGI 应用程序代码(应该替换为您自己的应用程序的生产可调用代码):
def application(env, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return ["Hello!"]
这是服务器包含的文件,每次请求到来时,服务器使用此应用程序可调用来运行应用程序的请求处理程序(例如 控制器)在解析 URL(例如 mysite.tld/控制器/方法/变量)。
放入应用程序代码后,按 CTRL+X,然后按 Y 确认,将此文件保存在虚拟环境和包含实际应用程序的应用程序模块旁边的“my_app”文件夹中。
注意: 这个 WSGI 应用程序是同类中最基本的示例。 您将需要替换此代码块以包含应用程序模块中您自己的应用程序对象。
完成后,您的主应用程序部署目录应如下所示:
my_app # Main Folder to Contain Everything Together | |=== my_app_venv # V. Env. folder with the Python Int. |=== app # Your application module | |--- wsgi.py # File containing application callable |.. |.
运行服务器
要开始为您的应用程序提供服务,您只需执行:
gunicorn [option] [option] .. [wsgi file]
运行以下命令启动服务器:
gunicorn -b 0.0.0.0:8080 wsgi
这将在前台运行服务器。 如果要停止它,请按 CTRL+C。
要在后台运行服务器,请运行以下命令:
gunicorn -b 0.0.0.0:8080 wsgi &
当您在后台运行应用程序时,您将需要使用进程管理器(例如 htop) 杀死(或停止)它。
配置和优化 Gunicorn
注意: 下面是一些最常用的配置和优化设置。 要查看所有可用选项,请查看 Gunicorn 配置概述 的官方文档。
如前所述,Gunicorn 是高度可配置的,并且很容易修改所有必要的参数以按照自己的方式进行操作。
[!] 重要提示: 下面列出的所有设置和配置选项都将被链接(一个接一个)以启动 gunicorn 并为您的应用程序提供服务。 启动服务器后,您无法修改任何选项。 无论您使用哪个或多个选项,它们后面都必须跟着包含应用程序入口点的 wsgi 文件。
例子:
# Simply running the server (as shown above): gunicorn -b 0.0.0.0:8080 wsgi # Running the server with five workers: gunicorn -b 0.0.0.0:8080 --workers=5 wsgi
工人数
通常,人们认为(并接受)应用程序受 I/O 限制而不是 CPU 限制。 这意味着,瓶颈不是由虚拟服务器的处理能力引起的,而是由磁盘引起的。 这个想法是:当一个工作人员忙于磁盘操作时,另一个工作人员仍然利用 CPU 处理请求。
因此,建议的工人数量通常使用以下简单公式来设置:
# (2 Workers * CPU Cores) + 1 # --------------------------- # For 1 core -> (2*1)+1 = 3 # For 2 cores -> (2*2)+1 = 5 # For 4 cores -> (2*4)+1 = 9
您可以通过传递参数 --workers=[n]
来指定工人的数量。
用法:
# Example: gunicorn --workers=[number of workers] gunicorn --workers=5
注意: 上述场景并不严格适用于非阻塞工作者。
套接字设置
套接字绑定的工作方式如下:
# Example: gunicorn -b [address:port] gunicorn -b 127.0.0.1:8080
注意: 当应用程序设置为侦听
127.0.0.1
上的传入连接时,只能在本地访问它。 但是,如果您使用0.0.0.0
,它也将接受来自 外部 的连接。
选择工作人员类型
正如我们所讨论的,Gunicorn 提供了与各种类型的工人一起工作的可能性。
对于大多数部署,标准工作器类型 - 同步 - 就足够了,并且默认提供,因此不需要任何显式设置。
对于其他工作人员,请注意您需要将它们安装为依赖项。
用法:
# Example: gunicorn -k [worker] gunicorn -k sync # or; gunicorn -k gevent # ..
可用类型:
- 同步
- 小事件
- 事件
- 龙卷风
Eventlet/Gevent 的同时连接数
要修改 Eventlet 和 Gevent 工作人员的同时连接数:
# Example: gunicorn -k [worker] --worker-connections [number] gunicorn -k gevent --worker-connections 1001
访问日志
如果您想明确设置文件以写入访问日志:
# Example: gunicorn --access-logfile [file] gunicorn --access-logfile acclogs
默认情况下,此选项设置为 None。
错误日志
要指定要写入错误日志的文件,请使用此设置。
# Example: gunicorn --log-file [file] gunicorn --log-file error_logs.log
日志级别
这用于设置错误日志输出的粒度。 可能的选项是:
- 调试
- 信息
- 警告
- 错误
- 危急
用法:
# Example: gunicorn --log-level [level] gunicorn --log-level error
进程命名
如果您使用 top 等实用程序来监视您的进程,则可以使用此设置为它们指定一个更有意义的名称,这将有助于您完成任务。
# Example: gunicorn --name [name] gunicorn --name my_application
配置 Nginx
在学习了如何配置和运行 Gunicorn 之后,我们现在需要对 Nginx 做同样的事情来与运行应用程序的 Gunicorn 服务器通信。 为此,我们需要修改 Nginx 的配置文件:nginx.conf
运行以下命令打开“nginx.conf”并使用 nano 文本编辑器对其进行编辑:
sudo nano /etc/nginx/nginx.conf
之后,您可以将文件替换为以下示例配置,以使 Nginx 作为反向代理工作,与您的应用程序对话。
注意:要了解加入SSL支持,请先阅读这篇文章:在Nginx上创建SSL证书。
Web 应用程序的示例配置:
worker_processes 1; events { worker_connections 1024; } http { sendfile on; gzip on; gzip_http_version 1.0; gzip_proxied any; gzip_min_length 500; gzip_disable "MSIE [1-6]\."; gzip_types text/plain text/xml text/css text/comma-separated-values text/javascript application/x-javascript application/atom+xml; # Configuration containing list of application servers upstream app_servers { server 127.0.0.1:8080; # server 127.0.0.1:8081; # .. # . } # Configuration for Nginx server { # Running port listen 80; # Settings to serve static files location ^~ /static/ { # Example: # root /full/path/to/application/static/file/dir; root /app/static/; } # Serve a static file (ex. favico) # outside /static directory location = /favico.ico { root /app/favico.ico; } # Proxy connections to the application servers # app_servers location / { proxy_pass http://app_servers; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $server_name; } } }
完成修改配置后,按 CTRL+X 并按 Y 确认保存并退出。 您需要重新启动 Nginx 才能使更改生效。
运行以下命令重启 Nginx:
sudo service nginx stop sudo service nginx start
注意:想了解更多关于Nginx的知识,请参考我们的文章:如何在VPS上配置Nginx Web服务器。
其他提示和建议
防火墙:
保护 SSH:
创建警报:
每天监控和观察服务器访问日志: