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
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:
Here, to avoid replication, I have moved the credentials across to a
.env
file:For testing purposes I updated your
index.ts
to test the connection by executing a simple query.Build and run:
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/