Search code examples
mysqlnode.jsdockerdocker-composetypeorm

Docker Compose getting error ECONNREFUSED 127.0.0.1:3306 with MySQL and NodeJS


I am trying to setup some containers for my NestJS + TypeORM + MySQL environment by using Docker Compose in a Windows 10 host, but I am getting an ECONNREFUSED error:

connect ECONNREFUSED 127.0.0.1:3306 +2ms
backend_1  | Error: connect ECONNREFUSED 127.0.0.1:3306
backend_1  |     at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1145:16)
backend_1  |     --------------------
backend_1  |     at Protocol._enqueue (/usr/src/app/node_modules/mysql/lib/protocol/Protocol.js:144:48)
backend_1  |     at Protocol.handshake (/usr/src/app/node_modules/mysql/lib/protocol/Protocol.js:51:23)        
backend_1  |     at PoolConnection.connect (/usr/src/app/node_modules/mysql/lib/Connection.js:116:18)
backend_1  |     at Pool.getConnection (/usr/src/app/node_modules/mysql/lib/Pool.js:48:16)
backend_1  |     at /usr/src/app/node_modules/typeorm/driver/mysql/MysqlDriver.js:793:18
backend_1  |     at new Promise (<anonymous>)
backend_1  |     at MysqlDriver.createPool (/usr/src/app/node_modules/typeorm/driver/mysql/MysqlDriver.js:790:16)
backend_1  |     at MysqlDriver.<anonymous> (/usr/src/app/node_modules/typeorm/driver/mysql/MysqlDriver.js:278:51)
backend_1  |     at step (/usr/src/app/node_modules/typeorm/node_modules/tslib/tslib.js:141:27)
backend_1  |     at Object.next (/usr/src/app/node_modules/typeorm/node_modules/tslib/tslib.js:122:57)

I have created the following Dockerfile to configure the NestJS API container:

FROM node:12-alpine
WORKDIR /usr/src/app

COPY package.json .
RUN npm install

EXPOSE 3000

#CMD ["npm", "start"]

CMD /wait-for-it.sh db:3306 -- npm start

COPY . .

And then I reference this from Docker Compose with the following docker-compose.yml:

version: "3.8"

networks:
  app-tier:
    driver: bridge

services:
  db:
    image: mysql
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    expose:
      - "3306"
    ports:
      - "3306:3306"    
    networks:
      - app-tier      
    environment:
      MYSQL_DATABASE: school
      MYSQL_ALLOW_EMPTY_PASSWORD: ok
      MYSQL_ROOT_PASSWORD: root
      MYSQL_USER: dbuser
      MYSQL_PASSWORD: dbuser
      MYSQL_ROOT_HOST: '%'
  backend:
    depends_on:
      - db
    build: .
    ports:
      - "3000:3000"
    networks:
      - app-tier      

Finally, I set the TypeORM configuration to match with the Docker Compose file:

export const DB_CONFIG: TypeOrmModuleOptions = {
    type: 'mysql',
    host: 'db',
    port: 3306,
    username: 'dbuser',
    password: 'dbuser',
    database: 'school',
    entities: [], // We specify the entities in the App Module.
    synchronize: true,
};

I am kind of new to Docker Compose, but I have tried many things like changing the output port to 3307, setting an explicit network... and the port 3306 is free in my host OS when I run it. Any help?

Edit 1

I have included MYSQL_ROOT_HOST and wait-for-it.sh as suggested, but still no results.


Solution

  • I think your db is taking more time to start and your app is starting before the db, try something like this for your docker-compose.yml file:

    version: "3.8"
    
    networks:
      app-tier:
        driver: bridge
    
    services:
      db:
        image: mysql
        command: --default-authentication-plugin=mysql_native_password
        restart: always
        expose:
          - "3306"
        ports:
          - "3306:3306"    
        networks:
          - app-tier      
        environment:
          MYSQL_DATABASE: school
          MYSQL_ALLOW_EMPTY_PASSWORD: ok
          MYSQL_ROOT_PASSWORD: root
          MYSQL_USER: dbuser
          MYSQL_PASSWORD: dbuser
          MYSQL_ROOT_HOST: '%'
      backend:
        depends_on:
          - db
        build: .
        command: bash -c 'while !</dev/tcp/db/3306; do sleep 1; done; npm start'
        ports:
          - "3000:3000"
        networks:
          - app-tier