NGINX Conf 2018:为生产应用配置NGINX Unit——部署Django项目

NGINX | 2018年11月28日

NGINX Unit是一款完全动态的应用服务器,可支持多种语言以及每种语言的多个版本。其动态性体现在:可以使用RESTful JSON API修改内存中的配置,无需中断服务或重新加载配置。

在10月举行的NGINX Conf 2018上,我演示了如何在现有生产环境中配置新应用。具体来说,我在运行基于PHP的WordPress的环境中部署了一个使用Django框架的Python应用。我还演示了如何从文件加载配置,以及如何通过API调用参数指定并加载配置。

本博客包含我在演示中使用的所有命令和配置代码,便于您根据自己的部署进行调整。

先决条件

为了在NGINX Conf上进行演示,我安装了以下软件:

  • Ubuntu 16.04
  • NGINX Plus,但除非另有说明,也可以使用 NGINX Open Source
  • NGINX Unit,已安装所有语言模块
  • Python 3
  • Django(尚未配置,本演示和这篇博客将介绍如何配置)
  • root权限,或通过sudo获得的同等访问权限(我们会在必要时使用)

我还安装了PHP和WordPress作为现有应用。

创建Django项目

  1. 切换到要创建Django项目的目录:
$ cd /var/www/
  1. 使用django-admin startproject命令初始化新项目。我们将其命名为djapp。
$ sudo django-admin startproject djapp
  1. 切换到项目目录:
$ cd djapp
  1. 使用manage.py脚本迁移项目数据库,这是新建项目的必要步骤。Django默认使用SQLite,本演示也采用此默认设置,但您可以使用任何满足项目需求的数据库。manage.py脚本由我们在第2步运行的django-admin命令安装;它执行与django-admin相同的命令并接受相同的参数,但会自动获取并使用一些项目特定的设置,更加方便。有关详细信息,请参阅Django文档。
$ sudo python3 manage.py migrate
  1. 对于此类示例项目,虽然并非必须,但建议创建一个Django 超级用户身份:
$ sudo python3 manage.py createsuperuser
  1. 切换到包含settings.py文件的子目录。该文件由第 2 步中的django-admin startproject命令创建。
$ cd /var/www/djapp/djapp
  1. 使用常用的文本编辑器打开settings.py。此处使用nano:
$ sudo nano settings.py
  1. 找到ALLOWED_HOSTS行,并添加应用程序的域名、主机名或IP地址:
ALLOWED_HOSTS = ['domain-name']
  1. 此外,在文件末尾添加以下行,用于指定存储应用程序所提供的所有静态内容的目录(请参阅步骤 9)。
STATIC_ROOT = '/var/www/djapp/djapp/static'
  1. 切换回主项目目录(即manage.py所在的目录)。
$ cd ..
  1. 运行manage.py collectstatic命令,收集Django项目中的所有静态文件,并将其放入步骤7中定义的STATIC_ROOT位置。
$ sudo python3 manage.py collectstatic

配置NGINX

默认情况下,Django本身负责提供项目的静态内容,但NGINX Open Source和NGINX Plus可提供更出色的性能。此处配置的是NGINX Plus,但除下文所述的一项功能外,也可以使用NGINX Open Source。

  1. 切换到目录/etc/nginx/conf.d,这是存放特定功能(在本例中为特定应用)HTTP配置文件的常用位置:
$ cd /etc/nginx/conf.d
  1. 创建一个名为“django.conf”的文件(这里仍使用nano):
$ sudo nano django.conf
  1. 插入以下配置以启用缓存。该配置还包含两项NGINX Plus专属功能。如果您使用NGINX Plus并希望利用这些功能,请取消相关指令的注释。需要注意的是,在NGINX Conf的演示中,我将本地计算机的IP地址指定为proxy_set_header指令的第二个参数。在生产环境中,更适合使用如下所示的$host变量。
# Upstream group for the backend (NGINX Unit running the Python application)
upstream django_unit {
    zone django_unit 64k;
    server 127.0.0.1:8000;
}
 
server {
    listen 8080;
    # Uncomment to collect metrics if using NGINX Plus and the NGINX Plus API
    #status_zone django;
      	
    # enable caching
    proxy_cache django_cache;
    proxy_cache_valid 200 60m;
 
    # root directory for static files
    root /var/www/djapp/djapp;
 
    # proxy to the NGINX Unit backend
    location / {
        proxy_pass http://django_unit;

        # Second argument must match your production hostname and the value of 
        # ALLOWED_HOSTS in settings.py
        proxy_set_header Host $host; 
 
        # Uncomment to enable active health checks if using NGINX Plus
        #health_check;
    }

    # Location for the static files collected from Django and served by 
    # NGINX Plus; can be empty (as here), because it inherits the value of the 
    # 'root' directive from its parent block
    location /static {
    }
}
  1. 检查配置的语法是否有效:
$ sudo nginx –t
  1. 修复所有错误后,重新加载配置:
$ sudo nginx -s reload

配置 NGINX Unit

最后,我们需要配置NGINX Unit,将请求转发给应用程序。

  1. 运行以下curl命令,显示当前的NGINX Unit配置,该配置用于在PHP上运行的WordPress。此处不显示输出,但在下面的步骤6中会同时显示WordPress配置和即将添加的Python应用配置。请注意,我在sudo命令中使用了curl,但大多数curl命令可能不需要这样做。此处必须使用该命令,因为访问UNIX套接字需要root对其拥有的读写权限。
$ sudo curl --unix-socket /run/control.unit.sock http://localhost/config/
  1. 切换到NGINX Unit配置文件所在的目录。请注意,这些文件并非必需,只是为了方便加载一组配置,无需在调用NGINX Unit API时将所有数据作为参数输入。由于文件内容与所有配置数据一样通过API上传,因此NGINX Unit并不知道文件的位置,也无法在启动时自动读取文件(这与NGINX Open Source和NGINX Plus不同)。NGINX Unit会将其运行时状态保存在单独的目录中。
$ cd /etc/unit
  1. 创建一个名为“django.config”的文件(这里仍使用nano):
$ sudo nano django.config
  1. 添加以下JSON,该JSON表示我们的Python应用程序。
{
      "type": "python",
      "processes": 5,
      "module": "djapp.wsgi",
      "path": "/var/www/djapp"
}
  1. 运行以下curl命令,将django.config中包含的JSON加载为由NGINX Unit管理的新应用程序对象,并将其命名为djapp:
$ sudo curl -X PUT --data-binary @/etc/unit/django.config --unix-socket /run/control.unit.sock http://localhost/config/applications/djapp
  1. 在此命令中:
    • HTTP PUT 方法会在最后一个参数(URL)指定的位置创建新的 NGINX Unit 配置对象。请参阅下方最后一个项目符号。
    • The --data-binary参数指示curl按原样加载django.config的内容,保留换行符和回车符,不进行任何处理。
    • The --unix-socket参数用于定义NGINX Unit API的侦听位置。(由于套接字使用默认所有者sudo,因此我们使用root命令。)
    • 最后一个参数用于定位并命名新的应用程序对象,以便使用以下文件中采用JSON格式的配置数据填充该对象:django.config。其中,config是NGINX Unit的顶层配置对象,applications是应用程序对象的父对象,djapp是新应用程序对象的名称。
  2. 为应用定义监听器对象。与步骤4中加载配置数据文件不同,我们直接在curl命令行中定义数据,并指定djapp应用监听8000端口。
$ sudo curl -X PUT --data-binary '{"application":"djapp"}' --unix-socket /run/control.unit.sock 'http://localhost/config/listeners/*:8000'
  1. 重复执行步骤 1 中的“curl”命令,以显示 NGINX Unit 配置。该配置现在包含我们的 Python 应用程序“djapp”,并以橙色突出显示:
$ sudo curl --unix-socket /run/control.unit.sock http://localhost/config/{
      "listeners": {
            "127.0.0.1:8090": {
                  "application": "script_index_php"
            },
 
            "127.0.0.1:8091": {
                  "application": "direct_php"
            },
 
            "*:8000": { "application": "djapp" }
      },
 
      "applications": {
            "script_index_php": {
                  "type": "php",
                  "processes": {
                        "max": 20,
                        "spare": 5
                   },
 
                  "user": "www-data",
                  "group": "www-data",
                  "root": "/var/www/wordpress",
                  "script": "index.php"
            },
 
            "direct_php": {
                  "type": "php",
                  "processes": {
                        "max": 5,
                        "spare": 0
                  },
 
                  "user": "www-data",
                  "group": "www-data",
                  "root": "/var/www/wordpress",
                  "index": "index.php"
                  },
 
            "djapp": { "type": "python", "processes": 5, "module": "djapp.wsgi", "path": "/var/www/djapp" }
      }
}

总结

本文首先介绍了如何使用NGINX Unit在生产环境中运行WordPress的PHP应用,然后添加了一个Python应用。在演示中,我使用NGINX Plus仪表盘说明添加新应用不会中断现有应用,但也可以使用任何系统监控工具(例如ps命令)来验证这一点。NGINX Unit配置的动态特性可以为正在运行的应用节省资源,并确保新部署实现零停机,以及应用版本之间平稳过渡。

要了解更多信息,请访问unit.nginx.org。


分享
标签: Python, F5 NGINX, Tech

相关博客文章

NGINX Plus R26 正式发布
NGINX | 2022/02/15

NGINX Plus R26 正式发布

NGINX Plus R26通过缓存JSON Web密钥集加快JWT验证,并强化TLS握手,从而提升安全性。NGINX JavaScript的新功能包括增强对异步函数的支持,以及实现WebCrypto API。

使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击
NGINX | 2022/02/10

使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击

gRPC具备开发人员设计和部署现代应用所需的速度与灵活性,但其开放性也使其极易受到第7层DoS攻击。NGINX App Protect DoS可保护gRPC应用免受此类破坏性攻击。

Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划
NGINX | 2021/09/13

Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划

了解选择错误的Ingress控制器可能带来的风险,以及如何从关键方面着手,让您的选择更好地适应未来需求。

NGINX Plus R19 正式发布
NGINX | 2019/09/03

NGINX Plus R19 正式发布

NGINX Plus R19扩展了监控功能,不仅提供更多指标,还新增了指标分析方式;增加试运行模式,用于测试限速效果;增强键值存储,以支持IP地址范围;并使限速更加动态。

NGINX现已正式加入F5
NGINX | 2019/05/09

NGINX现已正式加入F5

NGINX现已正式成为F5的一部分。Gus Robertson现任F5 NGINX业务部门负责人。他阐述了两家公司在人才、文化和愿景方面融合的价值,以及双方将如何携手增强NGINX的开源产品和商业产品。

使用NGINX和NGINX Plus实现高性能缓存
NGINX | 2016/08/24

使用NGINX和NGINX Plus实现高性能缓存

我将介绍NGINX在内容缓存和性能方面的工作原理,并分享一些控制NGINX内容缓存方式的技巧。