DEV Community

Cover image for Dockerize Nestjs app with Postgres + Redis + Prisma ORM
Manuchehr
Manuchehr

Posted on

Dockerize Nestjs app with Postgres + Redis + Prisma ORM

We're about to embark on an epic journey into the world of containerization. In this guide, we'll be turning a regular NestJS app into a Dockerized powerhouse, complete with PostgreSQL, Redis, and the magic touch of Prisma ORM.

First of all we should create Dockerfile:

FROM node:18-alpine  WORKDIR /usr/src/app  COPY package*.json ./  COPY entrypoint.sh ./  RUN npm install COPY . . RUN chmod +x /usr/src/app RUN chmod +x /usr/src/app/entrypoint.sh RUN npx prisma generate --schema=/usr/src/app/src/database/schema.prisma RUN npm run build ENTRYPOINT ["/usr/src/app/entrypoint.sh", "npm", "run", "start:prod"]  CMD ["npm", "run", "start:prod"] 
Enter fullscreen mode Exit fullscreen mode
  1. FROM node:18-alpine - This line sets the base image for the Docker image. It specifies that the image should be based on the official Node.js 18 Alpine image. Alpine is a lightweight Linux distribution, making the resulting Docker image smaller.

  2. WORKDIR /usr/src/app - This line sets the working directory inside the container to /usr/src/app. Subsequent commands will be executed from this directory.

  3. COPY package*.json ./ - Copies the package.json and package-lock.json files from the host machine to the /usr/src/app directory inside the container. This allows for efficient installation of Node.js dependencies.

  4. COPY entrypoint.sh ./ - Copies the entrypoint.sh script from the host machine to the /usr/src/app directory inside the container. This script might be used to perform additional setup or configuration before starting the application.

  5. RUN npm install - Executes the npm install command inside the container, installing the Node.js dependencies specified in the package.json file. This step is crucial for setting up the application environment.

  6. COPY . ./ - Copies the entire application source code from the host machine to the /usr/src/app directory inside the container. This includes all the application files, not just the package.json and package-lock.json files.

  7. RUN npx prisma generate --schema=/usr/src/app/src/database/schema.prisma - Executes the Prisma CLI command to generate Prisma client code based on the schema defined in /usr/src/app/src/database/schema.prisma. This step is specific to Prisma and is part of the database setup.

  8. RUN npm run build - Executes the npm run build command inside the container. This command is often used to compile TypeScript code or perform other build-related tasks for the Node.js application.

  9. ENTRYPOINT ["/usr/src/app/entrypoint.sh", "npm", "run", "start:prod"] - Specifies the default command to run when the container starts. In this case, it uses the entrypoint.sh script followed by the command npm run start:prod. The entrypoint.sh script handles additional setup before running the application.

  10. CMD ["npm", "run", "start:prod"] - Provides a default command to run when the container starts if no other command is specified. This is overridden by the ENTRYPOINT command. Here, it's set to run npm run start:prod.

by following .dockerignore file:

Dockerfile .dockerignore node_modules npm-debug.log dist 
Enter fullscreen mode Exit fullscreen mode

You should also create entrypoint.sh this file is executed once docker image is started to make prisma migrations:

#!/bin/sh  # Apply Prisma migrations and start the application  npx prisma migrate deploy --schema=/usr/src/app/src/database/schema.prisma npx prisma generate --schema=/usr/src/app/src/database/schema.prisma # Run database migrations  npx prisma migrate dev --name init --schema=/usr/src/app/src/database/schema.prisma # Run the main container command  exec "$@" 
Enter fullscreen mode Exit fullscreen mode

Attention! You should specify the path of your prisma.schema file.

Create a docker-compose.yml file:

version: "3" services: app: container_name: "myapp_web_app" restart: unless-stopped build: context: . dockerfile: Dockerfile environment: PORT: ${PORT} POSTGRES_HOST: postgres_db # localhost doesn't work in docker container, hence you should use postgres container name instead of localhost REDIS_HOST: redis # the same for redis. Use redis container name instead of localhost ports: - ${PORT}:${PORT} depends_on: - postgres_db - redis networks: myapp_net: postgres_db: image: bitnami/postgresql:15 container_name: "myapp_postgres_db" restart: unless-stopped environment: POSTGRESQL_USERNAME: ${POSTGRES_USER} POSTGRESQL_PASSWORD: ${POSTGRES_PASSWORD} POSTGRESQL_DATABASE: ${POSTGRES_DB} POSTGRESQL_TIMEZONE: "Asia/Tashkent" # This is optional ports: - ${POSTGRES_PORT}:5432 volumes: - "postgres_data:/bitnami/postgresql" networks: myapp_net: redis: image: "bitnami/redis:7.2" container_name: "myapp_redis" restart: unless-stopped ports: - ${REDIS_PORT}:${REDIS_PORT} volumes: - "redis_data:/bitnami/redis/data" environment: REDIS_PASSWORD: ${REDIS_PASSWORD} REDIS_PORT: ${REDIS_PORT} REDIS_DB: ${REDIS_DB} REDIS_IO_THREADS: 4 REDIS_IO_THREADS_DO_READS: yes REDIS_DISABLE_COMMANDS: FLUSHDB,FLUSHALL networks: myapp_net: volumes: postgres_data: redis_data: networks: myapp_net: 
Enter fullscreen mode Exit fullscreen mode

This is my .env file:

PORT=9000 # Postgres POSTGRES_DB=sampledb POSTGRES_HOST=localhost POSTGRES_PORT=5432 POSTGRES_USER=username POSTGRES_PASSWORD=password DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}?schema=public # Redis REDIS_HOST=localhost REDIS_PORT=6379 REDIS_PASSWORD=veryhardpassword REDIS_DB=0 
Enter fullscreen mode Exit fullscreen mode

Run docker compose

sudo docker compose up -d --build 
Enter fullscreen mode Exit fullscreen mode

For windows users:

docker-compose up -d --build 
Enter fullscreen mode Exit fullscreen mode

That’s all! I apologize for any mistake I made. If you find any mistake, please let me know.
I hope it’s helpful

Top comments (0)