Configurando Ambiente de Produção Django com Virtualenvwrapper, Gunicorn e Nginx

Fala pessoal, hoje estou aqui para apresentar uma solução que utilizei esses dias para rodar uma aplicação Django em produção.

Não sou muito experiente no mundo Python, mas sei que o pessoal costuma a usar bastante servidores wsgi para rodar aplicações da linguagem.

Estava acostumado a subir aplicações Django usando FastCGI em servidores compartilhados (por falta de outra opção), mas em meu último serviço pude subir o projeto em meu vps, então optei por algo mais simples que funcionasse bem.

A opção de usar o Nginx com o Gunicorn me pareceu a melhor, dado o fato que já tinha o servidor web instalado e a integração seria bem fácil.

Preparando Ambiente

Assim como a documentação do Gunicorn recomenda, vamos criar um ambiente isolado com virtualenv para que possamos trabalhar com múltiplas versões do Django.

Instale o virtualenv via pip:

$ sudo pip install virtualenv

Eu particularmente gosto de usar o virtualenvwrapper também, pois facilita um pouco mais, instale ele via pip:

$ sudo pip install virtualenvwrapper

Agora carregue o arquivo do virtualenvwrapper com funções para administrar os ambientes:

$ source /usr/local/bin/virtualenvwrapper.sh

Adicione essa mesma linha acima no final do arquivo ~/.bashrc ou ~/.bash_profile para que os comandos sejam carregados junto com o shell.

Vamos criar um ambiente agora:

$ mkvirtualenv django-1.5

Aqui estou criando um ambiente chamado "django-1.5", usaremos ele para trabalhar com projetos dessa versão do Django.

Se você rodar $ ls ~/.virtualenvs verá que um diretório "django-1.5" foi criado, nessa pasta serão armazenadas as bibliotecas do nosso ambiente.

Observe também que no shell teremos o nome do ambiente entre parênteses antes do nome do usuário, desse jeito: (django-1.5)glauco@glauco-note ~$. Isso significa que esse ambiente está ativo, para desativá-lo rode $ deactivate django-1.5 e para ativar, basta rodar $ workon django-1.5.

Nosso ambiente isolado está criado no servidor, agora precisamos fazer deploy do projeto e instalar as dependências (como o Django, South etc..).

Saindo do servidor e indo para nosso ambiente local de desenvolvimento, vamos congelar as dependências do projeto em um arquivo txt:

$ pip freeze > requirements.txt

Faça deploy no servidor de produção usando git ou ferramentas como Fabric, acesse a pasta do arquivo com as dependências do projeto e instale-as via $ pip install -r requirements.txt.

Instalando e Configurando Gunicorn

Instalar o Gunicorn é fácil, basta rodar pip install gunicorn e pronto.

A partir da versão 1.4 do Django, quando criamos um projeto, ele vem com um arquivo chamado wsgi.py que serve para fazer a ligação entre o servidor web (nesse exemplo Nginx) e o servidor de aplicação (nesse exemplo Gunicorn).

Precisamos alterar o arquivo para adicionar o caminho de nossa aplicação ao python path:

# wsgi.py
import os, sys

PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
settings_module = "%s.settings" % PROJECT_ROOT.split(os.sep)[-1]
if PROJECT_ROOT not in sys.path:
    sys.path.append(PROJECT_ROOT)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", settings_module)

from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

Aqui pegamos o caminho absoluto do projeto e verificamos se ele está no python path, senão estiver, adicionamos, depois dizemos ao Django qual a localização do arquivo settings.py.

Vamos rodar nossa aplicação para testar:

$ gunicorn -b "127.0.0.1:8007" meu_projeto.wsgi:application

O código acima deve ser executado no diretório acima do projeto, nesse caso ~/, pois o projeto está em ~/meu_projeto. Troque "meu_projeto" pelo nome do diretório que contém seu projeto.

Se tudo deu certo, você já tem o Gunicorn rodando.

Servindo Arquivos Estáticos com Nginx

Não é recomendado servir arquivos estáticos com o Django, por isso precisamos de um servidor web para fazer o serviço, nesse tutorial iremos usar o Nginx.

Considerando que você já tenha ele instalado, vamos configurar um servidor como abaixo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
server {
  listen   8006;
  passenger_enabled off;
  server_name localhost;
  root /home/superuser/meu_projeto;
  location /static/ {
    alias /home/superuser/meu_projeto/my_template/static/;
    if ($query_string) {
      expires max;
    }
  }
  location / {
    proxy_pass_header Server;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Scheme $scheme;
    proxy_connect_timeout 30;
    proxy_read_timeout 20;
    proxy_pass http://127.0.0.1:8007;
  }
}
A linha 3 serve para dizer ao Nginx que o Passenger deve estar desabilitado nesse servidor, você só irá precisar dela caso tenha o Passenger instalado, se você não tem pode tirá-la.

Aqui definimos um servidor ouvindo na porta 8006, mapeando as urls que começam com /static/ para o caminho de arquivos estáticos de nossa aplicação e que define um proxy reverso que serve para jogar as requisições ao Gunicorn que está escutando na porta 8007 (como foi definido no teste anteriormente).

Ao terminar de configurar o Nginx, reinicie-o e acesse o servidor via ip mesmo (por ex: http://111.222.33.444:8006) e já devemos ter nossa aplicação rodando.

Automatizando Startup do Gunicorn com Upstart

Poderiamos parar por aqui pois já temos o que precisamos, mas imagine só que você precise reinicar o processo do Gunicorn ao fazer um deploy, da forma que está, você precisaria dar um ps aux para localizar o processo e depois matá-lo, isso não é muito legal.

Servidores Ubuntu possuem o Upstart, com ele conseguimos controlar serviços apenas rodando um sudo stop nome_servico e sudo start nome_servico, além da garantia que ele nos dá que o processo sempre estará rodando, é disso que precisamos.

Vamos criar um arquivo chamado start.sh na pasta do projeto que seja responsável por subir nossa aplicação:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
set -e
APP_NAME='meu_projeto'
APP_PATH=/home/superuser
ENV_PATH=$APP_PATH/.virtualenvs/django-1.5
LOGFILE="$APP_PATH/$APP_NAME/log"
NUM_WORKERS=3
# user/group to run as
USER=superuser
#GROUP=your_unix_group
PORT=8007
source $ENV_PATH/bin/activate
cd "$APP_PATH/"
exec gunicorn -w $NUM_WORKERS -b "127.0.0.1:$PORT" --user=$USER --log-level=debug --log-file=$LOGFILE 2>>$LOGFILE "$APP_NAME.wsgi:application"

Dê permissão de execução a ele via $ chmod +x start.sh.

Nesse arquivo defino algumas variáveis para que possamos usar na inicializaçao do servidor. Atente para a linha 12, nela eu ativo o ambiente a ser utilizado, isso é muito importante.

Na linha 7 definimos quantos workers o Gunicorn usará, recomenda-se utilizar a seguinte fórmula para calcular: 1 + 2 * NUMERO DE CORES DO PROCESSADOR.

Com nosso script de inicialização pronto, vamos criar um novo serviço no Upstart para cuidar dele. Acesse a pasta /etc/init e crie um arquivo chamado meu_projeto.conf com o seguinte conteúdo:

description "Meu Projeto Gunicorn"
start on runlevel [2345]
stop on runlevel [016]
respawn

exec su - superuser -c '/home/superuser/meu_projeto/start.sh'

Salve e pronto, agora você pode controlar o Gunicorn via sudo start meu_projeto e sudo stop meu_projeto.

Abraços.

Written on November 23, 2013

Share: