Motivation
Eventhough running a Node.js project in a docker container might sound trivial, however, making it work out is so not. To start, we are assuming that you already have a Node.js project ready for this tutorial.
Containerizing Node.js Project
The first step in containerizing any project is by adding a file to build its image. When using docker, this file is Dockerfile. So, add the following `Dockerfile` (without any extension) to your project.
FROM node:16.14.0-alpine AS build
RUN mkdir -p /app
WORKDIR /app
COPY package*.json /app/
RUN npm install
COPY . /app/
RUN npm run build
FROM nginx:alpine
COPY ./default.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist/{project_name}/usr/share/nginx/html
EXPOSE 80
As you may have noticed, this file follows the Docker Builder Pattern, which helps in reducing the size of the final image to limit its content to only contain the needed files.
In the first stage of the build (lines 1 to 10) where pulling node's base image and building our project. I chose the alpine version of node 16.14.0 which is a lighter edition of it. The output of this stage is a group of files that will constitute our final image's content, and it will be stored under the directory /app/dist/{project_name} of the file system of this stage (not visible in your local machine).
After we built our project, we need a webserver to run it in. For this tutorial I chose NGINX.
In the second stage (lines 12 to19), we are:
- pulling NGINX's alpine image
- copying NGINX's configuration file `default.conf` which we will talk about in a bit to it's required directory in our image
- copying the output of the build done in the build stage to NGINX's web root directory.
- exposing the port 80
Configuring NGINX
NGINX is more than just a web server, it can be used as a reverse proxy, load balancer, etc. Whichever you're using NGINX for, you will probably need to configure some of its behavior.
In our example, we are using it as a web server. Without the line 14 of the Dockerfile, our web application will not have the best experience on refresh, as it will redirect us to 404 code error. To solve it, we need to create file named `default.conf` and copy it to the image as we are doing in line 14 of Dockerfile. The content of default.conf is below:
server {
listen 80;
root /usr/share/nginx/html;
location / {
try_files $uri $uri/ /index.html =404;
}
}
In the above configuration, we are:
- listening on port 80
- specifying the webroot path, where our build content lives in
- adding a rule for all the paths in order to avoid immediately being redirected to the 404 error page.
Running the Container
To run the container, you can run the following commands:
docker build -i image_name .
docker run -dp 8080:80 image_name