0

i'm trying to build a web app using NodeJS (with expressJS) as backend and MySQL for the database. This is all built and used with a docker-compose.yml, and a dockerfile for nodejs.

Problem is, the server can't connect to the database, it keep giving me this error in docker-compose logs :

/usr/src/app/server.js:17
        if (err) throw err
                 ^

Error: connect ECONNREFUSED 127.0.0.1:3606
    at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1300:16)
    --------------------
    at Protocol._enqueue (/usr/src/app/node_modules/mysql/lib/protocol/Protocol.js:144:48)
    at Protocol.handshake (/usr/src/app/node_modules/mysql/lib/protocol/Protocol.js:51:23)
    at PoolConnection.connect (/usr/src/app/node_modules/mysql/lib/Connection.js:116:18)
    at Pool.getConnection (/usr/src/app/node_modules/mysql/lib/Pool.js:48:16)
    at startServer (/usr/src/app/server.js:16:10)
    at Object.<anonymous> (/usr/src/app/server.js:28:1)
    at Module._compile (node:internal/modules/cjs/loader:1119:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1173:10)
    at Module.load (node:internal/modules/cjs/loader:997:32)
    at Module._load (node:internal/modules/cjs/loader:838:12) {
  errno: -111,
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: '127.0.0.1',
  port: 3606,
  fatal: true
}

Here is my docker-compose.yml :

services:
  db:
    image: mysql:latest
    restart: unless-stopped
    environment:
      - MYSQL_DATABASE = areadb
      - MYSQL_ROOT_PASSWORD = password
    ports:
      - 3606:3606
    volumes:
      - sql-db:/var/lib/mysql
    networks:
      - backend

  server:
    depends_on:
      - db
    build: ./server
    restart: unless-stopped
    environment:
      - MYSQL_DATABASE = areadb
      - MYSQL_USER = root
      - MYSQL_PASSWORD = password
      - MYSQL_HOST = db
    ports:
      - 8080:8080
    networks:
      - backend

networks:
  backend:

volumes:
  sql-db:

And the server.js file that is used at the start :

const express = require("express");
const mysql = require("mysql");

function startServer() {
    const app = express();
    const port = 8080;
    const pool = mysql.createPool({
        connectionLimit: 10,
        host: "127.0.0.1",
        user: "root",
        password: "password",
        database: "areadb",
        port: "3606"
    });

    pool.getConnection(function (err, connection) {
        if (err) throw err
        else console.log("App successfully connected to MySQL database.");
    });
    app.get("/", (req, res) => {
        res.send("Hello World");
    });
    app.listen(port, function () {
        console.log("Listening on port 8080");
    });
}

startServer();

Please help me understand why this error happens and how can I fix it.

  • 2
    Why isn't your server using the environment variables that are set in `docker-compose.yml`? The correct hostname to connect to (`db`) is in there. – robertklep Sep 24 '22 at 14:21
  • @robertklep If you mean putting "db" in the js file where i put "127.0.0.1", I just tried, I got the same error. When you say using the env variables set in the .yml, do you mean there is a specific way of using them or just putting the same values in the .yml and the .js ? – Thomas Gireaudot Sep 24 '22 at 14:25
  • Docker containers have their own distinct localhost. So while you're exposint 3306 to the docker host, the docker containers don't connect to each other that way. `db` is the name of the container you want to connect to. Don't even bother writing "I tried that too, it didn't work". Just update the question with the exact error message from using `db` – erik258 Sep 24 '22 at 14:34

1 Answers1

0

Notice how the correct connection information is all present in your docker-compose.yml:

    environment:
      - MYSQL_DATABASE = areadb
      - MYSQL_USER = root
      - MYSQL_PASSWORD = password
      - MYSQL_HOST = db

So it would be a shame not to use it in your server.js:

host: process.env.MYSQL_HOST,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DATABASE,
port: 3606 // might also want to make this an environment variable

An an aside, instead of port 3606 I think you mean 3306, which is the default MySQL port.

robertklep
  • 198,204
  • 35
  • 394
  • 381
  • I did as you said, used the process.env.MYSQL_VAR to use them directly from env, and switched to port 3306 for the database, however it gave me this error : Error response from daemon: Ports are not available: exposing port TCP 0.0.0.0:3306 -> 0.0.0.0:0: listen tcp 0.0.0.0:3306: bind: address already in use – Thomas Gireaudot Sep 24 '22 at 14:34
  • That's a different issue altogether: there's already a process listening on port 3306 on your machine. I'm not sure if you actually have to expose ports if you're connecting to them from another Docker container, as you are doing. – robertklep Sep 24 '22 at 14:35
  • It is important to remove the spaces in the list items under `environment:`, `MYSQL_HOST=db` with no spaces. – David Maze Sep 24 '22 at 14:43
  • @robertklep I tried removing the "ports: - 3306:3306" from the db service in the .yml, the problem came back to the original one, with the same error message. Some research gave me the answer that I do have to leave the port exposure for the db service, so i'm gonna try and resolve that other problem. – Thomas Gireaudot Sep 24 '22 at 14:45