¿Te imaginas ejecutar tu aplicación en cualquier lugar sin preocuparte por el entorno? Docker lo hace posible. Primero vamos a conocer qué es Docker, por qué es tan popular entre desarrolladores y DevOps, y cómo puedes dockerizar tu primera app con Node.js.
¿Qué es docker?
Docker es una plataforma que permite crear, ejecutar y gestionar aplicaciones dentro de contenedores. Estos contenedores tienen la característica de ser ligeros, portables y tener todo lo necesario para que nuestra app pueda ejecutarse (código, dependencias, config, etc).
Y sí, el problema de “en mi máquina si funciona” se acaba hoy.
Conceptos clave
Imágenes
Las imágenes en docker son plantillas que nos permiten montar contenedores. Contienen lo que necesita nuestro aplicativo: sistema operativo base, dependencias, archivos, comandos de ejecución…
Contenedores
Un contenedor es una instancia de nuestra imagen. Un contenedor ejecuta tu aplicación como si estuviera dentro de un propio minisistema.
Docker Hub
Así como GitHub y sus proyectos públicos, lo mismo pero diferente. Imágenes públicas listas para usar, tienes a tu disposición bases de datos, lenguajes de programación, sistemas de CI/CD… Y adivina qué, puedes subir tus propias imágenes y que se encuentren disponibles de manera pública.
Dockericemos algo
Haremos este tutorial con la aplicación Hello World que escribimos el otro día.
En la raíz de nuestra aplicación debemos crear un archivo Dockerfile. Este archivo no tiene extensión
FROM node:22
La palabra FROM define que imagen usaremos de base para la construcción de nuestro contenedor. ¿Pero de que va? Recuerda que tu aplicación está hecha en Node.js y node utiliza npm como gestor de paquetes. Si tu aplicación estuviera escrita en java o C# tendríamos que cambiar la imagen base para poder compilar nuestro código.
Docker descargará automáticamente la imagen (si es que encuentra alguna) desde Docker Hub, puedes también añadir otros repositorios pero eso será más adelante 😉
Si quieres utilizar otras versiones de node debes darle un vistazo a las imágenes disponibles, en este ejercicio elegí node 22 porque es la que tengo instalado localmente y veo que mi aplicación funciona bien con esta versión.
WORKDIR /app
Esta línea de código establece el directorio de trabajo del contenedor.
Es el equivalente a un cd /app. Las siguientes instrucciones que ejecutes serán dentro de esta carpeta (no te preocupes, docker la crea automáticamente)
COPY package*.json ./
Esto copia los archivos package.json y package-lock.json desde tu máquina. Estos tienen la información necesaria de que dependencias tiene tu proyecto.
RUN npm install
Esto instala las dependencias dentro de nuestro contenedor.
COPY . .
Esto copiará todo el contenido del proyecto (carpetas y subcarpetas también) a la ruta app
No sobreescribirá node_modules, estos ya docker los está manejando.
EXPOSE 3000
Recuerda que nuestra aplicación se ejecutaba en el puerto 3000. Debemos especificarlo dentro de la imagen de docker para que este se encuentre disponible para recibir tráfico.
CMD ["npm", "start"]
Tenemos que especificar que comando levantará nuestra aplicación, en este caso al ser una app node.js tenemos comandos que levantan nuestra aplicación desde la parte de package.json.
Ejecutemos nuestro contenedor
Para ejecutar nuestro contenedor es necesario primero guardar esta imagen, lo recomendable es utilizar un tag para poder versionarlo con facilidad.
Ejecuta el siguiente comando en la carpeta donde tienes tu Dockerfile
docker build -t leocorp/node-server .
Ya tenemos guardada de manera local nuestra imagen, ya podemos ejecutarla. En este caso estamos ejecutando nuestra imagen haciendo una redirección de puertos, en nuestro ordenador estamos utilizando el puerto 8080 y lo dirigimos al puerto 3000 dentro del contenedor.
docker run -p 8080:3000 leocorp/node-server
Has tus propias pruebas y ejecuta tus contenedores en diferentes puertos! no es necesario eliminar las anteriores.
Conclusiones
Ya hemos creado nuestra primera imagen docker.
Docker cache: La forma en la que copiamos los archivos de nuestra aplicación (primero package y luego todo lo demás) permite que docker no reinstale siempre las dependencias cada vez que el código cambia.
Docker brinda una gran cantidad de funcionalidades, nos falta conversar sobre volúmenes, redes, variables de entorno y demás… Hey pero este ha sido un gran avance, ya has dado tu primer paso en el mundo DevOps!