Por curiosidad hace unos días empece a jugar con el servicio de DotCloud. A modo de prueba se me ocurrió configurar localmente un entorno virtual en python que duplique el stack que tenia en mi instancia de DotCloud ( django-nonrel + mongoDB ), de forma tal que se simplifique el desarrollo y deploy de un proyecto dado . Para eso me propuse generar un entorno con la siguiente estructura de directorios.

  1. |-project_container
  2. |—-project_name_dotcloud
  3. |——-dotcloud.yml
  4. |——-mkadmin.py
  5. |——-nginx.conf
  6. |——-postinstall
  7. |——-requirements.txt
  8. |——-waitfordb.py
  9. |——-wsgi.py
  10. |——-project_name
  11. |———-__init__.py
  12. |———-manage.py
  13. |———-settings.py
  14. |———-urls.py
  15. |—-project_name_env
  16. |——-….

project_container: Raiz del proyecto, contiene mi proyecto de DotCloud, y el entorno virtual de python.

project_name_dotcloud: Contenedor del proyecto DotCloud, incluye los archivos de configuración de mi instancia, y el projecto de django.

project_name: Raíz del proyecto en django-nonrel.

project_name_env: Entorno virtual de python.

 

Acá les dejo el paso a paso.

1) Registración en DotCloud

Para hacer algunas pruebas del servicio podemos registrarnos gratuitamente, esto nos habilitará a instalar dos servicios en nuestra instancia. Podemos crear nuestra cuenta desde la siguiente url https://www.dotcloud.com/accounts/register/ una ves que nos registramos debemos instalar la aplicación cliente en nuestra máquina.

  1. $ sudo easy_install pip && sudo pip install dotcloud

y finalmente vinculamos el cliente a nuestra instancia en la nube.

  1. $ dotcloud
  2. Enter your api key (You can find it at http://www.dotcloud.com/account/settings):

 

2) Instalando MongoDB

La instalación de mongodb la podemos realizar en forma simple desde el port de Mac OSX.

  1. $ sudo port install mongodb

y para iniciar la instancia local ejecutamos.

  1. $ sudo mongod

 

3) Generamos nuestro entorno de desarrollo

Creamos el directorio project_container, este será la raíz y contenedor principal de nuestro proyecto y de la configuración del virtualenv.

  1. $ mkdir project_container
  2. $ cd project_container

Una vez que tenemos nuestro contenedor creamos el entorno, en caso de ser necesario primero instalamos virtualenv

  1. project_container$ pip install virtualenv

Creamos el entorno

  1. project_container$ virtualenv project_name_env
  2. New python executable in project_name_env/bin/python
  3. Installing setuptools…………done.
  4. Installing pip……………done.

y finalmente activamos nuestro nuevo entorno de trabajo.

  1. project_container$ source project_name_env/bin/activate

 

4) Instalamos django-nonrel y las dependencias necesarias para trabajar con mongodb.

Instalando django-nonrel

  1. (project_name_env)project_container$ pip install hg+https://bitbucket.org/wkornewald/django-nonrel

Instalando djangotoolbox

  1. (project_name_env)project_container$ pip install hg+https://bitbucket.org/wkornewald/djangotoolbox
  2. Successfully installed djangotoolbox
  3. Cleaning up…

Instalando mongodb-engine

  1. (project_name_env)project_container$ pip install git+https://github.com/django-mongodb-engine/mongodb-engine
  2. Successfully installed pymongo django-mongodb-engine
  3. Cleaning up…

 

5) Creamos nuestro proyecto en django-nonrel

Primero creamos un directorio contenedor para el proyecto de DotCloud.

  1. (project_name_env)project_container$ mkdir project_name_dotcloud
  2. (project_name_env)project_container$ cd project_name_dotcloud

Dentro de este contenedor creamos el proyecto en django.

  1. (project_name_env)project_container/project_name_dotcloud$ django-admin.py startproject project_name

 

6) Configuración de nuestra instancia en DotCloud

  • Indicamos los servicios que vamos a utilizar.
  1. (project_name_env)project_container/project_name_dotcloud$ nano dotcloud.yml
  2. www: 
  3.   type: python
  4. db: 
  5.   type: mongodb

En esta url http://docs.dotcloud.com/guides/build-file/ podemos encontrar mas opciones de configuración a definir.

 

  • A continuación  Indicamos cuales son los requerimientos para nuestro proyecto.
  1. (project_name_env)project_container/project_name_dotcloud$ nano requirements.txt
  2.  
  3. pymongo
  4. git+http://github.com/django-nonrel/mongodb-engine.git#egg=django_mongodb_engine
  5. hg+http://bitbucket.org/wkornewald/django-nonrel#egg=Django
  6. hg+http://bitbucket.org/wkornewald/djangotoolbox#egg=djangotoolbox

- pymongo, El cliente de MongoDB para Python.

- django_mongodb_engine, Contiene la interface entre Django y MongoDB.

- django-nonrel, Un fork de Django que incluye cambios menores para permitir operar con base de datos NoSQL.

- djangotoolbox, No es requerido por django, pero si por el sitio de administración.

En este enlace http://www.pip-installer.org/en/latest/requirement-format.html podemos encontrar mas detalles acerca del uso de pip y los formatos utilizados en el archivo requirements.txt

 

  • El archivo wsgi.py es el puente entre el servicio de python, y nuestra aplicación django. Indicamos que ejecute el handler de django con el setting correspondiente a nuestro proyecto.
  1. (project_name_env)project_container/project_name_dotcloud$ nano wsgi.py
  2.  
  3. import os
  4. os.environ[‘DJANGO_SETTINGS_MODULE’] = ‘project_name.settings’
  5. import django.core.handlers.wsgi
  6. application = django.core.handlers.wsgi.WSGIHandler()

 

  • Este hook se ejecuta en el servidor luego de cada deploy. Lo utilizamos para verificar el estado de mongodb, sincronizar la base de datos y copiar los archivos estáticos relacionados al proyecto (css, imágenes, etc ).
  1. (project_name_env)project_container/project_name_dotcloud $ nano postinstall
  2.  
  3. #!/bin/sh
  4. # verificamos que luego del deploy mongodb este activo
  5. python waitfordb.py
  6. # Sincronizamos la base de datos con el modelo de django
  7. python project_name/manage.py syncdb –noinput
  8. # creamos un usuario administrador en django
  9. python mkadmin.py
  10. # Creamos carpetas para archivos estaticos, y copiamos los relacionados al proyecto
  11. mkdir -p /home/dotcloud/data/media /home/dotcloud/data/static
  12. python project_name/manage.py collectstatic –noinput

 

  • Con este script verificamos si la instancia de mongodb esta activa.
  1. (project_name_env)project_container/project_name_dotcloud $ nano waitfordb.py
  2.  
  3. #!/usr/bin/env python
  4. from wsgi import *
  5. from django.contrib.auth.models import User
  6. from pymongo.errors import AutoReconnect
  7. import time
  8. deadline = time.time() + 600
  9. while time.time() < deadline:
  10.     try:
  11.         User.objects.count()
  12.         print ‘Successfully connected to database.’
  13.         exit(0)
  14.     except AutoReconnect:
  15.         print ‘Could not connect to database. Waiting a little bit.’
  16.         time.sleep(10)
  17. print ‘Could not connect to database after 10 minutes. Something is wrong.’
  18. exit(1)

 

  • Con este script verificamos si existe un usuario  “admin” en caso e no existir lo creamos con permisos de “superuser”.
  1. (project_name_env)project_container/project_name_dotcloud $ nano mkadmin.py
  2.  
  3. #!/usr/bin/env python
  4. from wsgi import *
  5. from django.contrib.auth.models import User
  6. u, created = User.objects.get_or_create(username=‘admin’)
  7. if created:
  8.     u.set_password(‘password’)
  9.     u.is_superuser = True
  10.     u.is_staff = True
  11.     u.save()

 

  • Configuramos nginx el acceso a los directorios “media” y “static”.
  1. (project_name_env)project_container/project_name_dotcloud $ nano nginx.conf
  2.  
  3. location /media/ { root /home/dotcloud/data ; }
  4. location /static/ { root /home/dotcloud/data ; }

En este enlace http://docs.dotcloud.com/guides/nginx/ encontramos información mas detallada acerca de las opciones que nos provee nginx.

 

7) Configurando nuestro proyecto de django

  1. (project_name_env)project_container/project_name_dotcloud $ nano project_name/settings.py

En el archivo settings.py de nuestro proyecto django modificamos las siguientes configuraciones.

  1. import json
  2. import os
  3. try:
  4.   with open(os.path.expanduser(‘~/environment.json’)) as f:
  5.     env = json.load(f)
  6.     cloud_setting = True
  7. except:
  8.   cloud_setting = False
  9.  
  10. if cloud_setting:
  11.   DATABASES = {
  12.      ‘default’ : {
  13.         ‘ENGINE’ : ‘django_mongodb_engine’,
  14.         ‘NAME’ : ‘project_db’,
  15.         ‘HOST’ : env[‘DOTCLOUD_DB_MONGODB_URL’],
  16.         ‘SUPPORTS_TRANSACTIONS’ : False,
  17.      }
  18.   }
  19. else:
  20.   DATABASES = {
  21.      ‘default’ : {
  22.         ‘ENGINE’ : ‘django_mongodb_engine’,
  23.         ‘NAME’ : ‘project_db’,
  24.         ‘HOST’ : ,
  25.         ‘SUPPORTS_TRANSACTIONS’ : False,
  26.      }
  27.   }
  28.  
  29. if cloud_setting:
  30.   MEDIA_ROOT = ‘/home/dotcloud/data/media/’
  31.   MEDIA_URL = ‘/media/’
  32.   STATIC_ROOT = ‘/home/dotcloud/data/static/’
  33.   STATIC_URL = ‘/static/’
  34. else:
  35.   MEDIA_ROOT =
  36.   MEDIA_URL =
  37.   STATIC_ROOT =
  38.   STATIC_URL = ‘/static/’
  39.  
  40. INSTALLED_APPS = (
  41.     ‘django.contrib.auth’,
  42.     ‘django.contrib.contenttypes’,
  43.     ‘django.contrib.sessions’,
  44.     #‘django.contrib.sites’,
  45.     ‘django.contrib.messages’,
  46.     ‘django.contrib.staticfiles’,
  47.     # Uncomment the next line to enable the admin:
  48.     ‘django.contrib.admin’,
  49.     # Uncomment the next line to enable admin documentation:
  50.     # ‘django.contrib.admindocs’,
  51.     ‘djangotoolbox’,
  52. )

Habilitamos las urls para acceder al administrador de django.

  1. (project_name_env)project_container/project_name_dotcloud $ nano project_name/urls.py
  2.  
  3. from django.conf.urls.defaults import patterns, include, url
  4.  
  5. from django.contrib import admin
  6. admin.autodiscover()
  7.  
  8. urlpatterns = patterns(,
  9.     # Uncomment the next line to enable the admin:
  10.     url(r‘^admin/’, include(admin.site.urls)),
  11. )

 

8 ) Probamos la instancia local

Una ves que tenemos configurado nuestro entorno podemos verificar si nuestra instancia local estafuncionando correctamente. Para eso sincronizamos nuestro modelo de django, y ejecutamos el servidor local.

  1. (project_name_env)project_container/project_name_dotcloud $ cd project_name
  2. (project_name_env)project_container/project_name_dotcloud/project_name $ python manage.py syncdb
  3. (project_name_env)project_container/project_name_dotcloud/project_name $ python manage.py runserver

Si todo funciona como corresponde en esta url http://127.0.0.1:8000/admin tendremos acceso al administrador de django.

 

9) Hacemos el deploy a DotCloud

Primero debemos crear el proyecto en nuestra instancia de dotcloud, para eso ejecutamos este comando.

  1. (project_name_env)project_container/project_name_dotcloud $ dotcloud create projectnamedjango

Una vez que tenemos nuestro proyecto creado podemos hacer un deply de cada modificación ejecutando el siguiente comando.

  1. (project_name_env)project_container/project_name_dotcloud $ dotcloud push projectnamedjango

Para verificar que el deploy se realizo en forma correcta podremos acceder con una url similar a la siguiente: http://projectnamedjango-xxxxxxx.dotcloud.com/admin/

 

 

En caso de haber realizado todos los pasos en forma correcta, tendríamos que ver exactamente lo mismo en nuestra instancia local que en la instancia de DotCloud. Podríamos seguir desarrollando localmente y cuando necesitemos hacer un deploy bastara con ejecutar el siguiente comando:

  1. (project_name_env)project_container/project_name_dotcloud $ dotcloud push projectnamedjango