Desarrollo de aplicaciones Node.js y Express.js con Docker
Tags: docker, devops, beginners, tutorial
Published: 2019-09-18 17:42:02

---
title: Desarrollo de aplicaciones Node.js y Express.js con Docker
published: true
description: Serie de artículos sobre Docker y Contenedores.
tags: docker, devops, beginners, tutorial
series: Aprenda Docker - Zero to Hero (Español)
---

[![docker.png](https://i.postimg.cc/7LZsn8Tc/docker.png)](https://postimg.cc/VJ2WzhgB)

_artículo escrito originalmente por Chris Noring - **[AQUI](https://dev.to/softchris/5-part-docker-series-beginner-to-master-3m1b)**_

En el **[último artículo](https://dev.to/azure/introduccion-a-docker-conceptos-basicos-51id)** 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:

```bash
> npm init -y
```

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

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

```json
{
  "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"
  }
}
```

Si desea desarrollar el código fuente, creé un repositorio en GitHub. En este caso, solo descargar todo el proyecto **[AQUÍ](https://github.com/glaucia86/docker-zero-to-hero-series)**

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](https://i.postimg.cc/76GrVVHy/Screen-Shot-07-05-19-at-03-40-PM.png)](https://postimg.cc/cgSz1ftD)

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

```bash
> npm install
```

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:


```javascript
/**
 * 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);
```

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](https://i.postimg.cc/cHq3mdw1/Screen-Shot-07-05-19-at-04-30-PM.png)](https://postimg.cc/Z9c0YtwX)

¡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:

```bash
WORKDIR /app

COPY . .

RUN npm install

EXPOSE 3000

ENTRYPOINT ["node", "app.js"]
```

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 !!! **)

```bash
> docker build -t exemplo-2-node-docker/node:latest .
```

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](https://s3.gifyu.com/images/gif-3d3a08bc2e12687ca.gif)](https://gifyu.com/image/EJJm)

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:

```bash
> docker images
```

[![Screen-Shot-07-05-19-at-08-08-PM.png](https://i.postimg.cc/fRRytsMP/Screen-Shot-07-05-19-at-08-08-PM.png)](https://postimg.cc/dLgwpzkR)

¡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:

```bash
> docker run -p 8000:3000 exemplo-2-node-docker/node
```

¿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:

```bash
-p [puerta externa]:[puerta interna]
```

Vea en gif la ejecución del comando anterior:

[![gif-4.gif](https://s3.gifyu.com/images/gif-4.gif)](https://gifyu.com/image/EltG)

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

```bash
> docker container ls 
```

2. Luego copie el ** Id ** del contenedor y ejecute el siguiente comando:

```bash
> docker kill <Id do Container>
```

Vea el GIF:

[![gif-5.gif](https://s3.gifyu.com/images/gif-5.gif)](https://gifyu.com/image/El5b)

## 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:

```bash
FROM node:latest

WORKDIR /app

COPY . .

ENV PORT=3000

RUN npm install

EXPOSE 3000

ENTRYPOINT ["node", "app.js"]
```

¡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:

```bash
FROM node:latest

WORKDIR /app

COPY . .

ENV PORT=3000

RUN npm install

EXPOSE $PORT

ENTRYPOINT ["node", "app.js"]
```

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 `$`

```bash
> EXPOSE $PORT
```

## 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:

```bash
> process.env.PORT
```

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

```javascript
/**
 * 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}`);
```

Tenga en cuenta que cuando realizamos el cambio al archivo `app.js` o al archivo` Dockerfile`, 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:

```bash
> docker stop
```

```bash
> docker rm
```

¡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:

```bash
> docker ps
```

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](https://i.postimg.cc/C1SScXVN/Screen-Shot-08-03-19-at-04-41-PM.png)](https://postimg.cc/Y4n59X0G)

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í:

```bash
> docker stop 3da
```

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. 

```bash
> docker run -d -p 8000:3000 exemplo-2-node-docker/node
```

[![Screen-Shot-08-03-19-at-04-56-PM.png](https://i.postimg.cc/BbvgBS7G/Screen-Shot-08-03-19-at-04-56-PM.png)](https://postimg.cc/bDKkzhj6)

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:

```bash
> docker stop 014 
```

## 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:

```bash
> docker rm <id-do-contêiner>
```

Ejemplo:

```bash
> docker rm -f ef8
```

```bash
> docker ps
```

## 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](https://docs.microsoft.com/es-es/learn/modules/intro-to-containers/?WT.mc_id=devto-blog-gllemos)**

**[Otros Cursos Grátis de Docker](https://docs.microsoft.com/es-es/learn/browse/?term=docker&WT.mc_id=devto-blog-gllemos)**

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

[![Twitter](https://code4coders.files.wordpress.com/2019/05/image-12.png)](https://twitter.com/glaucia_lemos86)

Y sigan al Chris Noring también! 

[![Screen-Shot-08-03-19-at-05-14-PM.png](https://i.postimg.cc/kGDD7GgG/Screen-Shot-08-03-19-at-05-14-PM.png)](https://postimg.cc/4HkX5JtR)

Hasta pronto!