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
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}`);
});
I've also setup esbuild to bundle our project.
"build": "esbuild --bundle src/index.js --outfile=build/app.js --minify --platform=node"
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" ]
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
Let's update our package.json
scripts
"dev": "docker-compose -f docker-compose.dev.yml up"
we can use the -d
flag to run in daemon mode
Let's start developing!
yarn dev
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
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
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
docker-compose -f docker-compose.prod.yml build
let's start our production container on port 80
with the name react-app
docker run -p 80:4000 --name node-app app-prod
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)
Thanks! Where do you run tests?
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
great article
Thank you Allan!