user475680
user475680

Reputation: 699

NodeJS and Sequelize can't connect to MySQL in docker compose

I have a very similar issue that appears here: Node.js connect to MySQL Docker container ECONNREFUSED

But unfortunately the proposed solution doesn't work. I have a NodeJS project with Typescript(probably unrelated), Sequelize and a MySQL database. I've set up a docker-compose file with scripts that set them up and spin them up as well based on github's scripts to rule them all.

script/setup just creates the volume for the DB and spins it up:

...
docker-compose down
docker volume create --name=tournaments-data
docker-compose up -d tournaments-db

Once that finishes, I run script/start which is just spinning up the web app:

...
docker-compose up web
version: '3'

volumes:
  tournaments-data:

services:
  base: &app_base
    build:
      context: .
      dockerfile: Dockerfile
    depends_on:
      - tournaments-db

  web:
    <<: *app_base
    command: npm run watch-debug
    volumes:
      - ./dist:/usr/src/app/dist
    ports:
      - 3000:3000
      - 5858:5858

  tournaments-db:
    image: mysql:5.6.45
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: 'whatever'
      MYSQL_DATABASE: tournaments
    expose:
      - '3307'
    ports:
      - '3307:3306'
    volumes:
      - tournaments-data:/var/lib/mysql

My sequelize configuration looks like this:

...
development: {
    username: 'root',
    password: 'whatever',
    database: 'tournaments',
    host: 'tournaments-db',
    port: '3307',
    dialect: 'mysql',
    operatorsAliases: false,
  }
...

All the containers spin up correctly, and I'm able to connect successfully into the MySQL container both from the command line using this: mysql -uroot -p -h 127.0.0.1 -P 3307 --protocol=tcp and also using JetBrains Datagrip.

It looks like the NodeJS application can't seem to connect correctly to the mysql db as I get the following error:

Unable to connect to the database: ConnectionRefusedError [SequelizeConnectionRefusedError]: connect ECONNREFUSED 127.0.0.1:3306

I tried giving root access from all IPs (and not just localhost) but that didn't work either. Also thought it was a network issue with docker-compose, so I verified they are on the same network (they are), also tried creating a different network for them via docker-compose but that didn't work either.

Does anyone have any ideas what might be missing? Since I can connect to the mysql instance from outside I assume I'm missing some configuration or some such, but after looking at a lot of proposed solutions, non worked.

P.S The MySQL version is locked to that because of business restrictions, so I can't upgrade/use a different version

Full Error message returned from Sequelize:

web_1             | [Node] Unable to connect to the database: ConnectionRefusedError [SequelizeConnectionRefusedError]: connect ECONNREFUSED 127.0.0.1:3306
web_1             | [Node]     at /usr/src/app/node_modules/sequelize/lib/dialects/mysql/connection-manager.js:123:19
web_1             | [Node]     at tryCatcher (/usr/src/app/node_modules/bluebird/js/release/util.js:16:23)
web_1             | [Node]     at Promise._settlePromiseFromHandler (/usr/src/app/node_modules/bluebird/js/release/promise.js:547:31)
web_1             | [Node]     at Promise._settlePromise (/usr/src/app/node_modules/bluebird/js/release/promise.js:604:18)
web_1             | [Node]     at Promise._settlePromise0 (/usr/src/app/node_modules/bluebird/js/release/promise.js:649:10)
web_1             | [Node]     at Promise._settlePromises (/usr/src/app/node_modules/bluebird/js/release/promise.js:725:18)
web_1             | [Node]     at _drainQueueStep (/usr/src/app/node_modules/bluebird/js/release/async.js:93:12)
web_1             | [Node]     at _drainQueue (/usr/src/app/node_modules/bluebird/js/release/async.js:86:9)
web_1             | [Node]     at Async._drainQueues (/usr/src/app/node_modules/bluebird/js/release/async.js:102:5)
web_1             | [Node]     at Immediate._onImmediate (/usr/src/app/node_modules/bluebird/js/release/async.js:15:14)
web_1             | [Node]     at processImmediate (internal/timers.js:439:21) {
web_1             | [Node]   name: 'SequelizeConnectionRefusedError',
web_1             | [Node]   parent: Error: connect ECONNREFUSED 127.0.0.1:3306
web_1             | [Node]       at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1134:16) {
web_1             | [Node]     errno: 'ECONNREFUSED',
web_1             | [Node]     code: 'ECONNREFUSED',
web_1             | [Node]     syscall: 'connect',
web_1             | [Node]     address: '127.0.0.1',
web_1             | [Node]     port: 3306,
web_1             | [Node]     fatal: true
web_1             | [Node]   },
web_1             | [Node]   original: Error: connect ECONNREFUSED 127.0.0.1:3306
web_1             | [Node]       at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1134:16) {
web_1             | [Node]     errno: 'ECONNREFUSED',
web_1             | [Node]     code: 'ECONNREFUSED',
web_1             | [Node]     syscall: 'connect',
web_1             | [Node]     address: '127.0.0.1',
web_1             | [Node]     port: 3306,
web_1             | [Node]     fatal: true
web_1             | [Node]   }
web_1             | [Node] }

Upvotes: 0

Views: 3658

Answers (1)

user475680
user475680

Reputation: 699

So, I finally figured out what was wrong. I fixed one problem but cause another. Essentially the Sequelize instance I was creating was not passed the host + port configuration, so it used the default one which is 127.0.0.1:3306

It was essentially this:

export const sequelize = new Sequelize({
  database: config.database,
  username: config.username,
  password: config.password,
  models: [path.join(__dirname, '/models')],
  dialect: config.dialect,
});

Instead of this:

export const sequelize = new Sequelize({
  host: config.host,
  port: config.port,
  database: config.database,
  username: config.username,
  password: config.password,
  models: [path.join(__dirname, '/models')],
  dialect: config.dialect,
});


So config was correct, but I was just not using it properly in my code.

Upvotes: 1

Related Questions