Django + Heroku >> Desplegando una aplicación Django en Heroku

django-heroku

En esta artículo vamos a ver como desplegar una aplicación Web realizada en Django en Heroku. Heroku es una plataforma como servicio de computación el anube (PaaS) que nos permite desplegar nuestra aplicación en la nube de manera gratuita. Si quisiéramos escalar nuestra aplicación tendríamos que contratar algunos de los servicios que nos ofrece Heroku,

Instalación

  • Instalar la herramienta Heroku toolbelt (v3.3.0). Esta herramienta consta de tres utilidades básicas:
    • Heroku client: Herramienta CLI para la creación y gestión de aplicaciones en Heroku.
    • Foreman: Utilidad para ejecutar aplicaciones localmente.
    • Git: Sistema de control de versiones que usaremos en nuestras aplicaciones alojadas en Heroku.

    Para su instalación en Debian/Ubuntu usamos el siguiente comando:

    $ wget -qO- https://toolbelt.heroku.com/install-ubuntu.sh | sh
    

    Una vez instalado, tendremos acceso al comando heroku desde nuestro terminal:

    $ heroku version
    heroku-toolbelt/3.3.0 (x86_64-linux) ruby/1.9.3 
    

    Para instalar Heroku toolbelt en otro sistema operativo puedes echar un vistazo aquí.

  • Obviamente, deberemos tener instalado Python y virtualenv en nuestro sistema operativo.
  • PostgreSQL instalado para poder testear localmente, ya que Heroku usa este motor de base de datos.
  • Una cuenta de usuario en Heroku que puedes conseguir de manera gratuita aquí.

Creando nuestra aplicación Django en nuestro virtualenv

A continuación, vamos a crear nuestra aplicación Django. Primero creamos una directorio vacío donde crearemos nuestra aplicación:

$ mkdir django-heroku && cd django-heroku 

A continuación creamos un entorno virtual usando virtualenv (v1.7):

$ virtualenv venv --distribute 
New python executable in venv/bin/python 
Installing distribute.............................................................................................................................................................................................done. 
Installing pip...............done.

Una vez creado nuestro entorno virtual lo activamos:

$ source venv/bin/activate

Veremos que el prompt de nuestro terminal cambiará indicándonos en que virtualenv estamos trabajando.

El siguiente paso es instalar las dependencias que necesitamos con pip. Para ello instalaremos el paquete django-toolbelt que incluye todos los paquetes que necesitamos:

  • Django
  • Gunicorn (Green Unicorn): Servidor WSGI implementado en Python compatible con Django.
  • dj-database-url: Utilidad de ayuda para configurar bases de datos en Django.
  • dj-static: Servidor de ficheros estáticos para Django.

Desde nuestro entorno virtual ejecutamos el siguiente comando:

$ pip install django-toolbelt
Installing collected packages: Django, psycopg2, gunicorn, dj-database-url, dj-static, static
  ...
Successfully installed Django psycopg2 gunicorn dj-database-url dj-static static
Cleaning up...

Una vez tenemos preparado nuestro entorno de trabajo, creamos nuestra aplicación Django:

$ django-admin.py startproject hellodjango . 

Definiendo nuestro Procfile

Vamos a hacer uso de un fichero Procfile. Este fichero debemos estar definido en nuestro directorio raíz y es donde declaramos los comandos que deberían ser ejecutados al arrancar nuestra aplicación. Para que nuestro aplicación se ejecute debemos de definir nuestros dynos. Un dyno no es más que un contenedor que ejecuta el comando que le especificamos.

Para que nuestra aplicación se ejecute lo primero que deberemos hacer es arrancar Gunicorn. Para ello creamos el fichero Procfile y añadimos lo siguiente:

Procfile

web: gunicorn hellodjango.wsgi 

Ahora podremos ejecutar nuestra aplicación localmente usando Foreman, el cual hemos instalado anteriormente:

$ foreman start
2013-04-03 16:11:22 [8469] [INFO] Starting gunicorn 0.17.2
2013-04-03 16:11:22 [8469] [INFO] Listening at: http://127.0.0.1:8000 (8469) 

Ahora abrimos nuestro navegador y nos dirigimos a la ruta donde Foreman está sirviendo nuestra aplicación (http://127.0.0.1:8000).

Definiendo las dependencias con Pip

Heroku reconoce una aplicación Python por la existencia de un fichero requirements.txt en el directorio raíz del repositorio. En este fichero se especifican los módulos Python adicionales que nuestra aplicación necesita. Para el correcto despliegue de nuestra aplicación tendremos que tener definidos los siguientes módulos:

requirements.txt

Django==1.6.2
dj-database-url==0.2.2
dj-static==0.0.5
gunicorn==18.0
psycopg2==2.5.2
static==1.0.2
wsgiref==0.1.2

Configurando la aplicación Django

El siguiente paso es configurar nuestra aplicación Django empezando por la configuración de la base de datos Postgres que usamos en Heroku. Como vimos en el apartado anterior, tenemos instalado un módulo llamado dj-database-url, este módulo parsea la variable de entorno DATABASE_URL en código que entiende nuestra aplicación Django. Estando seguros que el módulo dj-database-url está definido en nuestro fichero requirements.txt añadimos lo siguiente a nuestro fichero settings.py:

settings.py

# Parse database configuration from $DATABASE_URL
import dj_database_url
DATABASES['default'] =  dj_database_url.config()

# Honor the 'X-Forwarded-Proto' header for request.is_secure()
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

# Allow all host headers
ALLOWED_HOSTS = ['*']

# Static asset configuration
import os
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
STATIC_ROOT = 'staticfiles'
STATIC_URL = '/static/'

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)

A continuación modificamos el fichero wsgi.py añadiendo el siguiente código:

wsgi.py

from django.core.wsgi import get_wsgi_application
from dj_static import Cling

application = Cling(get_wsgi_application())

Con estos simples pasos ya tendremos configurada nuestra aplicación para ser desplegada en Heroku.

Creando un repositorio Git para la aplicación

El siguiente paso es crear un repositorio en Git donde guardaremos nuestra aplicación. El primer paso para crear nuestro repositorio es definir un fichero oculto .gitignore donde definiremos aquellos ficheros y directorios que queremos que sean ignorados por nuestro repositorio.
GitHub nos proporciona un fantástico fichero .gitignore que podemos usar como base, aunque lo más normal es que conforme avance nuestro proyecto definamos nuevas restricciones. Nos aseguramos que nuestro fichero .gitignore contenga las siguientes restricciones:

.gitignore

venv
*.pyc
staticfiles

A continuación creamos nuestro repositorio y guardamos nuestro cambios:

$ git init 
Initialized empty Git repository in /home/amatellanes/djangoheroku/.git/ 

$ git add . 

$ git commit -m 'initial commit' 
[master (root-commit) da56753] initial commit 
 6 files changed, 128 insertions(+) 
 create mode 100644 Procfile 
 create mode 100644 hellodjango/__init__.py 
 create mode 100644 hellodjango/requirements.txt 
 create mode 100644 hellodjango/settings.py 
 create mode 100644 hellodjango/urls.py 
 create mode 100644 hellodjango/wsgi.py 
 create mode 100644 manage.py 

Desplegando la aplicación en Heroku

El siguiente paso es subir la aplicación que acabamos de crear a un repositorio de Heroku. Para ello usamos el siguiente comando:

$ heroku create 
Creating gentle-gorge-9766... done, stack is cedar 
http://gentle-gorge-9766.herokuapp.com/ | [email protected]:gentle-gorge-9766.git 
Git remote heroku added

Este comando ha creado un repositorio remoto en Heroku ([email protected]:gentle-gorge-9766.git donde subiremos nuestra aplicación usando el siguiente comando:

$ git push heroku master

Initializing repository, done. 
Counting objects: 11, done. 
Delta compression using up to 2 threads. 
Compressing objects: 100% (9/9), done. 
Writing objects: 100% (11/11), 2.36 KiB, done. 
Total 11 (delta 0), reused 0 (delta 0) 

-----> Python app detected 
-----> No runtime.txt provided; assuming python-2.7.6. 
-----> Preparing Python runtime (python-2.7.6) 
-----> Installing Setuptools (2.1) 
-----> Installing Pip (1.5.4) 
-----> Installing dependencies using Pip (1.5.4) 
       Downloading/unpacking Django==1.6.2 (from -r requirements.txt (line 1)) 
     ...
       Successfully installed Django dj-database-url dj-static gunicorn psycopg2 static pystache 
       Cleaning up... 

-----> Discovering process types 
       Procfile declares types -> web 

-----> Compressing... done, 34.8MB 
-----> Launching... done, v5 
       http://gentle-gorge-9766.herokuapp.com deployed to Heroku 

To [email protected]:gentle-gorge-9766.git 
* [new branch]      master -> master 

El siguiente paso es arrancar la aplicación que ya está en Heroku. Para ello ejecutaremos el comando en un dyno. Ejecutamos el siguiente comando:

$ heroku ps:scale web=1

Ahora puedes comprobar tu aplicación se esta ejecutando correctamente abriendo la dirección proporcionada por Heroku. También puedes ejecutar el siguiente comando:

$ heroku open 
Opening gentle-gorge-9766... done 

Para ver el estado de los dynos de nuestra aplicación ejecutamos el comando heroku ps:

$  heroku ps 
=== web (1X): `gunicorn hellodjango.wsgi` 
web.1: up 2014/02/23 18:20:54 (~ 9m ago)  

Como vemos, solo tenemos un dyno ejecutándose en este momento.

Comprobando los logs

Heroku permite consultar el log de nuestra aplicación. Simplemente hay que ejecutar el comando heroku logs:

$ heroku logs
2014-02-23T19:38:25+00:00 heroku[web.1]: State changed from created to starting
2014-02-23T19:38:29+00:00 heroku[web.1]: Starting process with command `gunicorn hellodjango.wsgi`
2014-02-23T19:38:29+00:00 app[web.1]: Validating models...
2014-02-23T19:38:29+00:00 app[web.1]:
2014-02-23T19:38:29+00:00 app[web.1]: 0 errors found
2014-02-23T19:38:29+00:00 app[web.1]: Django version 1.6.2, using settings 'hellodjango.settings'
2014-02-23T19:38:29+00:00 app[web.1]: Development server is running at http://0.0.0.0:8000/
2014-02-23T19:38:29+00:00 app[web.1]: Quit the server with CONTROL-C.
2014-02-23T19:38:30+00:00 heroku[web.1]: State changed from starting to up
2014-02-23T19:38:32+00:00 heroku[slugc]: Slug compilation finished

Sincronizando la base de datos

Heroku nos proporciona el comando heroku run que nos permite ejecutar los comandos que usamos cuando trabajamos en local con nuestra aplicación Django, como por ejemplo syncdb o validate. Para sincronizar los modelos definidos en nuestra aplicación Django con la base de datos deberemos ejecutar el siguiente comando:

$ heroku run python manage.py syncdb 
Running `python manage.py syncdb` attached to terminal... up, run.6034 
Creating tables ... 
Creating table django_admin_log 
Creating table auth_permission 
Creating table auth_group_permissions 
Creating table auth_group 
Creating table auth_user_groups 
Creating table auth_user_user_permissions 
Creating table auth_user 
Creating table django_content_type 
Creating table django_session 

You just installed Django's auth system, which means you don't have any superusers defined. 
Would you like to create one now? (yes/no): yes 
Username (leave blank to use 'u8183'): amatellanes 
Email address: [email protected] 
Password: 
Password (again): 
Superuser created successfully. 
Installing custom SQL ... 
Installing indexes ... 
+Installed 0 object(s) from 0 fixture(s)

También podemos usar el comando heroku run para ejecutar la shell de Django y trabajar con los datos almacenados en nuestra aplicación desplegada en Heroku:

$ heroku run python manage.py shell 
Running `python manage.py shell` attached to terminal... up, run.4549 
Python 2.7.6 (default, Jan 16 2014, 02:39:37) 
[GCC 4.4.3] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
(InteractiveConsole) 
>>> from django.contrib.auth.models import User 
>>> User.objects.all() 
[<User: amatellanes>]

A partir de aquí puedes leer varios artículos sobre el uso avanzado de Heroku: