domingo, 13 de novembro de 2011

Deploy de aplicações Rails e Django no Heroku

No post anterior foi mostrada a importância de se colocar o projeto num servidor de controle de versões, mesmo logo após a sua criação. Algumas preocupações puderam ser rapidamente testadas e solucionadas, por exemplo o setup em máquinas de outros desenvolvedores.

Ainda nesta fase tão precoce, podemos ir mais além: testar o deploy da aplicação num ambiente production-like. Desta forma, cria-se uma cultura de, em cada iteração, testar de ponta-a-ponta o processo de desenvolvimento.

Um dos objetivos é antecipar questões e riscos que tradicionalmente só seriam atacados ao final do projeto. Caso surjam problemas de integração, ou dificuldades técnicas que possam colocar em risco a subida do sistema para produção, as causas podem ser prontamente diagnosticadas e tratadas o mais cedo possível antes que possam comprometer o sucesso do projeto.

Setup do Heroku

O Heroku é uma opção muito popular para o deploy de aplicações Rails, que consiste simplesmente em executar:

git push heroku master

ou seja, pushando o projeto para um repositório Git remoto no Heroku.

A preparação é semelhante a da criação de uma conta no Github. É necessário criar uma conta no Heroku, e fazer o upload de uma chave pública para administração da conta via terminal.

Instalação

O primeiro passo é instalar a gem do heroku:

gem install heroku

Chave pública

Em seguida, fazer o upload da chave pública:

Caso o heroku não encontre uma chave pública em ~/.ssh/id_rsa.pub, e também não exista a chave privada ~/.ssh/id_rsa correspondente, o próprio heroku é capaz de gerar estas chaves para nós (como mostrado no trecho acima).

Podemos também aproveitar a chave pública do github, bastando que ela esteja presente em ~/.ssh/id_rsa.pub para ser upada para o heroku.

Caso mais de uma chave esteja presente no diretório .ssh, o heroku pergunta qual deve ser usada:

Criação da aplicação no Heroku

Resolvida a questão das chaves, podemos criar a aplicação no heroku: Este comando cria um ambiente no Heroku e o adiciona automaticamente como um repositório Git remoto do projeto, o que pode ser confirmado: Note também que, após deployada, a aplicação responderá inicialmente no endereço http://afternoon-robot-3025.heroku.com.

Deploy de uma aplicação Rails no Heroku

Dispensa comentários:

Até mesmo para abrir o navegador, o heroku ajuda:

heroku open

Rackfile e Procfile

O Heroku consegue fazer o deploy de aplicações Rails devido à presença do arquivo config.ru na raiz do projeto. Trata-se de um arquivo Rack, que instrui ao Heroku a forma como a aplicação é iniciada:

Procfile e Foreman

Uma alternativa ao Rack é criar um arquivo Procfile na raiz do projeto. Trata-se de um mecanismo de declarar quais comandos devem ser executados ao deployar na plataforma Heroku. Ele consiste de um conjunto de pares informando o tipo de processo e o comando para executar um determinado processo: Apesar de opcional em aplicações Rails, seu uso é recomendado pois proporciona maior controle e flexibilidade para a aplicação. Além disso, o Heroku provê o comando

heroku scale

para ajustar como escalar a aplicação, baseados no Procfile.

Para executar localmente aplicações baseadas no Procfile, é necessário instalar o Foreman.

gem install foreman

Ao iniciar a aplicação com o foreman, ele inicia cada um dos processos declarados no Procfile:

Django e Heroku

Conforme anunciado neste post, o Heroku também oferece suporte a Python, no stack* Cedar, baseado no Ubuntu 10.04.
* o Heroku oferece diferentes stacks - ambientes completos de deploy, incluindo o sistema operacional e bibliotecas associadas.

Para criar um ambiente no stack cedar, é necessário executar o comando:

heroku create --stack cedar

e o deploy também é feito via git push:

Porém, como se vê acima, o push é rejeitado, informando que o Heroku não consegue detectar nenhuma aplicação Rails/Rack. Alguns ajustes são necessários para conseguir realizar o deploy da aplicação Django no Heroku.

Procfile para rodar aplicações Django no Heroku

Aplicações que NÃO são baseadas no Rack podem ser deployadas no Heroku usando o Procfile. No caso de uma aplicação Django, basta criar um Procfile com o seguinte conteúdo:

web: python manage.py runserver

que a aplicação passa a ser inicializável via foreman:

Agora que está tudo rodando localmente, basta apenas fazer o deploy e correr pro abraço, vai dar até pra sair mais cedo e pegar um cineminha: Oooops... Agora, através do Procfile, o Heroku já é capaz de reconhecer que se trata de uma aplicação Python, porém continua rejeitando o deploy, com uma enigmática mensagem "Django app must be in a subdirectory".

Ainda bem que o Google e o Stack Overflow existem, e alguém já havia postado a solução para este problema: http://stackoverflow.com/questions/7974902/deploying-existing-django-app-on-heroku.

Para deployar a aplicação Django no Heroku, ela precisa estar organizada de tal forma que o Procfile e o requirements.txt fiquem na raiz do repositório, e o projeto Django deve ser um subdiretório a partir da raiz do repositório.

Com esta nova organização, é importante assegurar que o arquivo settings.py esteja com o valor correto para a propriedade ROOT_URLCONF:

ROOT_URLCONF = 'urls'

Ajustada a estrutura do projeto, aí sim, esperamos que o deploy seja bem sucedido.

Basta agora um heroku open e ver se o navegador abre a página e... Ooops. Nada acontece:

A essas alturas, cineminha já era... Neste caso, nem com ajuda de Google e Stack Overflow surgiu alguma pista. Recorrendo ao comando

heroku logs

é possível visualizar o log da subida da aplicação no Heroku, tentando procurar alguma pista sobre o que está faltando: Voilá, nos logs surge a pista: a aplicação crasheou durante a subida, devido à ausência do módulo psycopg2.

Googleando um pouco mais, surge este blog, com instruções simples para instalar localmente este módulo:

  • Pré-requisito:
    sudo apt-get install libpq-dev python-dev
  • Instalação: adicionar ao requirements.txt a linha
    psycopg2==2.4.2
  • Executar
    pip install -r requirements.txt

Após nova subida, é cruzar os dedos e... nada! Eis o novo log:

Ao que o erro indica, o Heroku não faz o binding na porta 8000, e sugere pesquisar a variável de ambiente PORT. Um tanto enigmático. Recorrendo mais uma vez ao Google, eis uma pista melhor, nos comentários deste blog:

"Creating a Procfile and adding: "web: play run --http.port=$PORT $PLAY_OPTS" fixed the problem." (Ivar Abrahamsen)


o que nos conduz a alterar o Procfile para:

web: python manage.py runserver 0.0.0.0:$PORT

E finalmente:

Deploy de aplicação Django no Heroku - Resumo

  1. O projeto Django deve ser um subdiretório a partir da raiz que é comitada no Git
  2. Alterar o settings.py, fazendo
    ROOT_URLCONF = 'url'
  3. Adicionar um Procfile na raiz do projeto contendo:
    web: python manage.py runserver 0.0.0.0:$PORT
  4. Instalar o psycopg2
    1. Para deployar no Heroku é suficiente adicionar ao requirements.txt:
      psycopg2==2.4.2
    2. Para instalar localmente, é necessário:
      1. Instalar pré-requisitos
        sudo apt-get install libpq-dev python-dev
      2. Invocar o PIP pra instalar o pycopg2
        pip install -r requirements.txt
  5. Deploy: git push heroku master

Considerações Finais

As tentativas que envidamos para conseguir subir a aplicação Django no Heroku reforçam a tese da importância de testar o processo de desenvolvimento de ponta-a-ponta. Em cada iteração, é importante incluir o deploy para um ambiente production-like, para identificar dificuldades e riscos iterativamente, à medida que a aplicação é desenvolvida.

Nenhum comentário:

Postar um comentário