Hace un tiempo escribí un tutorial en el que explicaba este mismo tema pero sin Docker. Hasta ese tiempo no sabía la capacidad que podía tener esta herramienta, simplemente entendía que era algo que se estaba usando y que podía hacer cosas muy buenas para procesos en tendencia como DevOps, y entonces me propuse indagar un poco más y poder aprender algo nuevo, que le sirva mucho a mi empresa y a mi carrera como desarrollador. El resultado quedó bastante bien por lo que decidí escribir este tutorial para que te pueda aportar en algo. !Entonces vamos allá!.

Docker

Antes de todo debemos saber que es Docker y porque mucha gente habla cosas muy buenas acerca de esta herramienta.
Docker es una tecnología de creación de contenedores de software. Creo que podemos decir que es una especie de software de virtualización pero sin incluir un sistema operativo de manera directa, para que lo entiendan un poco mejor usemos esta imagen que pude extraer de la página oficial de Docker.

Esta es la propuesta que nos da Docker para manejar nuestras aplicaciones, ponelas en contenedores con la finalidad que se puedan implementar de manera más rápida y liviana.

Accediendo a mi servidor

Para este tutorial voy a trabar en una instancia Ec2 de Amazon tipo t2.micro, con un sistema operativo Ubuntu Server 18.04 LTS, puedes usar el Free Tier que te da Amazon para obtener una instancia de Ec2.

Me conectaré a la instancia de Amazon vía SSH.

Instalamos Docker

Y bien, ya dentro de mi sistema operativo lo primero que debo hacer es instalar Docker. En mi caso al estar usando Linux lo voy a hacer a través del comando apt-getsi estas usando un sistema operativo diferente puedes encontrar más información acerca de la instalación de Docker desde su documentación oficial.

Entonces, ejecutemos los siguientes comandos:

sudo apt-get updatesudo apt install docker.io

También podemos ejecutar los siguientes comandos para que Docker se levante junto con el sistema operativo.

sudo systemctl start dockersudo systemctl enable docker

Instalamos Git

Instalamos Git usando el siguiente comando:

sudo apt-get install git

Para comprobar que todo salió bien y ver que versión se instaló ejecutamos:

git --version

Dockerizando tu app en NodeJs

Cuando decimos dockerizar o dockerize (en inglés suena mejor) nos referimos a que básicamente debemos crear un archivo de configuración en el cual dictaremos los procesos que Docker va a seguir para que nuestra aplicación funcione dentro de un contenedor.

Voy a usar el mismo repositorio del tutorial anterior modificando y agregando ciertos archivos que van a tener información acerca del contenedor que voy a crear, estas modificaciones las van a encontrar en un nuevo branch del repositorio.

Básicamente este repositorio contiene una simple aplicación en NodeJs que sirve un directorio estático que tiene un archivo en formato HTML. El archivo principal y que contiene toda la configuración de un servidor con express se encuentra en API/server.js.

git clone https://github.com/thianlopezz/tuto-node-prod.gitcd tuto-node-prod

Bien una vez hayamos accedido a nuestro repositorio vamos a notar que tenemos 3 archivos nuevos en la raíz: dockerfile, .dockerignore, ecosystem.config.js.

En el archivo dockerfile tendremos toda la configuración para crear una imagen de Docker a partir de una versión en especifico de NodeJs y demás configuraciones que se detallan en los comentarios de este archivo.

En el archivo .dockerignore simplemente se definen los directorios o archivos que debemos ignorar en los procesos que vamos a realizar con Docker.

Y por último tenemos el archivo ecosystem.config.js que es el archivo que contendrá todas las configuraciones que necesitamos para ejecutar nuestra aplicación con PM2. Y antes de avanzar hablemos un poco de PM2.

PM2

PM2 es una herramienta para ambientes de producción de aplicaciones de NodeJs, básicamente esta herramienta nos va a servir para levantar nuestra aplicación como un servicio demonio dentro de nuestro contenedor, aparte nos ayudará a que nuestra aplicación este siempre arriba en caso de que se produzca un error, con PM2 también podemos configurar variables de ambiente y es aquí donde usaremos el archivo ecosytem.config.js.

Creando una imagen de Docker a partir de un dockerfile

En la raíz de nuestro repositorio vamos a ejecutar el siguiente comando:

sudo docker build -t <nuestro_nombre_de_usuario>/<nombre_imagen> .

En mi caso puntual ejecutaré:

sudo docker build -t thianlopezz/tuto-node-prod .

Lo que hemos hecho con este comando es crear una imagen de Docker a partir de la configuración que hemos especificado en nuestro dockerfile.

Una imagen en Docker es una especie de plantilla de un contenedor, es decir que a través de una imagen vamos a poder crear varios contenedores.

Podemos ver la imagen que hemos creado con el comando:

sudo docker images

Este comando va a enlistar todas las imágenes que tenemos en nuestro SO.

Creando un contenedor a partir de una imagen

Tenemos lista nuestra imagen y ahora nos toca crear un contenedor a partir de esta, para hacer esto ejecutamos el siguiente comando:

sudo docker run -p <puerto_so>:<puerto_app> -d <nuestro_nombre_de_usuario>/<nombre_imagen> --name <nombre_contenedor>

Expliquemos un poco el comando que vamos a ejecutar, el comando se llama run y un primer parámetro que vamos a indicar es -p el cual configura una redirección de uno o varios puertos de nuestro sistema operativo hacia un puerto dentro de nuestro contenedor, en nuestro caso vamos a hacer que cuando alguien haga una petición al puerto 5002 de nuestro sistema operativo este redirija al puerto 5002 dentro del contenedor que va a tener mi aplicación, recuerda que la aplicación de NodeJs con la que estamos trabajando está configurada para que se sirva en este puerto. Como segundo parámetro tenemos -d el cual va a indicar a partir de que imagen vamos a crear el contenedor. Y por último tenemos — name el cual indica el nombre que va a tener nuestro contenedor.

En mi caso este comando quedaría de la siguiente manera:

sudo docker run -p 5002:5002 --name tuto-node-prod -d thianlopezz/tuto-node-prod

La configuración que definimos con -p se puede traducir de la siguiente manera: cuando se acceda al puerto 5002 de nuestro sistema operativo automáticamente se redirige al puerto 5002 de nuestro contenedor.

Podemos ver los contenedores que tenedores que están activos con el comando:

sudo docker ps

Si no aparece tu contenedor pudo haber pasado algo durante el script anterior podemos ver todos los contenedores (activos e inactivos) con el comando:

sudo docker ps --all

En caso de que tu contenedor aparezca con inconvenientes podemos ejecutar el siguiente comando para ver los logs de que generó el contenedor:

sudo docker logs tuto-node-prod

Por último no olvides configurar en la consola de Amazon para que el puerto configurado para nuestra contenedor pueda ser accedido.

Si todo se realizó de manera correcta, podemos acceder a la IP de nuestro servidor junto con el puerto que hemos configurado hacia nuestro contenedor a través del navegador y debería de arrojarnos el siguiente resultado:

Y si bien ya tenemos nuestra página web en línea, no podemos de dejar de configurar Nginx para que funciones como reverse proxy.

Nginx

Es recomendable usar un Reverse Proxy, lo haremos con Nginx para que básicamente haga lo siguiente:

Nos va a ayudar para que nuestra aplicación no sea accedida directamente desde el tráfico de internet, sino que pase por Nginx y este se encargue de poner en ruta la petición al puerto que se configure, de esta manera también optimizamos el uso de nuestro servidor, si quieres saber más este post esta muy bueno.

Acá vamos a configurar Nginx desde un contenedor en nuestro Docker y para hacerlo necesitamos hacer un pull de la imagen de Nginx desde DockerHub.

Ejecutamos el siguiente comando:

sudo docker pull nginx

Ejecutado:

sudo docker images

Debería darnos el siguiente resultado, y vemos a ngnix entre las imagenes que ahora tenemos.

Ahora, de la misma manera que hicimos con la imagen de nuestra aplicación, vamos a crear un contenedor a partir de la imagen que hemos descargado ejecutando:

sudo docker run --name nginx -p 80:80 -p 443:443 -d nginx

Las peticiones que se harán hacia el puerto 80 o 443 van a llegar hacia nuestro contenedor que tiene Nginx, luego este va a hacer una redirección hacia nuestro contenedor.

Y si todo es correcto y enlistamos los contenedores activos tendríamos un contenedor nuevo que se llama Nginx.

Networking en Docker

Cuando creamos contenedores, Docker arma una especie de red para que los contenedores puedan verse entre si, asignándoles a cada uno una dirección IP dentro de la red, la red por defecto que crea Docker se llama Bridge, también podemos crear varias otras redes según nuestras necesidades.

En este punto del proceso necesitamos tener la IP que se ha asignado a nuestro contenedor. para lo cual vamos a ejecutar el siguiente comando:

sudo docker inspect tuto-node-prod

Y en el apartado de Networks.bridge.IPAdress copiamos la IP del contenedor y de momento vamos a guardarla en un lugar seguro para proceder a usarla más tarde.

Configuración del container de Nginx

Ahora debemos configurar nuestro contenedor Nginx. Para esto vamos a acceder al shell de este contenedor ejecutando en nuestro sistema operativo:

sudo docker exec -it nginx /bin/sh

Exec va a hacer que ejecutemos el shell de nuestro contenedor.

Una vez dentro del contenedor vamos a instalar el paquete nano para poder editar los archivos de configuración de Nginx:

apt-get updateapt-get -y install nano

Instalado este paquete accedemos a editar el archivo /etc/nginx/nginx.conf:

nano /etc/nginx/nginx.conf

Y agregamos la siguiente configuración:

Y bien no olviden que en esta configuración en las líneas 12 y 13 debemos especificar el path donde se alojan nuestros certificados SSL, si deseas tener un certificado gratuito te recomiendo que sigas este tutorial. Estos certificados deben estar dentro de nuestro contenedor por lo que nos vemos en la necesidad de crear un directorio y mover nuestro archivos .crt y .key a este directorio para luego especificarlo en estas líneas. Podemos mover archivos desde nuestro sistema operativo host a nuestro contenedor con el comando cp de Docker.

sudo docker cp <path_to_file>/filenam.ext <container_name_nginx>:<destination_path>

Luego en la línea 26 cambiar 127.0.0.1 a la IP que habíamos guardado en nuestro lugar seguro, la IP asignada a nuestro contenedor que tiene nuestra aplicación.

Verificamos que la configuración que acabamos de hacer se encuentre correcta con:

nginx -t

Y luego reiniciamos el servicio con:

nginx -s reload

Y bien si hicimos todo de manera correcta debemos estar listos, lo único que necesitamos ahora es configurar las reglas de acceso en AWS para que podamos acceder a los puertos 80 y 443 para que Nginx haga su trabajo.

Conclusiones

Docker es una tecnología que llegó para quedarse, en este tutorial hemos aprendido un caso de uso bastante práctico para esta tecnología, un caso práctico de muchas otras posibilidades, te recomiendo que no te quedes solo con estos conceptos y vayas a aprender más. Docker salió hace un tiempo y lo siguiente es Kubernetes que es lo que aspiro aprender en un corto plazo.

Espero que toda esta información te haya servido tanto como a mi, comenta si tienes algún inconveniente o para contarme como te fue. Nos vemos y Happy coding!

--

--