웃웃웃웃웃
웃웃웃웃웃

Reputation: 11984

Dockerize nestjs microservices application

I am trying to dockerize a microservice-based application. The api is built with nestjs and MySQL. The following is the directory structure

.
├── docker-compose.yml
├── api
│   ├── src
│   ├── Dockerfile
│   ├── package.json
│   ├── package-lock.json
│   ├── ormconfig.js
│   └── .env
├── payment
│   ├── src
│   ├── Dockerfile
│   ├── package.json
│   └── package-lock.json
├── notifications
│   ├── src
│   ├── Dockerfile
│   ├── package.json
│   └── package-lock.json
└

The following is the Dockerfile inside the api directory

FROM node:12.22.3

WORKDIR /usr/src/app

COPY package*.json .

RUN npm install
    
CMD ["npm", "run", "start:dev"]

The below is the docker-compose.yml file. Please note that the details for payment & notifications are not added yet in the docker-compose file.

version: '3.7'

networks:
  server-network:
    driver: bridge

services:
  api:
    image: api
    build: 
      context: .
      dockerfile: api/Dockerfile
    command: npm run start:dev
    volumes:
      - ".:/usr/src/app"
      - "/usr/src/app/node_modules"
    networks:
      - server-network
    ports:
      - '4000:4000'
    depends_on:
      - mysql
  mysql:
    image: mysql:5.7
    container_name: api_db
    restart: always
    environment:
      MYSQL_DATABASE: api
      MYSQL_ROOT_USER: root
      MYSQL_PASSWORD: 12345
      MYSQL_ROOT_PASSWORD: root
    ports:
      - "3307:3306"
    volumes:
      - api_db_db:/var/lib/mysql
    networks:
      - server-network
volumes:
  api_db:

Now, when I try to start the application using docker-compose up I'm getting the following error.

no such file or directory, open '/usr/src/app/package.json'

UPDATE Tried removing the volumes and it didn't help too. Also, try to see what is there in the api by listing the contents of the directory by running

docker-compose run api ls /usr/src/app

and it shows the following contents in the folder

node_modules  package-lock.json

Any help is much appreciated.

Upvotes: 3

Views: 2307

Answers (1)

David Maze
David Maze

Reputation: 159975

Your build: { context: } directory is set wrong.

The image build mechanism uses a build context to send files to the Docker daemon. The dockerfile: location is relative to this directory; within the Dockerfile, the left-hand side of any COPY (or ADD) directives is always interpreted as relative to this directory (even if it looks like an absolute path; and you can't step out of this directory with ..).

For the setup you show, where you have multiple self-contained applications, the easiest thing is to set context: to the directory containing the application.

build:
  context: api
  dockerfile: Dockerfile  # the default value

Or, if you are using the default value for dockerfile, an equivalent shorthand

build: api

You need to set the build context to a parent directory if you need to share files between images (see How to include files outside of Docker's build context?). In this case, all of the COPY instructions need to be qualified with the subdirectory in the combined source tree.

# Dockerfile, when context: .
COPY api/package*.json ./
RUN npm ci
COPY api/ ./

You should not normally need the volumes: you show. These have the core effect of (1) replacing the application in the image with whatever's on the local system, which could be totally different, and then (2) replacing its node_modules directory with a Docker anonymous volume, which will never be updated to reflect changes in the package.json file. In this particular setup you also need to be very careful that the volume mappings match the filesystem layout. I would recommend removing the volumes: block here; use a local Node for day-to-day development, maybe configuring it to point at the Docker-hosted database.

If you also remove things that are set in the Dockerfile (command:) and things Compose can provide reasonable defaults for (image:, container_name:, networks:) you could reduce the docker-compose.yml file to:

version: '3.8'
services:
  api:          # without volumes:, networks:, image:, command:
    build: api  # shorthand corrected directory-only form
    ports:
      - '4000:4000'
    depends_on:
      - mysql
  mysql:        # without container_name:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_DATABASE: api
      MYSQL_ROOT_USER: root
      MYSQL_PASSWORD: 12345
      MYSQL_ROOT_PASSWORD: root
    ports:
      - "3307:3306"
    volumes:
      - api_db:/var/lib/mysql
volumes:
  api_db:

Upvotes: 1

Related Questions