DEV Community

Cover image for Dockerize your Node app
Karan Pratap Singh
Karan Pratap Singh

Posted on

Dockerize your Node app

Hey, welcome back. This article is part of the Dockerize series, make sure to checkout the Introduction where I go over some concepts we are going to use.

Today we'll dockerize our Node application, very similar to how we dockerized our React app in the last part by taking advantage of builder pattern with multi stage builds!

I've also made a video, if you'd like to follow along

Project setup

I've initialized a simple express app

├── node_modules
├── index.js
├── package.json
└── yarn.lock
Enter fullscreen mode Exit fullscreen mode
const express = require('express');

const app = express();
const PORT = process.env.PORT || 4000;

app.get('/', (request, response) => {
  response.status(200).json({
    message: 'Hello Docker!',
  });
});

app.listen(PORT, () => {
  console.log(`Server is up on localhost:${PORT}`);
});
Enter fullscreen mode Exit fullscreen mode

I've also setup esbuild to bundle our project.

"build": "esbuild --bundle src/index.js --outfile=build/app.js --minify --platform=node"
Enter fullscreen mode Exit fullscreen mode

For more details, you can checkout my previous article Blazing fast TypeScript with Webpack and ESBuild.

For development

Let's start by adding a Dockerfile

FROM node:14-alpine AS development
ENV NODE_ENV development
# Add a work directory
WORKDIR /app
# Cache and Install dependencies
COPY package.json .
COPY yarn.lock .
RUN yarn install
# Copy app files
COPY . .
# Expose port
EXPOSE 4000
# Start the app
CMD [ "yarn", "start" ]
Enter fullscreen mode Exit fullscreen mode

Let's create a docker-compose.dev.yml. Here we'll also mount our code in a volume so that we can sync our changes with the container while developing.

version: "3.8"

services:
  app:
    container_name: app-dev
    image: app-dev
    build:
      context: .
      target: development
    volumes:
      - ./src:/app/src
    ports:
      - 4000:4000
Enter fullscreen mode Exit fullscreen mode

Let's update our package.json scripts

"dev": "docker-compose -f docker-compose.dev.yml up"
Enter fullscreen mode Exit fullscreen mode

we can use the -d flag to run in daemon mode

Let's start developing!

yarn dev
Enter fullscreen mode Exit fullscreen mode

Great, our dev server is up!

Attaching to app-dev
app-dev  | yarn run v1.22.5
app-dev  | $ nodemon src/index.js
app-dev  | [nodemon] to restart at any time, enter `rs`
app-dev  | [nodemon] watching path(s): *.*
app-dev  | [nodemon] starting `node src/index.js`
app-dev  | Server is up on localhost:4000
Enter fullscreen mode Exit fullscreen mode

For production

FROM node:14-alpine AS builder
ENV NODE_ENV production
# Add a work directory
WORKDIR /app
# Cache and Install dependencies
COPY package.json .
COPY yarn.lock .
RUN yarn install --production
# Copy app files
COPY . .
# Build
CMD yarn build

FROM node:14-alpine AS production
# Copy built assets/bundle from the builder
COPY --from=builder /app/build .
EXPOSE 80
# Start the app
CMD node app.js
Enter fullscreen mode Exit fullscreen mode

Let's add a docker-compose.prod.yml for production

version: "3.8"

services:
  app:
    container_name: app-prod
    image: app-prod
    build:
      context: .
      target: production
Enter fullscreen mode Exit fullscreen mode
docker-compose -f docker-compose.prod.yml build
Enter fullscreen mode Exit fullscreen mode

let's start our production container on port 80 with the name react-app

docker run -p 80:4000 --name node-app app-prod
Enter fullscreen mode Exit fullscreen mode

Next steps

With that, we should be able to take advantage of docker in our workflow and deploy our production images faster to any platform of our choice.

Feel free to reach out to me on Twitter if you face any issues.

Top comments (4)

Collapse
 
jonlauridsen profile image
Jon Lauridsen

Thanks! Where do you run tests?

Collapse
 
karanpratapsingh profile image
Karan Pratap Singh

Thank you reading! I usually run integration tests before building the images and unit test while building by adding a step in the dockerfile itself

Collapse
 
allanshady profile image
Allan Camilo

great article

Collapse
 
karanpratapsingh profile image
Karan Pratap Singh

Thank you Allan!