skip to Main Content

I’m using Docker Compose to define two services: one for the NodeJS App and the other for MySQL.
This is the docker-compose:

services:
  app-node:
    build: .
    ports: 
      - "3000:3000"
    depends_on:
      - mysql2
    environment:
      DB_HOST: mysql2
      DB_USER: lucasfer
      DB_PASSWORD: contra31
      DB_NAME: test-docker
      DB_PORT: "3306"

  mysql2:
    image: mysql:5.7.27
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    ports: 
    - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: contra31
      MYSQL_DATABASE: test-docker
      MYSQL_USER: lucasfer
      MYSQL_PASSWORD: contra31

This is the Docker file that’s used to containerize nodejs app:

FROM node:18-alpine3.18

WORKDIR /app
COPY . .

RUN npm install
RUN npm run build

EXPOSE 3000

ENTRYPOINT ["node", "./dist/index.js"]

The NodeJS app is the following:

import express, { Request, Response } from 'express'
import mysql from 'mysql'
import { createUserTable, insertInitialUsers } from './src/DatabaseService.js'; 

const pool = mysql.createPool({
    connectionLimit : 10,
    host: process.env.DB_HOST,
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    database: process.env.DB_NAME,
    port: Number(process.env.DB_PORT)
});

const app = express()
const PORT = 3000;

createUserTable(pool)
insertInitialUsers(pool)


app.get('/', async (req: Request, res: Response) => {
    pool.query('SELECT * FROM users', (err: any, results: any) => {
        if (err) {
            console.error(err)
            return res.status(500).json({ error: 'Database error' })
        }
        res.json(results)
    })
})


app.listen(PORT, () => {
    console.log(`Servidor NodeJS corriendo en puerto ${PORT}`)
})

Database service file:

import { Pool } from "mysql";
export function createUserTable (pool: Pool) {
    pool.query(`
        CREATE TABLE IF NOT EXISTS users(
            id INT AUTO_INCREMENT PRIMARY KEY,
            firstName VARCHAR(255),
            lastName  VARCHAR(255),
            email     VARCHAR(255)      
        )
    ` , (err, result) => {
        if (err) {
            console.error(err)
            return
        }
        console.log('Tabla users creada exitosamente')
    })
}

export function insertInitialUsers (pool: Pool) {
    return pool.query(`
        INSERT INTO users(firstName, lastName, email)
        VALUES  ('Lucas', 'Ferrero', '[email protected]'),
                ('Juan', 'Perez', '[email protected]'),
                ('Pedro', 'PicaPiedra', '[email protected]')
    `, (err, result) => {
        if (err) {
            console.error(err)
            return
        }
        console.log('usuarios insertados correctamente')
    })
}

When I run docker compose up I get the following error from the nodejs app:

Error: connect ECONNREFUSED 172.21.0.3:3306
    at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1555:16)
    --------------------
    at Protocol._enqueue (/app/node_modules/mysql/lib/protocol/Protocol.js:144:48)
    at Protocol.handshake (/app/node_modules/mysql/lib/protocol/Protocol.js:51:23)
    at Connection.connect (/app/node_modules/mysql/lib/Connection.js:116:18)
    at file:///app/dist/index.js:22:5
    at ModuleJob.run (node:internal/modules/esm/module_job:195:25)
    at async ModuleLoader.import (node:internal/modules/esm/loader:337:24)
    at async loadESM (node:internal/process/esm_loader:34:7)
    at async handleMainPromise (node:internal/modules/run_main:106:12) {
  errno: -111,
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: '172.21.0.3',
  port: 3306,
  fatal: true
}

I’ve tried to connect to MySQL with a client (Adminer), and It works perfectly fine. I wonder why I get this error from Node.js app.

2

Answers


  1. You need to ensure that MySQL is ready to accept connections. There are a variety of ways to do this.

    One option would be to have your Node code retry connecting to MySQL.

    Alternatively you could implement a health check in your Docker Compose file:

    services:
      app-node:
        build: .
        ports: 
          - "3000:3000"
        depends_on:
          - mysql2
        environment:
          DB_HOST: mysql2
          DB_PORT: 3306
          DB_USER: ${MYSQL_USER}
          DB_PASSWORD: ${MYSQL_PASSWORD}
          DB_NAME: ${MYSQL_DATABASE}
        depends_on:
          mysql2:
            condition: service_healthy
    
      mysql2:
        image: mysql:5.7.27
        command: --default-authentication-plugin=mysql_native_password
        restart: always
        healthcheck:
          test: ["CMD", "mysqladmin", "ping", "-pcontra31"]
          interval: 1s
          retries: 120
    

    Here, to avoid replication, I have moved the credentials across to a .env file:

    MYSQL_ROOT_PASSWORD=contra31
    MYSQL_DATABASE=test-docker
    MYSQL_USER=lucasfer
    MYSQL_PASSWORD=contra31
    

    For testing purposes I updated your index.ts to test the connection by executing a simple query.

    import express, { Request, Response } from 'express'
    import mysql from 'mysql'
    
    const pool = mysql.createPool({
        connectionLimit : 10,
        host: process.env.DB_HOST,
        user: process.env.DB_USER,
        password: process.env.DB_PASSWORD,
        database: process.env.DB_NAME,
        port: Number(process.env.DB_PORT)
    });
    
    const app = express()
    const PORT = 3000;
    
    
    app.listen(PORT, () => {
        console.log("user:     "+process.env.DB_USER);
        console.log("password: "+process.env.DB_PASSWORD);
    
        pool.query('SELECT 1', (err, results) => {
            if (err) {
                return console.error('Error connecting to the database:', err);
            }
            console.log('Database connection successfully created.');
        });
    })
    

    Build and run:

    docker-compose build && docker-compose up
    

    enter image description here

    Login or Signup to reply.
  2. Create a docker network and use this network for your containers. This will allow to find from one container the other through using just the names of the containers. For each docker container within a docker network a Docker container name works like an ip address.

    https://docs.docker.com/reference/cli/docker/network/create/

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search