NGINX Conf 2018: Configurando o NGINX Unit para aplicações em produção — disponibilizando um projeto Django

NGINX | 28 de novembro de 2018

NGINX Unit é um servidor de aplicações totalmente dinâmico, capaz de oferecer suporte a várias linguagens e a diversas versões de cada uma delas. Ele é dinâmico porque permite usar a API JSON RESTful para alterar sua configuração na memória, sem interromper o serviço nem recarregar as configurações.

Na minha apresentação na NGINX Conf 2018, em outubro, mostrei como configurar uma nova aplicação em um ambiente de produção existente. Especificamente, com o WordPress em execução no PHP, implantei uma aplicação Python que usa o framework Django. Também mostrei como carregar a configuração tanto de um arquivo quanto conforme especificado por um argumento em uma chamada de API.

Este blog inclui todos os comandos e códigos de configuração que usei na demonstração, para facilitar a adaptação à sua própria implantação.

Pré-requisitos

Para a demonstração na NGINX Conf, eu tinha os seguintes softwares instalados:

  • Ubuntu 16.04
  • NGINX Plus, mas você pode usar o NGINX Open Source, exceto quando indicado
  • NGINX Unit com todos os módulos de linguagem instalados
  • Python 3
  • Django (não configurado – é disso que tratam a demonstração e este blog)
  • root ou acesso equivalente via sudo (que usamos quando necessário)

Eu também tinha o PHP e o WordPress instalados como a aplicação existente.

Criando o projeto Django

  1. Acesse o diretório onde criaremos nosso projeto Django:
$ cd /var/www/
  1. Use o django-admin startproject para inicializar o novo projeto. Vamos chamá-lo de djapp.
$ sudo django-admin startproject djapp
  1. Acesse o diretório do projeto:
$ cd djapp
  1. Use o script manage.py para migrar o banco de dados do projeto, o que é necessário para um projeto recém-criado. O Django usa o SQLite por padrão, e eu mantenho essa configuração na demonstração, mas você pode usar qualquer banco de dados que atenda às necessidades do seu projeto. O script manage.py é instalado pelo comando django-admin que executamos na Etapa 2; ele executa os mesmos comandos e aceita os mesmos argumentos que o django-admin, mas obtém e usa automaticamente algumas configurações específicas do projeto, o que é útil. Para obter detalhes, consulte a documentação do Django.
$ sudo python3 manage.py migrate
  1. Embora não seja estritamente necessário para um projeto de exemplo como este, recomendamos que você crie uma identidade de superusuário do Django:
$ sudo python3 manage.py createsuperuser
  1. Acesse o subdiretório que contém o arquivo settings.py, que foi criado pelo comando django-admin startproject na Etapa 2.
$ cd /var/www/djapp/djapp
  1. Usando seu editor de texto preferido, abra o arquivo settings.py. Neste exemplo, usamos o nano:
$ sudo nano settings.py
  1. Localize a linha ALLOWED_HOSTS e adicione o nome de domínio, nome do host ou endereço IP do aplicativo:
ALLOWED_HOSTS = ['domain-name']
  1. Adicione também a seguinte linha ao final do arquivo para especificar o diretório que armazena todo o conteúdo estático disponibilizado pelo aplicativo (consulte a Etapa 9).
STATIC_ROOT = '/var/www/djapp/djapp/static'
  1. Volte para o diretório principal do projeto (onde o arquivo manage.py está localizado).
$ cd ..
  1. Execute o comando manage.py collectstatic para coletar todos os arquivos estáticos localizados no projeto Django e colocá-los no diretório STATIC_ROOT definido na Etapa 7.
$ sudo python3 manage.py collectstatic

Configurando o NGINX

Por padrão, o próprio Django disponibiliza o conteúdo estático de um projeto, mas o NGINX Open Source e o NGINX Plus oferecem desempenho superior. Aqui, configuramos o NGINX Plus, mas você pode usar o NGINX Open Source, exceto por um recurso mencionado abaixo.

  1. Acesse o diretório /etc/nginx/conf.d, o local convencional para arquivos de configuração HTTP específicos de uma função (ou, no nosso caso, de uma aplicação):
$ cd /etc/nginx/conf.d
  1. Crie um arquivo chamado django.conf (novamente, estamos usando o nano):
$ sudo nano django.conf
  1. Insira a configuração a seguir, que habilita o cache. A configuração também inclui dois recursos exclusivos do NGINX Plus. Remova os comentários das diretivas relevantes se você estiver usando o NGINX Plus e quiser aproveitar esses recursos: vale observar que, na demonstração realizada na NGINX Conf, especifiquei o endereço IP da minha máquina local como o segundo argumento da diretiva proxy_set_header. Em um ambiente de produção, faz mais sentido usar a variável $host, conforme mostrado abaixo.
# 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. Verifique se a configuração é sintaticamente válida:
$ sudo nginx –t
  1. Após corrigir todos os erros, recarregue a configuração:
$ sudo nginx -s reload

Configurando o NGINX Unit

Para finalizar, precisamos configurar o NGINX Unit para encaminhar as solicitações ao aplicativo.

  1. Execute este comando curl para exibir a configuração atual do NGINX Unit, que corresponde ao WordPress em execução no PHP. Não mostro a saída aqui, mas a configuração do WordPress aparece na Etapa 6 abaixo, junto com a configuração do aplicativo Python que estamos prestes a adicionar. Observe que uso sudo no comando curl, o que talvez não seja necessário para a maioria dos comandos curl. Aqui, isso é necessário porque, para acessar o soquete UNIX, precisamos da permissão de leitura e gravação que o usuário root possui sobre ele.
$ sudo curl --unix-socket /run/control.unit.sock http://localhost/config/
  1. Acesse o diretório dos arquivos de configuração do NGINX Unit. Lembre-se de que esses arquivos são opcionais e servem apenas como uma forma prática de carregar conjuntos de configurações sem precisar inserir todos os dados como argumento em uma chamada à API do NGINX Unit. Como o conteúdo dos arquivos é enviado por meio da API (assim como todos os dados de configuração), o NGINX Unit não conhece a localização dos arquivos e não pode lê-los automaticamente ao ser iniciado (ao contrário do NGINX Open Source e do NGINX Plus). Em vez disso, o NGINX Unit salva seu estado de execução em um diretório separado.
$ cd /etc/unit
  1. Crie um arquivo chamado django.config (novamente, estamos usando o nano):
$ sudo nano django.config
  1. Adicione o seguinte JSON, que representa nosso aplicativo Python.
{
      "type": "python",
      "processes": 5,
      "module": "djapp.wsgi",
      "path": "/var/www/djapp"
}
  1. Execute este comando curl para carregar o JSON contido em django.config como um novo objeto de aplicativo a ser gerenciado pelo NGINX Unit, chamado djapp:
$ sudo curl -X PUT --data-binary @/etc/unit/django.config --unix-socket /run/control.unit.sock http://localhost/config/applications/djapp
  1. Neste comando:
    • O método HTTP PUT cria um novo objeto de configuração do NGINX Unit no local indicado pelo argumento final (a URL). Consulte o último item abaixo.
    • O argumento --data-binary instrui o curl a carregar o conteúdo de django.config exatamente como fornecido, preservando quebras de linha e retornos de carro, sem realizar nenhum tipo de processamento.
    • O argumento --unix-socket define onde a API do NGINX Unit está escutando. (Usamos o comando sudo porque estamos usando o proprietário padrão do socket, root.)
    • O argumento final localiza e nomeia o novo objeto de aplicativo que será preenchido com os dados de configuração em formato JSON contidos em django.config: config é o objeto de configuração de nível superior do NGINX Unit, applications é o objeto pai dos objetos de aplicativo, e djapp é o nome do novo objeto de aplicativo.
  2. Defina o objeto listener para a aplicação. Em vez de carregar um arquivo de dados de configuração como na Etapa 4, definimos os dados diretamente na linha de comando do curl, especificando que a aplicação djapp escuta na porta 8000.
$ sudo curl -X PUT --data-binary '{"application":"djapp"}' --unix-socket /run/control.unit.sock 'http://localhost/config/listeners/*:8000'
  1. Repita o comando curl da Etapa 1 para exibir a configuração do NGINX Unit, que agora inclui nosso aplicativo Python, djapp, destacado em laranja:
$ 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" }
      }
}

Resumo

Neste post, começamos com o NGINX Unit executando aplicações PHP para WordPress em produção e adicionamos uma aplicação Python. Na demonstração, uso o painel do NGINX Plus para mostrar que não há interrupção das aplicações existentes quando uma nova aplicação é adicionada, mas você pode usar qualquer ferramenta de monitoramento do sistema, como o comando ps, para essa finalidade. A natureza dinâmica da configuração do NGINX Unit economiza recursos para as aplicações em execução, além de garantir tempo de inatividade zero em novas implantações e uma transição tranquila entre versões das aplicações.

Para saber mais, acesse unit.nginx.org.


Compartilhar

Publicações relacionadas no blog

Como o F5 NGINX One aprimora o gerenciamento e a observabilidade
NGINX | 10/10/2024

Como o F5 NGINX One aprimora o gerenciamento e a observabilidade

Descubra como o F5 NGINX One aprimora o gerenciamento e a observabilidade de ambientes híbridos e multicloud ao oferecer um console web centralizado baseado em SaaS, com insights em tempo real, conformidade automatizada e gerenciamento simplificado de configurações.

Do OpenAPI ao NGINX como gateway de API usando uma API declarativa
NGINX | 17/06/2024

Do OpenAPI ao NGINX como gateway de API usando uma API declarativa

Descubra como transformar uma definição de esquema OpenAPI em uma configuração NGINX totalmente funcional, operando como um API Gateway com a segurança de um Web Application Firewall e um Portal do Desenvolvedor, usando uma abordagem declarativa de API.

Como gerenciar picos repentinos de tráfego e sobrecarga do servidor
NGINX | 14/07/2021

Como gerenciar picos repentinos de tráfego e sobrecarga do servidor

Picos de tráfego e sobrecarga de servidores são preocupações sérias para varejistas online em qualquer época, mas especialmente durante a “Cyber Season” de compras de fim de ano. Detalhamos como você pode aproveitar as soluções de entrega de aplicações de nível de produção da NGINX para se preparar para aumentos repentinos de tráfego.

Distribuição segura de chaves privadas SSL com o NGINX
NGINX | 02/04/2019

Distribuição segura de chaves privadas SSL com o NGINX

Descrevemos três maneiras progressivamente mais seguras de proteger chaves privadas SSL ao configurar o NGINX para processar tráfego HTTPS: permitir acesso de leitura apenas ao usuário root, criptografar as chaves com senhas armazenadas separadamente e distribuir as senhas a partir de um repositório central.

Agrupando solicitações de API em lotes com NGINX Plus e o módulo JavaScript do NGINX
NGINX | 24/05/2018

Agrupando solicitações de API em lotes com NGINX Plus e o módulo JavaScript do NGINX

O módulo JavaScript do NGINX lançado com o NGINX Plus R15 oferece suporte a subsolicitações, possibilitando uma classe totalmente nova de casos de uso para o NGINX Plus. Este exemplo completo também usa a API do NGINX Plus e os módulos de chave-valor para converter solicitações de API dos clientes em solicitações separadas para as APIs dos microsserviços que compõem um aplicativo.

Como superar o esgotamento de portas efêmeras no NGINX e no NGINX Plus
NGINX | 19/04/2016

Como superar o esgotamento de portas efêmeras no NGINX e no NGINX Plus

Confira dicas para evitar o esgotamento de portas efêmeras com ajustes no kernel do Linux, conexões keepalive e conexões vinculadas dinamicamente a endereços IP locais.