# Dockerizing NestJs application for production

# Prerequisites

- Docker installed [https://docs.docker.com/engine/install/](https://docs.docker.com/engine/install/)
- A nest Js application

# Containerized Nest Js Application

## Creating Dockerfile with multi-stage build

create a file named `Dockerfile` in the root directory of the nestjs application

Replace `9009` with your application port

```docker
FROM node:12 As development
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

FROM node:12-alpine As production
RUN apk update && apk upgrade && \
  apk add --no-cache bash git openssh
ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install --only=production
COPY . .
COPY --from=development /usr/src/app/dist ./dist
EXPOSE 9009
CMD ["node", "dist/main"]
```

## Creating .dockerignore

From the [official docs](https://docs.docker.com/engine/reference/builder/#dockerignore-file) of docker for .dockerignore:

> Before the docker CLI sends the context to the docker daemon, it looks for a file named .dockerignore in the root directory of the context. If this file exists, the CLI modifies the context to exclude files and directories that match patterns in it. This helps to avoid unnecessarily sending large or sensitive files and directories to the daemon and potentially adding them to images using ADD or COPY.

```docker
node_modules
npm-debug.log
dist
```

## Build Docker Image

When building an image, we use the following command:

```bash
docker build -t username/image_name:tag_name .
```

in the below command replace api with your application name

```bash
docker build -t sreeteja06/api:v0.1 .
```

## Running the image

replace `api` with your application name

replace `9009:9009` with your application port

```bash
docker run -p 9009:9009 api
```

Run detached
```bash
docker run -d -p 9009:9009 api
```

# docker-compose

docker-compose helps developers with their local development. Since our application is containerized and works the same on every machine, why should our database be dependent on the developer’s machine?

We are going to create a docker-compose config that will initiate and wire up three services for us.

The `mariadb` service will, as their names imply, run containerized mariadb.

In the application root directory, create a file called `docker-compose.yml` and fill it with the following content:

replace `api` with your application name and `9009:9009` with your port

```yaml
version: '3.7'

services:
  db:
    image: mariadb
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: example
      MYSQL_DATABASE: mydb
      MYSQL_USER: user
      MYSQL_PASSWORD: user
    ports:
      - 3306:3306
    volumes:
      - mariadb-data:/data
    
  api:
    image: api
    restart: always
    ports:
      - 9009:9009

volumes:
  mariadb-data:
```

### **Running the application in development**

To run the application, we now have to use the following command:

```bash
docker-compose up
```

Run Detached
```bash
docker-compose up -d
```

And Docker will take care of everything for us.

Stop docker-compose by running
```bash
docker-compose down
```
Remove volumes by running
```bash
docker-compose down -v
```
