I have a NestJS application that I want to dockerize. I'm new to docker and I have to do this. In my NestJS application I use mysql database with Typeorm. This mysql itself comes from the docker image, that is, mysql is not installed on my computer.
I have this docker-compose.yml file:
# docker-compose.yml version: '3.3' services: mysql: image: mysql:latest restart: always environment: - MYSQL_USER=myuser - MYSQL_PASSWORD=mypassword - MYSQL_DATABASE=db - MYSQL_ROOT_USER=myuser - MYSQL_ROOT_PASSWORD=root volumes: - mysql:/var/lib/mysql ports: - '3306:3306' volumes: mysql:
I can run docker-compose up -d and use the database on my computer. Right now, I also have a Dockerfle I'm trying to write.
I've changed a lot of things over the past 5 hours or so, but in summary, it goes like this:
FROM ubuntu:18.04 # Set the working directory to /usr/src/app WORKDIR /usr/src/app # Copy the package.json and package-lock.json files into the container COPY package*.json ./ RUN apt-get update RUN apt-get -y install curl RUN curl -sL https://deb.nodesource.com/setup_16.x | bash RUN apt install -y nodejs # Install the app dependencies RUN npm install # Copy the rest of the app files into the container COPY . . # Set environment variables for the MySQL connection ENV MYSQL_HOST=mysql ENV MYSQL_USER=myuser ENV MYSQL_PASSWORD=mypassword ENV MYSQL_DATABASE=db # Install the MySQL server RUN apt-get update -qq && apt-get install -y mysql-server # Expose the app's port EXPOSE 3000 # Start the app in development mode CMD ["npm", "run", "start:dev"]
What I am trying to do in the Docekerfile above is create an ubuntu image on the host machine and install curl, node and mysql respectively so that the application can be used with mysql. I can build this image via docker build -t my-app.
Then, I run image docker run my-app and receive the following error:
[Nest] 29 - 04/02/2023, 7:37:26 PM ERROR [TypeOrmModule] Unable to connect to the database. Retrying (1)... Error: connect ECONNREFUSED 127.0.0.1:3306 at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1494:16)
I don't know how to deal with this problem.
For reference, this is my app.module.ts file
import { Module, OnModuleInit } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { TypeOrmModule } from '@nestjs/typeorm'; import { UsersModule } from './users/users.module'; import { ArtworksModule } from './artworks/artworks.module'; import { User } from './users/entities/user.entity'; import { Artwork } from './artworks/entities/artwork.entity'; import { AuthModule } from './auth/auth.module'; import { ConfigModule } from '@nestjs/config'; import { SeedService } from './users/seedService/seedService'; @Module({ imports: [ TypeOrmModule.forRoot({ type: 'mysql', host: 'localhost', port: 3306, username: 'myuser', password: 'mypassword', database: 'db', entities: [User, Artwork], synchronize: false, autoLoadEntities: true, logging: true, }), ConfigModule.forRoot({ isGlobal: true, }), UsersModule, ArtworksModule, AuthModule, ], controllers: [AppController], providers: [AppService, SeedService], }) export class AppModule implements OnModuleInit { constructor(private seedService: SeedService) {} async onModuleInit() { await this.seedService.seedUsers(); } }
What's going on with this error? How can I solve this problem? Thanks for all the help.
cheers
Edit: Now I think I have a little more understanding of the problem, so I'm trying to write a docker-compose-yml file that will launch both my NestJS application and mysql image. First I changed the dockerfile to =>
# Use the official Node.js 14 image as the base image FROM node:14 # Create a working directory for the app WORKDIR /app # Copy the package.json and package-lock.json files into the container COPY package*.json ./ # Install app dependencies RUN npm install # Copy the rest of the app code into the container COPY . . # Expose port 3000 (the port that the app listens on) EXPOSE 3000 # Specify the command to run when the container starts CMD [ "npm", "run", "start:prod" ]
Then I wrote this docker-compose.yml file=>
services: app: build: . command: npm run start:prod restart: always ports: - '3000:3000' environment: - DB_HOST=mysql - DB_PORT=3306 - DB_USER=myuser - DB_PASSWORD=mypassword - DB_NAME=db depends_on: - mysql mysql: image: mysql:latest restart: always environment: - MYSQL_USER=myuser - MYSQL_PASSWORD=mypassword - MYSQL_DATABASE=db - MYSQL_ROOT_USER=myuser - MYSQL_ROOT_PASSWORD=root volumes: - mysql:/var/lib/mysql volumes: mysql: networks: default: driver: bridge
Now when I run sudo docker-compose up on bash (without sudo it gives a permission denied error) I get the following error
my-app-1 | [Nest] 19 - 04/03/2023, 8:28:03 AM ERROR [TypeOrmModule] Unable to connect to the database. Retrying (1)... my-app-1 | Error: connect ECONNREFUSED 127.0.0.1:3306 my-app-1 | at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1159:16) my-app-1 | [Nest] 19 - 04/03/2023, 8:28:06 AM ERROR [TypeOrmModule] Unable to connect to the database. Retrying (2)... my-app-1 | Error: connect ECONNREFUSED 127.0.0.1:3306 my-app-1 | at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1159:16)
As far as I know, it cannot connect to the database. What did I do wrong? How can I solve this problem?
Edit 2: Based on the comments, I made some more changes. These are my findings:
TheDB_HOST value doesn't seem to matter.
# docker-compose.yml version: '3.3' services: mysql: image: mysql:latest restart: always environment: - DB_HOST=localhost - MYSQL_ROOT_USER=myuser - MYSQL_ROOT_PASSWORD=root volumes: - mysql:/var/lib/mysql ports: - '3306:3306' volumes: mysql:
I can change this value to whatever I want and the script will run on my local machine.
This is my app.module.ts file again =>
import { Module, OnModuleInit } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { TypeOrmModule } from '@nestjs/typeorm'; import { UsersModule } from './users/users.module'; import { ArtworksModule } from './artworks/artworks.module'; import { User } from './users/entities/user.entity'; import { Artwork } from './artworks/entities/artwork.entity'; import { AuthModule } from './auth/auth.module'; import { ConfigModule } from '@nestjs/config'; import { SeedService } from './users/seedService/seedService'; @Module({ imports: [ TypeOrmModule.forRoot({ type: 'mysql', host: process.env.DB_HOST, port: 3306, username: 'myuser', password: 'mypassword', database: 'db', entities: [User, Artwork], synchronize: false, autoLoadEntities: true, logging: true, }), ConfigModule.forRoot({ isGlobal: true, }), UsersModule, ArtworksModule, AuthModule, ], controllers: [AppController], providers: [AppService, SeedService], }) export class AppModule implements OnModuleInit { constructor(private seedService: SeedService) {} async onModuleInit() { await this.seedService.seedUsers(); } }
When I try to dockerize this application so that it can run on a machine that only has Docker installed, I try to change the docker-compose.yml file like =>
version: '3.8' services: app: build: . command: npm run start:prod restart: always ports: - '3000:3000' environment: - DB_HOST=localhost - DB_PORT=3306 depends_on: - mysql mysql: image: mysql:latest restart: always environment: - MYSQL_ROOT_USER=myuser - MYSQL_ROOT_PASSWORD=root volumes: - mysql:/var/lib/mysql ports: - '3306:3306' volumes: mysql: networks: default: driver: bridge
This results in two different behaviors: I can no longer run docker-compose up, it gives the following error =>
=> [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 32B 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 34B 0.0s => [internal] load metadata for docker.io/library/node:14 1.4s => [1/5] FROM docker.io/library/node:14@sha256:a97048059988c65f974b37dfe25a44327069a0f4f81133624871de0063b98 0.0s => ERROR [internal] load build context 0.1s => => transferring context: 402.84kB 0.0s ------ > [internal] load build context: ------ failed to solve: error from sender: open /home/sirius/coding/my-app/mysql/#innodb_redo: permission denied
I'm using the Fish Terminal so for some reason I need to change to bash to run sudo docker-compose up which in turn gives the following error indicating there is a problem connecting to the database=>
e dependencies initialized +0ms budapest-icf-recruitment-backend-app-1 | [Nest] 19 - 04/03/2023, 9:26:34 AM ERROR [TypeOrmModule] Unable to connect to the database. Retrying (1)... budapest-icf-recruitment-backend-app-1 | Error: connect ECONNREFUSED 127.0.0.1:3306 budapest-icf-recruitment-backend-app-1 | at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1159:16) budapest-icf-recruitment-backend-app-1 | [Nest] 19 - 04/03/2023, 9:26:37 AM ERROR [TypeOrmModule] Unable to connect to the database. Retrying (2)... budapest-icf-recruitment-backend-app-1 | Error: connect ECONN
I'm really stuck.
P粉5417963222024-04-01 12:22:14
All issues were solved by changing the docker-compose.yml file as shown below =>
version: '3.8' services: app: image: my-app build: . volumes: - .:/app command: npm run start:dev restart: always ports: - '3000:3000' environment: - DB_HOST=mysql - DB_PORT=3306 depends_on: - mysql mysql: image: mysql:latest restart: always environment: - MYSQL_ROOT_USER=myuser - MYSQL_ROOT_PASSWORD=root volumes: - mysql:/var/lib/mysql ports: - '3306:3306' volumes: mysql: networks: default: driver: bridge
This is my Dockerfile =>
# Use the official Node.js 14 image as the base image FROM node:14 # Create a working directory for the app WORKDIR /app # Copy the package.json and package-lock.json files into the container COPY package*.json ./ # Install app dependencies RUN npm install # Copy the rest of the app code into the container COPY . . # Expose port 3000 (the port that the app listens on) EXPOSE 3000 # Specify the command to run when the container starts CMD [ "npm", "run", "start:dev" ]