Configurando Integración Continua en Ubuntu con Nodejs
15 de agosto de 2015 • 11 min de lectura

Pasé por sangre, sudor y lágrimas para traerte esto. Sufrí el calor abrasador del Valle de la Muerte y escalé las cimas del Monte McKinley. He sacrificado mucho.
Gran parte del contenido compartido en esta publicación no es mi trabajo original. Donde puedo, enlazo de vuelta al trabajo original.
Este artículo asume que puedes moverte por Linux.
No pude encontrar una guía completa sobre alojar y gestionar aplicaciones Nodejs en Ubuntu en capacidad de producción. He reunido múltiples artículos sobre el tema. Al final de este artículo espero que puedas configurar tu propio servidor Ubuntu y tener Nodejs desplegándose a través de un servidor de integración continua.
Entorno
Estoy usando TeamCity en Windows que luego despliega código desde GitHub a Ubuntu alojado en AWS.
Tecnologías
Para este artículo usé las siguientes tecnologías:
- Ubuntu 14.04 en AWS
- Plink 0.64
- TeamCity 9.1
- GitHub
- Nginx 1.9.3
Configurando Ubuntu
No voy a entrar en detalles aquí. Amazon Web Services (AWS) hace esto bastante fácil de hacer. No importa dónde esté o si está en tu propio servidor.
Encontré algunos problemas. Primero, asegúrate de que el puerto 80 esté abierto. Cometí el error tonto de intentar conectar con el puerto 80 cerrado. Una vez que descubrí mi error, me sentí como el trasero de un rinoceronte.
Instalando Nodejs desde el Código Fuente
Nodejs es una tecnología de servidor que usa el motor de javascript V8 de Google. Desde su lanzamiento en 2010, se ha vuelto ampliamente popular.
Las siguientes instrucciones originalmente vinieron de una publicación de Digital Ocean.
Siempre tienes la opción de instalar Nodejs desde apt-get, pero estará unas cuantas versiones atrasado. Para obtener los últimos bits, instala Nodejs desde el código fuente.
Al final de esta sección habremos descargado la última versión estable de node (al momento de este artículo), habremos construido el código fuente e instalado Nodejs.
Inicia sesión en tu servidor. Comenzaremos actualizando las listas de paquetes.
sudo apt-get update
También sugiero que actualices todos los paquetes. Esto no es necesario para Nodejs pero es una buena práctica mantener tu servidor actualizado.
sudo apt-get upgrade
Tu servidor está completamente actualizado. Es hora de descargar el código fuente.
cd ~
Al momento de escribir esto, 12.7 es la última versión estable de Nodejs. Consulta nodejs.org para la última versión.
wget https://nodejs.org/dist/v0.12.7/node-v0.12.7.tar.gz
Extrae el archivo que has descargado.
tar xvf node-v*
Muévete al directorio recién creado
cd node-v*
Configura y construye Nodejs.
./configure
make
Instala Nodejs
sudo make install
Para eliminar los archivos descargados y extraídos. Por supuesto, esto es opcional.
cd ~
rm -rf node-v*
¡Felicidades! ¡Nodejs ya está instalado! Y no fue muy difícil.
Configurando Nginx
Nodejs puede actuar como un servidor web, pero no es lo que querría exponer al mundo. Un servidor web industrial, endurecido y rico en características es mejor para esta tarea. He recurrido a Nginx para esta tarea.
Es un servidor web maduro con las características que necesitamos. Para ejecutar más de una instancia de Nodejs, necesitaremos reenvío de puertos.
Podrías estar pensando, ¿por qué necesitamos más de una instancia de Nodejs ejecutándose al mismo tiempo? Esa es una pregunta justa… En mi escenario, tengo un servidor y necesito ejecutar DEV, QA y PROD en la misma máquina. Sí, sé que no es ideal, pero no quiero levantar 3 servidores para cada entorno.
Para empezar, instalemos Nginx
sudo -s
add-apt-repository ppa:nginx/stable
apt-get update
apt-get install nginx
Una vez que Nginx se haya instalado exitosamente, necesitamos configurar los dominios. Voy a asumir que querrás tener cada uno de tus sitios en su propio dominio/subdominio. Si no quieres esto y quieres usar diferentes subcarpetas, eso es factible y muy fácil de hacer. No voy a cubrir ese escenario aquí. Hay toneladas de documentación sobre cómo hacer eso. Hay muy poca documentación sobre configurar diferentes dominios y reenvío de puertos a las instancias correspondientes de Nodejs. Esto es lo que cubriré.
Ahora que Nginx está instalado, crea un archivo para tudominio.com en /etc/nginx/sites-available/
sudo nano /etc/nginx/sites-available/tudominio.com
Agrega la siguiente configuración a tu archivo recién creado
# la(s) IP(s) en la(s) que tu servidor node está ejecutándose. Elegí el puerto 9001.
upstream app_myapp1 {
server 127.0.0.1:9001;
keepalive 8;
}
# la instancia del servidor nginx
server {
listen 80;
server_name tudominio.com;
access_log /var/log/nginx/tudominio.log;
# pasa la solicitud al servidor node.js con los headers correctos
# y mucho más puede ser agregado, ver opciones de configuración de nginx
location / {
proxy_http_version 1.1;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://app_myapp1;
}
}
Asegúrate de reemplazar “tudominio.com” con tu dominio real. Guarda y sal de tu editor.
Crea un enlace simbólico a este archivo en el directorio sites-enabled.
cd /etc/nginx/sites-enabled/
ln -s /etc/nginx/sites-available/tudominio.com tudominio.com
Para probar que todo funciona correctamente, crea una aplicación node simple y guárdala en /var/www/tudominio.com/app.js
y ejecútala.
Aquí hay una aplicación nodejs simple si no tienes una a mano.
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');}).listen(9001, "127.0.0.1");
console.log('Server running at http://127.0.0.1:9001/');
Reiniciemos Nginx.
sudo /etc/init.d/nginx restart
No olvides iniciar tu instancia de Nodejs, si no lo has hecho ya.
cd /var/www/tudominio/ && node app.js
Si todo funciona correctamente, cuando navegues a tudominio.com verás “Hello World.”
Para agregar otro dominio para una instancia diferente de Nodejs necesitas repetir los pasos anteriores. Específicamente necesitarás cambiar el nombre del upstream, el puerto y el dominio en tu nuevo archivo de configuración de Nginx. La dirección proxy_pass debe coincidir con el nombre del upstream en el archivo de configuración de nginx. Mira el nombre del upstream y el valor de proxy_pass y verás a qué me refiero.
Para recapitular, hemos instalado NodeJS desde el código fuente y acabamos de terminar de instalar Nginx. Hemos configurado y probado el reenvío de puertos con Nginx y Nodejs
Instalando PM2
Podrías estar preguntando “¿Qué es PM2?” como yo hice cuando escuché por primera vez sobre él. PM2 es un gestor de procesos para aplicaciones Nodejs. Nodejs no viene con mucho. Esta es parte de su atractivo. La desventaja de esto es, bueno, tienes que proporcionar las capas frente a él. PM2 es una de esas capas.
PM2 gestiona la vida del proceso Nodejs. Cuando se termina, PM2 lo reinicia. Cuando el servidor se reinicia, PM2 reinicia todos los procesos Nodejs por ti. También tiene un extenso proceso de ciclo de vida de desarrollo. No cubriremos este aspecto de PM2. Te animo a leer la documentación bien escrita.
Asumiendo que estás conectado al terminal, comenzaremos instalando PM2 vía NPM. Npm es el gestor de paquetes de Nodejs (npm). Se instaló cuando instalaste Nodejs.
sudo npm install pm2 -g
Eso es todo. PM2 ya está instalado.
Usando PM2
PM2 es fácil de usar.
El hola mundo para PM2 es simple.
pm2 start hello.js
Esto agrega tu aplicación a la lista de procesos de PM2. Esta lista se muestra cada vez que se inicia una aplicación.
En este ejemplo hay dos aplicaciones Nodejs ejecutándose. Una llamada api.dev y api.pre.
PM2 automáticamente asigna el nombre de la aplicación al “App name” en la lista.
Por defecto, PM2 no se configura para iniciarse cuando el servidor se reinicia. El comando es diferente para los diferentes sabores de Linux. Estoy ejecutando en Ubuntu, así que ejecutaré el comando de Ubuntu.
pm2 start ubuntu
Aún no hemos terminado. Tenemos que agregar una ruta al binario de PM2. Afortunadamente, la salida del comando anterior nos dice cómo hacer eso.
Salida:
[PM2] You have to run this command as root
[PM2] Execute the following command :
[PM2] sudo env PATH=$PATH:/usr/local/bin pm2 startup ubuntu -u sammy
Run the command that was generated (similar to the highlighted output above) to set PM2 up to start on boot (use the command from your own output):
sudo env PATH=$PATH:/usr/local/bin pm2 startup ubuntu -u sammy
Ejemplos de otros usos de PM2 (opcional)
Detener una aplicación por el nombre de la aplicación
pm2 stop example
Reiniciar por el nombre de la aplicación
pm2 restart example
Lista de aplicaciones actuales gestionadas por PM2
pm2 list
Especificar un nombre al iniciar un proceso. Si llamas, PM2 usa el archivo javascript como el nombre. Esto podría no funcionar para ti. Aquí está cómo especificar el nombre.
pm2 start www.js --name api.pre
Eso debería ser suficiente para empezar con PM2. Para aprender más sobre las capacidades de PM2, visita el Repositorio de GitHub.
Configurando y Usando Plink
Probablemente estés pensando, “¿Qué demonios es Plink?” Al menos eso pensé. Todavía no estoy seguro de qué pensar de él. Nunca he visto algo así.
¿Has visto la película Wall-e? Wall-e saca un spork. Primero trata de ponerlo con los tenedores, pero no encaja y luego trata de ponerlo con las cucharas, pero no encaja. Bueno, eso es Plink. Es un cruce entre Putty (SSH) y la Línea de Comandos de Windows.
Plink básicamente te permite ejecutar comandos bash a través de la línea de comandos de Windows mientras estás conectado a un shell de Linux (y probablemente Unix).
Comienza descargando Plink. Es solo un ejecutable. Recomiendo ponerlo en C:/Program Files (x86)/Plink
. Necesitaremos referenciarlo más tarde.
Si estás ejecutando una instancia de Ubuntu en AWS. Ya tendrás un certificado configurado para Putty (estoy asumiendo que estás usando Putty).
Si no es así, necesitarás asegurar que tienes un certificado ssh compatible para Ubuntu en AWS.
Si no estás usando AWS, puedes especificar el nombre de usuario y contraseña en la línea de comandos y no tendrás que preocuparte por los certificados ssh.
Aquí hay un ejemplo de línea de comandos que se conecta a Ubuntu con Plink.
"C:\Program Files (x86)\Plink\plink.exe" -ssh [email protected] -i "C:\Program Files (x86)\Plink\ssh certs\aws-ubuntu.ppk"
Esto podría estar adelantándose, pero para ejecutar un script ssh en el servidor Ubuntu agregamos la ruta completa al final del comando Plink.
"C:\Program Files (x86)\Plink\plink.exe" -ssh [email protected] -i "C:\Program Files (x86)\Plink\ssh certs\aws-ubuntu.ppk" /var/www/deploy-dev-ui.sh
Y eso, querido lector, es Plink.
Entendiendo NODE_ENV
NODE_ENV
es una variable de entorno popularizada por expressjs. Antes de iniciar la instancia de node, establece el NODE_ENV
al entorno. En el código puedes cargar archivos específicos basados en el entorno.
Estableciendo NODE_ENV
Linux & Mac: export NODE_ENV=PROD
Windows: set NODE_ENV=PROD
La variable de entorno se recupera dentro de una instancia de Nodejs usando process.env.NODE_ENV
.
ejemplo
var environment = process.env.NODE_ENV
o con expressjs
app.get('env')
*Nota: app.get('env')
por defecto es “development”.
Juntando todo
Nodejs
, PM2
, Nginx
y Plink
están instalados y esperemos que funcionando. Ahora necesitamos juntar todas estas piezas en una solución de integración continua.
Clona tu repositorio de GitHub en /var/www/tudominio.com
. Aunque SSH es más seguro que HTTPS, recomiendo usar HTTPS. Sé que esto no es ideal, pero no pude hacer que Plink funcionara con GitHub en Ubuntu. Sin entrar en muchos detalles, los formatos de certificados SSH de Plink y GitHub son diferentes y llamar a GitHub vía Plink a través de SSH no funcionó. ¡Si puedes resolver el problema, házmelo saber!
Para hacer que el pull de GitHub sea automático, el nombre de usuario y contraseña necesitarán ser parte de la url de origen.
Aquí está cómo estableces tu url de origen. Por supuesto necesitarás sustituir tu información donde sea apropiado.
git remote set-url origin https://username:[email protected]/username/tudominio.git
Clona tu repositorio.
cd /var/www/tudominio.com
git clone https://username:[email protected]/username/tudominio.git .
Nota que si este directorio no está completamente vacío, incluyendo archivos ocultos, Git no clonará el repositorio a este directorio.
Para encontrar archivos ocultos en el directorio ejecuta este comando
ls -a
Para el pegamento, estamos usando un script de shell. Aquí hay una copia de mi script.
#!/bin/bash
echo "> Current PM2 Apps"
pm2 list
echo "> Stopping running API"
pm2 stop api.dev
echo "> Set Environment variable."
export NODE_ENV=DEV
echo "> Changing directory to dev.momentz.com."
cd /var/www/tudominio.com
echo "> Listing the contents of the directory."
ls -a
echo "> Remove untracked directories in addition to untracked files."
git clean -f -d
echo "> Pull updates from Github."
git pull
echo "> Install npm updates."
sudo npm install
echo "> Transpile the ECMAScript 2015 code"
gulp babel
echo "> Restart the API"
pm2 start transpiled/www.js --name api.dev
echo "> List folder directories"
ls -a
echo "> All done."
Lanzo este script de shell con TeamCity, pero puedes lanzarlo con cualquier cosa.
Aquí está el comando crudo.
"C:\Program Files (x86)\Plink\plink.exe" -ssh [email protected] -i "C:\Program Files (x86)\Plink\ssh certs\aws-ubuntu.ppk" /var/www/deploy-tudominio.sh
exit
>&2
Eso es todo.
En Conclusión
Este proceso tiene algunos bordes ásperos… Espero pulir esos bordes con el tiempo. Si tienes sugerencias, por favor déjalas en los comentarios.
Este documento está en mi Repositorio de GitHub. Las tecnologías cambian, así que si encuentras un error por favor actualízalo. Entonces actualizaré esta publicación.
↑ Volver arriba