DEV Community

loading...
Microsoft Azure

Desarrollo de aplicaciones Node.js y Express.js con Docker

glaucia86 profile image Glaucia Lemos Updated on ・11 min read

docker.png

artículo escrito originalmente por Chris Noring - AQUI

En el último artículo vimos y aprendimos conceptos básicos sobre Docker, imágenes y contenedores. Ahora es el momento de desarrollar una aplicación y aprender en código cómo usar Docker en una aplicación.

¡¿Aquí vamos?!

¡Comencemos a codificar!

Ahora que entendemos qué es Docker y por qué deberíamos usarlo, ¡ahora es el momento en que debemos practicar el uso de Docker en alguna aplicación!

Bueno, necesitaremos un archivo que se utiliza mucho en Docker: DockerFile. Porque es en el archivo DockerFile, especificaremos todo lo que necesitaremos con respecto al sistema operativo, las variables de entorno y cómo ejecutar nuestra aplicación.

Vamos a profundizar en esta parte ahora. A través de este archivo ejecutaremos nuestra aplicación dentro de un contenedor aislado del mundo exterior, pero disponible para otros puertas (ports).

Vamos a tomar los siguientes pasos:

  • Crear una aplicación en Node.js

Desarrollemos una aplicación Node.js con Express. Funciona como una API REST.

  • Crear el archivo 'Dockerfile'

Este archivo será responsable de decirle a Docker cómo construir nuestra aplicación.

  • Crear una imagen

Para que nuestra aplicación funcione, debemos crear una imagen llamada Docker.

  • Crear un contenedor

Y, por último, veremos nuestra aplicación en funcionamiento y crearemos un contenedor a partir de una imagen de Docker.

Vamos a seguir estos pasos ahora?!

Creación la Aplicación Node.js y Express con Docker

Ahora abra su Visual Studio Code, cree una carpeta llamada: example-2 y dentro de esa carpeta escriba el siguiente comando:

> npm init -y
Enter fullscreen mode Exit fullscreen mode

Este comando crea para nosotros un archivo llamado: package.json.

Al final, el archivo package.json tendrá el siguiente aspecto:

{
  "name": "exemplo-2",
  "version": "1.0.0",
  "description": "Código do exemplo do artigo: Introdução a Docker - Parte I",
  "main": "app.js",
  "scripts": {
    "dev": "nodemon",
    "lint": "eslint --ext .js,.html -f ./node_modules/eslint-friendly-formatter . --fix",
    "prepush": "npm run lint",
    "start": "node app.js"
  },
  "keywords": [
    "nodejs",
    "javascript",
    "docker",
    "azure",
    "express"
  ],
  "author": "Glaucia Lemos",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/glaucia86/docker-zero-to-hero-series/issues"
  },
  "homepage": "https://github.com/glaucia86/docker-zero-to-hero-series/blob/master/README.md",
  "devDependencies": {
    "eslint": "^5.16.0",
    "eslint-config-airbnb-base": "^13.1.0",
    "eslint-plugin-import": "^2.17.3",
    "husky": "^2.3.0",
    "nodemon": "^1.19.1"
  },
  "dependencies": {
    "eslint-friendly-formatter": "^4.0.1",
    "eslint-plugin-html": "^5.0.5",
    "express": "^4.17.1"
  }
}
Enter fullscreen mode Exit fullscreen mode

Si desea desarrollar el código fuente, creé un repositorio en GitHub. En este caso, solo descargar todo el proyecto AQUÍ

Bueno, vamos a crear dentro de la carpeta example-2 el archivo app.js y luego el archivo Dockerfile

Al final, la estructura del proyecto será la siguiente:

Screen-Shot-07-05-19-at-03-40-PM.png

Ahora, dentro de la carpeta exemplo-2, ejecute el siguiente comando:

> npm install
Enter fullscreen mode Exit fullscreen mode

Este comando instalará todas las dependencias necesarias para nuestro proyecto y creará una carpeta llamada node_modules

Genial ¡Ahora comencemos a desarrollar!

Desarrollando el archivo 'App.js'

Después de crear la estructura del proyecto e instalar las dependencias necesarias en nuestra aplicación, abramos el archivo app.js y agreguemos el siguiente código:

/**
 * Arquivo: app.js
 * Descrição: arquivo principal e responsável pela execução da aplicação.
 * Data: 05/07/2019
 * Author: Glaucia Lemos
 */

const express = require('express');

const app = express();

const port = process.env.PORT || 3000;

app.get('/', (req, res) => {
  res.status(200).send({
    success: 'true',
    message: 'Seja Bem-Vindo(a) ao mundo Docker!',
    version: '1.0.0',
  });
});

app.listen(port);
console.log('Aplicação executando na porta ', port);
Enter fullscreen mode Exit fullscreen mode

Ahora vaya al prompt command y ejecute el comando: nodemon y luego abra el Postman y escriban en la url: http://localhost:3000/ y vean si Api está funcionando:

Screen-Shot-07-05-19-at-04-30-PM.png

¡Si el mensaje aparece como en la imagen de arriba es porque todo funciona perfectamente! ¡Continuemos con nuestro tutorial!

Desarrollando el archivo 'Dockerfile'

Vamos ahora crear el archivo Dockerfile. Este archivo es como un manifiesto, donde tiene todas las instrucciones necesarias para compilar y ejecutar nuestra aplicación. Pero, ¿qué se requiere para ejecutar la aplicación a través de Dockerfile? Necesitaremos:

  • copiar todos los archivos de la aplicación a través del contenedor docker.

  • instalar las dependências.

  • abrir una puerta en el contenedor al que se accederá, por así decirlo, en el exterior.

  • instruir al contenedor cómo iniciar nuestra aplicación

En una aplicación más compleja, necesitamos informar más cosas, como establecer variables de entorno o establecer credenciales para una base de datos o ejecutar una base de datos particular, entre otros puntos. Sin embargo, como esta es una aplicación simple, creemos Dockerfile de una manera muy simple:

WORKDIR /app

COPY . .

RUN npm install

EXPOSE 3000

ENTRYPOINT ["node", "app.js"]
Enter fullscreen mode Exit fullscreen mode

Ahora entendamos lo que hace cada comando:

  • FROM Aquí estamos seleccionando una imagen del sistema operativo Docker Hub. Docker Hub es un repositorio global que contiene imágenes que podemos extraer localmente. En nuestro caso, estamos eligiendo una imagen basada en Ubuntu que tenga instalado Node.js, llamado node. También especificamos una versión más nueva de Node.js usando la siguiente etiqueta: latest

  • WORKDIR aquí simplemente significa que definimos un directorio de trabajo. Esta es una forma de configurar lo que sucederá más adelante en el siguiente comando abajo.

  • COPY Aquí estamos copiando los archivos del directorio donde estamos especificando un directorio a través de este comando.

  • RUN Aquí ejecutaremos un comando en la terminal. En nuestro caso, instalaremos todas las bibliotecas que necesitamos para desarrollar nuestra aplicación Node.js con Express.

  • EXPOSE aquí significa que abriremos cierta puerta (port). Y es a través de esta puerta que nos comunicamos con nuestro contenedor.

  • ENTRYPOINTS Aquí es donde debemos indicar cómo comenzaremos nuestra aplicación. Los comandos deben especificarse como una matriz, por ejemplo: ["node", "app.js"]. Es como si nos encontramos con el comando en el terminal: 'node app.js'

Creando una Imagen

Para crear una imagen, debemos seguir 2 pasos, que son:

  • Creando una imagen:* con la ayuda del archivo 'Dockerfile' y el comando docker build crearemos una imagen

  • Iniciar el contenedor*

Ahora que tenemos una imagen, necesitamos crear un contenedor.

¡Realicemos estos pasos ahora! Abra la carpeta del proyecto ejemplo-2 y ejecute el siguiente comando: (** no olvide ejecutar Docker Desktop !!! **)

> docker build -t exemplo-2-node-docker/node:latest .
Enter fullscreen mode Exit fullscreen mode

Tenga en cuenta que hay un punto (.) al final. ¡Necesita ser incluido para crear nuestra imagen! Porque da instrucciones a Docker y le dice dónde se encuentra Dockerfile, en nuestro caso en el directorio donde se encuentra. Si no tiene la imagen del sistema operativo, le pedimos el comando FROM y nos llevará descargarlo de Docker Hub y finalmente crear la imagen especificada en Dockerfile. En su terminal debe aparecer como en el siguiente gif (dependiendo de la conexión a Internet, este comando puede tardar unos minutos en completarse):

gif-3d3a08bc2e12687ca.gif

Lo que vemos en el gif es cómo la imagen del SO node:latest trae y descarga por medio del Docker Hub. Y luego cada uno de nuestros comandos se ejecuta como WORKDIR,RUN y así sucesivamente. Lo que vemos aquí es que Docker se ejecuta de manera muy inteligente y almacena en caché todas las diferentes capas de archivos después de cada comando para que sea más rápido. Al final, vemos el mensaje: 'construido con éxito' que indica que nuestra imagen fue construida con éxito. Echemos un vistazo y veamos cómo se creó nuestra imagen. Abra el terminal y escriba el siguiente comando:

> docker images
Enter fullscreen mode Exit fullscreen mode

Screen-Shot-07-05-19-at-08-08-PM.png

¡Si aparece como la imagen es porque la imagen se creó con éxito!

Creación de un Contenedor

El siguiente paso es tomar nuestra imagen creada y construir un contenedor de ella. Un contenedor es esta pieza aislada que ejecuta nuestra aplicación en su interior. Creamos un contenedor ejecutando el comando: docker run. Abra el terminal de nuevo y ejecute el siguiente comando:

> docker run -p 8000:3000 exemplo-2-node-docker/node
Enter fullscreen mode Exit fullscreen mode

¿Recuerdas que en el archivo Dockerfile establecemos una puerta (port)? Y ya explicamos en el artículo anterior que necesitamos una asignación de puerto interno a una puerta (port) externo en la máquina host. Recuerde que esta es una aplicación que queremos ejecutar en el navegador. Por lo tanto, debemos mapear de la siguiente manera:

-p [puerta externa]:[puerta interna]
Enter fullscreen mode Exit fullscreen mode

Vea en gif la ejecución del comando anterior:

gif-4.gif

Tenga en cuenta que en el navegador, hay que poner la puerta exterior que en nuestro caso es la puerta: 8000.

Sin embargo, para dejar de ejecutar este contenedor, necesitamos ejecutar algunos comandos:

  1. Primero debemos enumerar los contenedores que se están ejecutando
> docker container ls 
Enter fullscreen mode Exit fullscreen mode
  1. Luego copie el ** Id ** del contenedor y ejecute el siguiente comando:
> docker kill <Id do Container>
Enter fullscreen mode Exit fullscreen mode

Vea el GIF:

gif-5.gif

Mejora de la configuración con variables de entorno

Genial! Ya aprendimos cómo crear nuestra primera imagen de Docker con Node.js & Express, aprendimos a ejecutar un contenedor y finalmente ejecutamos nuestra aplicación usando el archivo DockerFile. Sin embargo, podemos mejorar la variable PORT en el archivo DockerFile. Tal como está, será propenso a errores.

Para resolver este problema, podemos incluir una variable de entorno. Con esto, haremos dos cambios:

  • agregar una variable de entorno a Dockerfile
  • leer desde la variable de entorno en el archivo app.js

Agregando una variable de entorno

Para esto necesitamos usar el comando ** ENV **. Abra el archivo DockerFile y cambie de la siguiente manera:

FROM node:latest

WORKDIR /app

COPY . .

ENV PORT=3000

RUN npm install

EXPOSE 3000

ENTRYPOINT ["node", "app.js"]
Enter fullscreen mode Exit fullscreen mode

¡Hagamos un cambio más! Actualicemos la variable EXPOSE ahora, luego eliminaremos los valores estáticos y confiaremos en las variables de la siguiente manera:

FROM node:latest

WORKDIR /app

COPY . .

ENV PORT=3000

RUN npm install

EXPOSE $PORT

ENTRYPOINT ["node", "app.js"]
Enter fullscreen mode Exit fullscreen mode

Tenga en cuenta que cambiamos el comando EXPOSE a $PORT. Un punto muy importante aquí: cualquier variable que usemos debe tener como prefijo un carácter $

> EXPOSE $PORT
Enter fullscreen mode Exit fullscreen mode

Leyendo el valor de la variable de entorno en el archivo App.js

Podemos leer los valores de las variables de entorno en Node.js de la siguiente manera:

> process.env.PORT
Enter fullscreen mode Exit fullscreen mode

Así que vamos a actualizar el archivo app.js:

/**
 * Arquivo: app.js
 * Descrição: arquivo principal e responsável pela execução da aplicação.
 * Data: 05/07/2019
 * Author: Glaucia Lemos
 */

const express = require('express');

const app = express();

const port = process.env.PORT;

app.get('/', (req, res) => {
  res.status(200).send({
    success: 'true',
    message: 'Seja Bem-Vindo(a) ao mundo Docker!',
    version: '1.0.0',
  });
});

app.listen(port);
console.log(`Aplicação executando na porta..: ${port}`);
Enter fullscreen mode Exit fullscreen mode

Tenga en cuenta que cuando realizamos el cambio al archivo app.js o al archivoDockerfile, necesitamos reconstruir nuestra imagen. Esto significa que necesitamos ejecutar el comando de compilación de Docker nuevamente, y antes de eso debemos parar nuestro contenedor con los comandos:

> docker stop
Enter fullscreen mode Exit fullscreen mode
> docker rm
Enter fullscreen mode Exit fullscreen mode

¡Aprenderemos un poco más sobre estos dos comandos más adelante! 😉

Administrando el contenedor

Bueno! Acaba de iniciar su contenedor y se da cuenta de que no finaliza / cierra la ejecución en el terminal. ¡Ahí es donde golpea el pánico! 😳😳

En este caso, puede hacer lo siguiente, abrir otra ventana de terminal y ejecutar el siguiente comando:

> docker ps
Enter fullscreen mode Exit fullscreen mode

Este comando enumerará todos los contenedores que se ejecutan en su máquina. Puede ver el nombre de los contenedores y sus Id's de la siguiente manera:

Screen-Shot-08-03-19-at-04-41-PM.png

Como puede ver, tenemos la columna CONTAINER_ID y la columna NAMES. Ambos valores funcionarán para romper nuestro contenedor, porque eso es lo que tenemos que hacer, así:

> docker stop 3da
Enter fullscreen mode Exit fullscreen mode

Elegimos usar la columna CONTAINER_ID y solo necesitamos ingresar los primeros 3 dígitos sin tener que incluir el ID completo. Después de ejecutar este comando, tenga en cuenta que después de escribir docker ps no aparecerán más contenedores y dejará de ejecutar nuestra imagen.

Modo Daemon

Podemos hacer lo que hicimos anteriormente y abrir una nueva terminal separada. Sin embargo, se ejecuta en Modo Daemon, que en este caso es la mejor opción. Esto significa que ejecutaremos el contenedor en segundo plano y toda su salida no será visible. Para que esto suceda, simplemente agregue el flag -d.

> docker run -d -p 8000:3000 exemplo-2-node-docker/node
Enter fullscreen mode Exit fullscreen mode

Screen-Shot-08-03-19-at-04-56-PM.png

Tenga en cuenta que ahora tenemos el ID del contenedor. ¡Ahora es más fácil dejar de correr! Simplemente ingrese los primeros 3 dígitos del ID. Ejemplo:

> docker stop 014 
Enter fullscreen mode Exit fullscreen mode

Docker kill vs Docker stop

Hasta ahora hemos utilizado el comando docker stop como una forma de detener el contenedor. Sin embargo, hay otra forma de detener el contenedor, es decir, ejecutando el comando docker kill. Pero cual es la diferencia?

  • ** docker stop : este comando envía la señal **SIGTERM seguida de SIGKILL después de un periodo de carencia. En resumen, esta es una forma de reducir el tamaño del contenedor de manera más elegante, lo que significa que libera recursos y ahorra estado.

  • docker kill: este comando envía SIGKILL inmediatamente. Esto significa que la liberación de recursos o el ahorro de estado pueden no funcionar según lo previsto. En desarrollo, no importa cuál de los dos comandos se esté utilizando, pero en un escenario de producción es más prudente confiar en el comando docker stop.

Limpieza de los contenedores

En algún momento, durante el desarrollo de la aplicación, eventualmente creará numerosos contenedores. Entonces, para asegurarse de eliminar / limpiar estos contenedores, simplemente escriba el comando:

> docker rm <id-do-contêiner>
Enter fullscreen mode Exit fullscreen mode

Ejemplo:

> docker rm -f ef8
Enter fullscreen mode Exit fullscreen mode
> docker ps
Enter fullscreen mode Exit fullscreen mode

Conclusión

Aprendimos en este artículo cómo crear una aplicación Node.js & Express.js usando Docker de manera práctica y paso a paso. Aprendimos algunos comandos importantes de Docker y eso no se detendrá aquí. Porque aún tendremos muchas cosas importantes que aprender, como cómo trabajar con bases de datos, volúmenes, cómo vincular contenedores y por qué y cómo administrar múltiples contenedores, también conocido como orquestación.

¡Pero esta es una serie de artículos! Y tenemos que parar en algún lado o este artículo será muy largo. Estén atentos y vean la siguiente parte, donde hablaremos sobre Volúmenes y Bases de datos.

Si desea aprender y estudiar más Docker, le recomiendo los siguientes cursos de Docker:

Curso Grátis - Compilación de una aplicación web en contenedores con Docker

Otros Cursos Grátis de Docker

Y para saber esta y otras novedades, ¡sígueme en twitter!

Twitter

Y sigan al Chris Noring también!

Screen-Shot-08-03-19-at-05-14-PM.png

Hasta pronto!

Discussion

pic
Editor guide