Copiar enlace

Configurando Docker Compose con Nodejs y MySQL

En este tutorial aprenderás a configurar una aplicación Backend de Nodejs y una base de datos de MySQL, cada uno en su propio contenedor de Docker y comunicandose a traves de Docker Compose, todo desde cero y paso a paso.

Requerimientos para el tutorial

  • Tener instalado Docker
  • Tener intalado Nodejs

Tambien es recomendado haber usado previamente el contenedor de mysql para entener mejor como unirlos a otros contenedores, sin embargo no es un requerimiento e igual será explicado.

Configuracion del proyecto de Backend

Primero vamos a crear un proyecto de ejemplo de Backend en Nodejs:

mkdir nodejs-mysql-docker
cd nodejs-mysql-docker

Abrelo con Visual Studio Code o tu editor favorito:

code .

Luego vamos a inicializar un proyecto de Node:

npm init -y 

Instalaremos tambien los modulos principales

npm i express mysql2 dotenv

En este ejemplo, se utilizarán los siguientes paquetes:

  • express: Express es un framework Backend minimalista y flexible de Node.js que proporciona un conjunto sólido de características para aplicaciones web y móviles. Se utiliza para construir aplicaciones web, REST APIs y para configurar rutas, middlewares, y manejar solicitudes HTTP.
  • mysql2: MySQL2 es un módulo de Node.js que proporciona una implementación del cliente MySQL. Permite a las aplicaciones Node.js interactuar con bases de datos MySQL, realizando consultas y gestionando la base de datos. Ofrece una mejorada compatibilidad con MySQL, mejor rendimiento y soporte para Promesas.
  • dotenv: Dotenv es un módulo de Node.js que permite cargar variables de entorno desde un archivo .env en process.env. Es útil para manejar configuraciones específicas del entorno, como credenciales de bases de datos y claves de API, sin tener que incluirlas directamente en el código.

Luego tambien instalaremos un modulos adicional como dependencia de desarrollo llamado nodemon, este modulo permite reiniciar el codigo cada vez que cambiamos algo.

npm i -D nodemon

Luego vamos a crear un archivo que contendrá todo el proyecto en src/index.js con el siguiente contenido:

import express from 'express'

const app = express()

app.listen(3000)
console.log('Server on port', 3000)

Como en el código anterior estamos usando los Ecmascript Modules (los imports y exports en Javascript) por lo que debemos actualizar nuestro package.json para que use los modulos, ademas tambien crearemos un script para ejecutar en desarrollo con nodemon y en producción con node. Actualiza el codigo del package.json a lo siguiente:

{
  "name": "nodejs-mysql-docker",
  "version": "1.0.0",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "start": "node src/index.js",
    "dev": "nodemon src/index.js"
  },
  "license": "ISC",
  "dependencies": {
    "dotenv": "^16.3.1",
    "express": "^4.18.2",
    "mysql2": "^3.4.1"
  },
  "devDependencies": {
    "nodemon": "^2.0.22"
  }
}

Ahora puedes ejecutar sdes consola los comandos:

  • npm run dev para ejecutar con nodemon el proyecto
  • npm start para ejecutar con node el proyecto

MySQL en Docker compose

Ahora vamos a conectar a nuestra aplicacion de Nodejs a MySQL, y para esto necesitamos tener mysql instalado o tambien podemos usar Docker compose para crear nuestra base de datos.

Primero crea un archivo docker-compose en la raiz del proyecto, con el siguiente codigo:

version: '3.8'

services:
  mysqldb:
    image: mysql
    environment:
      - MYSQL_ROOT_PASSWORD=123456
      - MYSQL_DATABASE=fazt_db
    ports:
      - 3307:3306

Esto creara un contenedor de mysql con un usuario root con una contraseña 123456 y con una base de datos llamada fazt_db, ejecutandose internamente en el puerto 3306 y desde nuestro computador en el puerto 3307.

Por lo general veras muchas configuraciones de puerto con 3306:3306 pero para que se entienda mejor la diferencia he decidido cambiar el puerto expuesto.

Para probar la conexion a tu base de datos puedes usar Clientes de MySQL como Dbeaver, HeidiSQL o MySQL Workbench.

Conexión de Nodejs con Mysql

Ahora que ya tenemos a MySQL ejecutandose vamos a conectar Nodejs con MySQL.

Actualiza el codigo de src/index.js de esta forma:

import express from "express";
import { createPool } from "mysql2/promise";

const app = express();

const pool = createPool({
  host: "localhost",
  user: "root",
  password: "123456",
  port: 3307,
});

pool.on("connection", () => console.log("DB Connected!"));

app.get("/ping", async (req, res) => {
  const result = await pool.query("SELECT NOW()");
  res.json(result[0]);
});

app.listen(3000);
console.log("Server on port", 3000);

Con este puedes hacer peticiones GET a la ruta http://localhost:3000/api y obtendras como respuesta la fecha del servidor de MySQL.

Nodejs en Contenedor de Docker

Ahora pasemos a crear un contenedor de Nodejs.

Primero crea un archivo Dockerfile en la raiz del proyecto, con el siguiente contenido:

FROM node:18

WORKDIR /myapp
COPY package.json .
RUN npm install

EXPOSE 3000

COPY . .
CMD npm start

Luego actualiza el archivo docker-compose.yml de la siguiente forma:

version: '3.8'

services:
  mysqldb:
    image: mysql
    environment:
      - MYSQL_ROOT_PASSWORD=123456
      - MYSQL_DATABASE=fazt_db
    ports:
      - 3307:3306

  app:
    build: .
    depends_on:
      - mysqldb
    links:
      - mysqldb
    ports:
      - 3000:3000

Luego tendremos que actualizar nuestro archivo de src/index.js porque ahora como nuestro servidor de Nodejs estara conectandose internamente a un servidor de MySQL, los parametros son distintos:

const pool = createPool({
  host: "mysqldb",
  user: "root",
  password: "123456",
  port: 3306,
});

Como puedes ver la diferencia notable es el host que ahora tiene el nombre del servicio de Mysql en docker-compose mysqldb y el puerto es el 3306 debido a que ahora esta en la misma red interna de Docker.

Ahora vamos a ejecutar nuestra nueva configuracion, pero primero vamos a cancelar la ejecucion del contendor anterior presional Ctrl + c dos veces y luego ejecutando:

docker compose down

Seguido de ejecutar docker compose:

docker compose up

Una vez hecho esto ya puedes visistar el http://localhost:300/ping y deberias ver la misma respuesta.

Si obtenes un error como este Error: connect ECONNREFUSED 127.0.0.1:3307 Puede que tus parametros de conexion esten mal escritos, asi que asegurate de colocar los que tienes en docker-compose. O si no reinicia los volumes de Docker para que empiecen desde cero, primero ejecuta docker compose down luego docker volume rm $(docker volume ls -q) y finalmente elimina la imagen anteriores con docker rmi $(docker images -aq) y finalmente ejecuta nuevamente docker compose up

Variables de Entorno

Ahora como tipicamente vamos a querer cambiar las credenciales de usuario y contraseña o puerto vamos a crear un archivo con variables de entorno para que podamos desde un solo lugar actualizar las variables de docker y las variables de nodejs.

crea un archivo .env con el siguiente contenido:

MYSQLDB_HOST=mysqldb
MYSQLDB_ROOT_PASSWORD=123456
MYSQLDB_DATABASE=fazt_db

MYSQLDB_LOCAL_PORT=3307
MYSQLDB_DOCKER_PORT=3306

NODE_LOCAL_PORT=3000
NODE_DOCKER_PORT=3000

Y luego actualizaremos el archivo docker a lo siguiente:

version: '3.8'

services:
  mysqldb:
    image: mysql
    env_file: ./.env
    environment:
      - MYSQL_USER=$MYSQLDB_USER
      - MYSQL_PASSWORD=$MYSQLDB_PASSWORD
      - MYSQL_ROOT_PASSWORD=$MYSQLDB_ROOT_PASSWORD
      - MYSQL_DATABASE=$MYSQLDB_DATABASE
    ports:
      - $MYSQLDB_LOCAL_PORT:$MYSQLDB_DOCKER_PORT
  app:
    build: .
    depends_on:
      - mysqldb
    links:
      - mysqldb
    env_file: ./.env
    ports:
      - $NODE_LOCAL_PORT:$NODE_DOCKER_PORT

ademas que tambien el archivo de nodejs:

import express from "express";
import { createPool } from "mysql2/promise";
import {config} from 'dotenv'
config()

const app = express();

const pool = createPool({
  host: process.env.MYSQLDB_HOST,
  user: 'root',
  password: process.env.MYSQLDB_ROOT_PASSWORD,
  port: process.env.MYSQLDB_DOCKER_PORT,
});

pool.on("connection", () => console.log("DB Connected!"));

app.get("/ping", async (req, res) => {
  const result = await pool.query("SELECT NOW()");
  res.json(result[0]);
});

app.listen(process.env.NODE_DOCKER_PORT || 3000);
console.log("Server on port", process.env.NODE_DOCKER_PORT || 3000);

A partir de aqui puedes visitar la misma ruta /ping y obtener la misma respuesta. Y listo ya tienes tu proyecto configurado con docker-compose.

Creación de multiples entornos de desarroll

ahora vamos a crear dos entornos para desarrollar y ejecutar en producción:

actualiza el Dockerfile de la siguiente forma:

CMD npm run dev

añade esto al servicio app en docker-compose:

    volumes:
      - .:/myapp
    command: sh -c "npm install && npm run dev"

Luego crearemos un nuevo archivo docker-compose.prod.yml con el siguiente contenido:

version: "3.8"

services:
  mysqldb:
    image: mysql:5.7
    env_file: ./.env
    environment:
      - MYSQL_USER=$MYSQLDB_USER
      - MYSQL_PASSWORD=$MYSQLDB_PASSWORD
      - MYSQL_ROOT_PASSWORD=$MYSQLDB_ROOT_PASSWORD
      - MYSQL_DATABASE=$MYSQLDB_DATABASE
    ports:
      - $MYSQLDB_LOCAL_PORT:$MYSQLDB_DOCKER_PORT
    logging:
      driver: none

  app:
    depends_on:
      - mysqldb
    links:
      - mysqldb
    build: .
    # restart: unless-stopped
    env_file: ./.env
    ports:
      - $NODE_LOCAL_PORT:$NODE_DOCKER_PORT
    environment:
      - DB_HOST=$MYSQLDB_HOST
      - DB_USER=$MYSQLDB_USER
      - DB_PASSWORD=$MYSQLDB_PASSWORD
      - DB_NAME=$MYSQLDB_DATABASE
      - DB_PORT=$MYSQLDB_DOCKER_PORT

Ahora debemos usar este comando en el archivo Dockerfile:

CMD npm start

y puedes ejecutarlo con el comando

docker compose -f docker-compose.prod.yml up --build

Tambien puedes añadir un archivo .dockerignore con el siguiente contenido:

node_modules

Comandos utiles

Estos son algunos comandos utiles para usar con Docker compose

  • docker compose up
  • docker compose up -d
  • docker compose up --build
  • docker compose up --build -d
  • docker compose stop
  • docker compose rm
  • docker compose down
  • docker volume ls
  • docker volume ls -q
  • docker volume rm <container_id>
  • docker volume rm $(docker volume ls -q)

Posibles Errores de Docker Compose con MySQL

  • Error de conexion de MySQL, Este es una respuesta de stack overflow a un erro de conexion de mysql desde un Contenedor de docker a un Contenedor de Nodejs, el asunto es que si configuras mal la base de datos inicialmente, y luego lo cambias, este ya creo un volumen con una configuración por defecto, asi que la solucion que menciona aqui es eliminar el volumen, sin embargo puede que no sepas cual es, asi que la solucion es ejecutar el siguiente comando que elimina todos los volumes: docker volume rm $(docker volume ls -q) Luego puedes ejecutar tu tipico comando docker compose up y deberia funcionar leyendo tu configuracion nueva. Esta solucion fue obtenida de esta respuesta

Más Recursos

Actualizado por ultima vez el

Configura un proyecto de Nodejs y MySQL con Docker Compose desde cero

¿Quieres Compatir mi Contenido?

Publicado:hace 2 años

Actualizado:hace 2 años