Mostrando entradas con la etiqueta Cloud9. Mostrar todas las entradas
Mostrando entradas con la etiqueta Cloud9. Mostrar todas las entradas

martes, 10 de diciembre de 2013

Deploy de una app hecha con Grunt y Bower, desde Cloud9, en Heroku

¿Qué es Heroku?

Heroku es una plataforma como servicio (PaaS) en la nube, que nos permite arrancar un entorno de desarrollo para el lenguaje que queramos, de un modo transparente, y sin tener que perder tiempo por nuestra parte en configurar nada en nuestro sistema local. Podríamos decir que es un entorno de desarrollo "llave en mano". Al crear una aplicación en Heroku, éste nos ofrece un entorno sobre Debian, preparado ya para programar con ruby, php, java, node, o el lenguaje que necesitemos.

Nos ofrece también un repositorio Git, donde alojar nuestros fuentes. Cada vez que hagamos un push, Heroku compilará nuestro proyecto, y un servidor web al que podremos acceder para ver nuestra aplicación online: http://nuestraapp.herokuapp.com/

Para este pequeño "manual", voy a suponer que ya estás familiarizado con el desarrollo de aplicaciones con Grunt, Less, Jade, etc. Por tanto, entiendo que tu aplicación ya tiene un archivo package.json. Lo que voy a explicar aquí, es cómo modificarla para poder hacer deploys en Heroku, desde Cloud9:

Instalar el motor Node

Para que Node funcione correctamente en Heroku, debemos especificar en package.json que vamos a usar Node.js junto con su versión: algo que no era necesario para compilar en local, pero sí lo es en Heroku. Para ello, debemos añadir la propiedad "engines" a nuestro package.json:

"engines": {
     "node": "0.10.x"
}

No es necesario especificar que necesitaremos npm, ni su versión, ya que npm viene en el lote del motor Node.

Instalar Express, Grunt y Bower en nuestra app de Heroku

Por defecto, cuando compilamos una aplicación en Heroku, ésta se compila en modo producción, por lo tanto, lo que pongamos en "devDependencies" de nuestro package.json será ignorado. Llegados a este punto podemos hacer dos cosas:

  • o cambiamos el entorno a modo desarrollo, de tal modo que se instalen las dependencias definidas en "devDependencies",
  • o especificamos en "dependencies" las dependencias para producción.

Personalmente prefiero esta última opción, es decir, usar el entorno de producción en Heroku. Por tanto, copiamos los paquetes de "devDependencies" a "dependencies", y además, le añadimos también algunos paquetes que por defecto en Heroku no están instalados: express, bower, grunt y grunt-cli. Nuestro package.json quedaría así (por ejemplo):

"dependencies": {
  "express": "~3.3.4",
  "bower": "latest",
  "grunt": "latest",
  "grunt-cli": "latest",
  ...
  resto de paquetes
  ...
},
"devDependencies": {
  "grunt": "latest",
  ...
  resto de paquetes
  ...
}

Ejecutar Bower install en Heroku

Si en nuestra app hemos usado Bower, necesitaremos ejecutar el comando 'bower install' para instalar los repositorios al compilar. Para ello, añadimos la instrucción al bloque "scripts" en package.json:

"scripts": {
    "postinstall": "./node_modules/bower/bin/bower install"
  }

Crear el servidor de archivos estáticos

Imaginemos que nuestra app tiene la siguiente estructura:

/app  --> Archivos fuente
  |--/fonts
  |--/img
  |--/jade
  |--/js
  |--/less
  \--/test
/dev  --> Compilación de desarrollo
  |--/css
  |--/fonts
  |--/html
  |--/img
  |--/js
  \--/test
/pro  --> Compilación de producción (concatenada, minificada y ofuscada)
  |--/css
  |--/fonts
  |--/html
  |--/img
  |--/js
  \--/test

Por defecto, Heroku no nos crea un servidor HTTP. Debemos crearlo nosotros con Node. Para ello nos creamos un archivo javascript al que llamaremos por ejemplo "web.js".

Suponiendo que hemos configurado nuestra app, para que compile los estáticos en la carpeta /dev, y dentro de ella nuestro archivo index se encuentra en html/index.html, este sería nuestro archivo "web.js" para arrancar un servidor de estáticos en Heroku:

web.js

var express = require("express"),
    app = express.createServer(),
    port = process.env.PORT || 3000;

process.env.PWD = process.cwd();

app.configure(function(){
    app.use(express.static(process.env.PWD + '/dev'));
    app.use(express.bodyParser());
    app.use(express.methodOverride());

    //Error Handling
    app.use(express.logger());
    app.use(express.errorHandler({
        dumpExceptions: true, 
        showStack: true
    }));

    app.use(app.router);
});

app.get('/', function(req, res){
    res.redirect("html/index.html");
    res.render("index.html");
});

app.listen(port, function() {
    console.log("Listening on " + port + "\nDirectory: " + process.env.PWD + "/dev");
});

Ahora nos falta decirle a Heroku que ejecute dicho archivo. Para ello debemos crearnos un archivo llamado Procfile. Esto lo explico en el siguiente apartado.

Crear el archivo Procfile

Una vez configurado correctamente package.json, nos creamos un archivo nuevo llamado Procfile, en el que indicamos a Heroku lo que ejecutar al realizar el deploy. Es aquí debemos decirle a Heroku que arranque el servidor web, para que sirva los archivos estáticos generados previamente con grunt. Este sería nuestro Procfile:

web: node web.js

Instalar cliente Heroku en Cloud9

Para poder ejecutar comandos de Heroku, y manejar nuestro entorno desde la terminal de Cloud9, necesitamos instalar el cliente. Para ello escribimos, en el terminal de Cloud9:

wget http://assets.heroku.com/heroku-client/heroku-client.tgz
tar xzfv heroku-client.tgz
cd heroku-client/bin
PATH=$PATH:$PWD

Acceso al bash de Heroku desde Cloud9

Una vez instalado el cliente, desde el terminal de Cloud9 tendremos acceso al bash Heroku. Para ello abrimos un terminal de Cloud9, y escribimos:

heroku run bash -a nombre-de-nuestra-app

Configuramos el Buildpack

Cuando hacemos un git push a nuestro repositorio de Heroku, éste prepara los archivos para ser compilados. El conjunto de acciones que se realizan para compliar, se define en un Buildpack. Heroku dispone de varios Buildpacks, dependiendo del lenguaje y lo que queramos hacer. Sin embargo en este caso, necesitamos un BUILDPACK "no oficial", para que de soporte a Grunt. Para instalar dicho buildpack, escribimos en el terminal:

heroku config:add BUILDPACK_URL=https://github.com/mbuchetics/heroku-buildpack-nodejs-grunt.git -a nombre-de-nuestra-app

En este momento se compilarán nuestros archivos, tal y como lo hubiéramos compilado en Gruntfile.js, y tendremos acceso a ellos desde el servidor web de estáticos, en la URL: http://nombredenuestraapp.herokuapp.com

Añadir deploy en Cloud9

En este apartado veremos cómo lanzar un deploy desde Cloud9:

Después elegimos el servicio Heroku.com:

Configurar el entorno a "development" (opcional)

Este paso es opcional, y explica cómo proceder si quisiéramos cambiar el entorno a desarrollo, en vez de producción que es como lo tiene Heroku por defecto. Desde la terminal de Cloud9 escribimos:

heroku config:set NODE_ENV=development -a nombre-de-nuestra-app
heroku labs:enable user-env-compile -a nombre-de-nuestra-app

Más información

viernes, 5 de julio de 2013

Instalar Cloud9 en una instancia micro Amazon EC2, con Ubuntu 12.04

Últimamente no hago más que alucinar con Cloud9, y las cosas que se pueden hacer con este estupendo IDE en la nube. Incluso he estado a punto de pagar por sus servicios, una pequeña y bien merecida cuota de 12$/mes. Pero me echaba un poco para atrás, la idea de tener sólo 512Mb por workspace. Así que dándole vueltas, se me ocurrió instalarlo en una instancia micro de Amazon EC2, con Ubuntu 12.04, ¡gratis! y sin restricciones. Os cuento cómo:

Abrimos el puerto 3131 en nuestro EC2

Para este tutorial, vamos a utilizar dicho puerto como ejemplo, aunque podría ser cualquier otro

Para ello vamos a nuestra consola de gestión del EC2, y hacemos click en "Security Groups". Editamos el grupo de seguridad que tengamos asociado a nuestra micro instancia, sobre la que correrá Cloud9 con Node.js:


Instalamos las dependencias

Para que Cloud9 pueda funcionar, necesita ciertas dependencias, que debemos tener instaladas previamente en nuestro servidor. Para ello, ejecutamos en el terminal, la siguiente instrucción:

sudo apt-get install -y build-essential g++ curl libssl0.9.8 libssl-dev apache2-utils git libxml2-dev

Preparamos el directorio de instalación

Para evitar problemas de permisos, mejor crearnos un directorio en la carpeta home del usuario con el que vayamos a lanzar Cloud9, e instalar ahí todo lo que necesitemos ejecutar. Lo puedes llamar como quieras. Yo he usado "c9": si eliges otro nombre, recuerda cambiarlo en todos los comandos que veas de este tutorial. Ejecuta desde el terminal lo siguiente:

mkdir ~/c9
echo 'export PATH=$HOME/c9/bin:$PATH' >> ~/.bashrc
. ~/.bashrc

El resto de instrucciones, las ejecutaremos sobre el directorio que nos hemos creado:

cd ~/c9

Instalamos Node Version Manager (NVM)

Este paso es opcional, aunque no viene mal hacerlo. Con Node Version Manager, podrás tener las versiones de node que necesites instaladas en tu sistema, y ejecutar aplicaciones con una o con otra. Por ejemplo, Cloud9 no siempre funciona con la última versión de Node.js. Es posible que necesites ejecutar Cloud9, con otra versión anterior. Aquí es donde nos vendrá bien tener instalado el NVM. Para ello, primero debemos eliminar cualquier versión que tengamos instalada previamente de Node.js
Con los siguientes comandos, nos bajamos de GitHub la última versión de Node Version Manager, en la carpeta c9/nvm/ dentro del directorio home:

sudo apt-get remove nodejs
git clone git://github.com/creationix/nvm.git ~/c9/nvm
echo '. ~/c9/nvm/nvm.sh' >> ~/.bashrc && . ~/.bashrc

Instalamos Node.js desde NVM

Ahora ya podremos instalar la versión de Node.js que queramos. Incluso podemos tener varias simultáneamente:

nvm install v0.8.18
nvm install v0.10.12
nvm use 0.10.12

Descargamos e instalamos Cloud9 desde el repo de GitHub

Los siguientes comandos, descargan la última versión de Cloud9 en GitHub, creamos un directorio en la carpeta c9/cloud9/ de home, y dentro de éste cambiamos a la última rama de desarrollo, para después, actualizar todos los submódulos:

git clone git://github.com/ajaxorg/cloud9.git ~/c9/cloud9
cd ~/c9/cloud9
git checkout devel
git submodule update --init --recursive
bin/cloud9.sh
cd ..

Instalamos sourcemint

sudo npm install -g sm
cd ~/c9/cloud9
sudo sm install

Arrancamos Cloud9 con la versión de Node.js que necesitemos

Cloud9 puede ser usado con cualquier navegador. Todo lo que necesitas es arrancar el servidor con tu ruta de proyecto. Se arranca ejecutando el script ~/c9/cloud9/bin/cloud9.sh, y podemos pasarle algunos parámetros de configuración:

  • -l: indicamos la IP desde la que se puede acceder:
    • 127.0.0.0: si queremos que sólo se pueda acceder a nuestro Cloud9 desde http://localhost/
    • 0.0.0.0: si queremos que se pueda acceder desde cualquier IP
  • -p: indicamos el puerto (que tendremos que abrir desde EC2)
  • -w: indicamos la ruta al workspace a cargar

Por ejemplo, si quisiéramos ejecutar Cloud9, con la versión 0.10.12 de Node.js, y que fuese accesible desde cualquier IP, a través del puerto 3131, y que el directorio de trabajo fuese lo que tengamos en /var/www, tendríamos que escribir lo siguiente:

nvm use 0.10.12 && cd ~/c9/cloud9 && bin/cloud9.sh -l 0.0.0.0 -p 3131 -w /var/www

En este momento, debemos ver la siguiente imagen en nuestra consola:

Detener el servicio Cloud9

Por normal general, simplemente con CTRL+C, en la consola desde donde se ha lanzado el servicio, basta con detenerlo. Pero si por alguna razón, este método no nos funciona, podemos detener los procesos de Cloud9 manualmente.

Lo primero que tenemos que hacer, es abrir otra consola, o terminal, y ejecutar el comando que nos permita ver qué procesos hay asociados a Cloud9. Para ello:

ps aux | grep cloud9

Con esto nos aparecerá un listado de los procesos involucrados. Para detenerlos manualmente, ya sólo tenemos que hacer:

kill PID

Si quisiésemos ver los procesos de node:

ps aux | grep node
kill PID

Si esto no funciona, podemos probar con:

killall node

Desinstalando Cloud9

En caso de que Cloud9 no te guste, puedes borrarlo completamente, eliminando el directorio de instalación que nos creamos antes, de tu ~/.bashrc. En este tutorial es ~/c9, por tanto:

nano ~/.bashrc

Y eliminamos la siguiente linea:

export PATH=$HOME/c9/bin:$PATH

Después borramos las dependencias (opcional)

sudo apt-get remove build-essential g++ curl libssl-dev apache2-utils git libxml2-dev

Cambiar fácilmente de un proyecto a otro (opcional)

Por defecto, Cloud9 está preparado para trabajar con un único proyecto, o espacio de trabajo. Tengo muchos proyectos en sendos repositorios Git. Intenté meter cada uno en un directorio independiente, dentro de un mismo espacio de trabajo, pero no funcionó como debería. Lo puedes hacer, pero perderás la integración con Git.

La instalación de un único proyecto, tiene sentido en un servidor cloud, pero es un inconveniente cuando trabajas con una instalación local. De cualquier forma, es fácil cambiar de un proyecto a otro con un simple shell script. Lo primero que tienes que hacer es tener instalado Zenity:

sudo apt-get install zenity

Después editamos el script

nano gedit ~/c9/projectswitcher.sh

Añadimos el siguiente código y guardamos:

#!/bin/bash
PROJECT=$(zenity --file-selection --directory --title 'Select a Project Directory')

if test -d "${PROJECT}";then
  killall node
  nvm use 0.10.12 && cd ~/c9/cloud9 && bin/cloud9.sh -l 0.0.0.0 -p 3131 -w ${PROJECT} &
fi
exit

Le cambiamos los permisos para hacerlo ejecutable:

chmod +x ~/c9/projectswitcher.sh

Bibliografía

Agradecimientos

Quiero agradecer especialmente a mi excompañero de trabajo: Víctor Gutiérrez, por haberme enseñado este estupendo IDE. Sin él, nunca lo habría descubierto!