Debugging a Dockerfile for Containerizing a Node.js API.

Dolamu Oludare
Towards Data Engineering
6 min readNov 11, 2023
Photo by Kenny Eliason from Unsplash.

This practical article is about a Nexascale community challenge I participated in by debugging a docker file for an API built with Node.js. The application has already been built locally, so all that we have to do is dockerize the application so that we can run the application on any platform or operating system. In the article, I would document my process of debugging the docker file for the application, building the docker image, and running the docker container on docker.

Firstly, you need to make sure you have a GitHub account and Docker installed on your local machine or you can use the Play with Docker platform to test your Docker corrections. Click on this link to read the instructions for the challenge. Then you have to clone the git repository that contains what we want to debug to your local machine by running the following command:

git clone https://github.com/ohansck/atheria-troubleshoot-dockerfile.git
Directory Content.

After cloning the repository from GitHub, you should see the files in the image on your local machine. You can also verify that the folder is a git repository by running the following command.

git status
The outcome from running git status.

You can see that we now have the git repository on our local machine, so we can run the challenge.

Before we debug the Dockerfile, we can run through the server file written in Typescript shown in the images below:

This Javascript code above is a basic setup for a Node.js API using the Express framework. The code setup is designed to listen to incoming requests and respond with a simple message when you access the root URL. So our job is to dockerize this setup by making sure our Dockerfile is properly written.

Troubleshooting the Dockerfile.

Now, we will review our Dockerfile for errors and potential bugs. The initial content of the Dockerfile is shown below:

Error prone Dockerfile.

Before starting the challenge, let’s build our Docker image with the Dockerfile present in the folder and see if it works or not. We will build our Docker image with the following command:

docker build -t docker-challenge-app .
Error from Docker build.

We are getting errors from the docker build process which means that our Dockerfile is truly infested with bugs. So now let's go into debugging properly.

  1. The first bug I noticed from the Dockerfile is the use of the ARG and FROM keyword. The ARG keywords are used to set variables in the Dockerfile and they are referenced in the FROM keyword to set our base image for the Dockerfile. These variables are meant to be referenced using the dollar sign ($) and enclosed in curly brackets {}.
ARG NODE_VERSION=node:current-alpine3.17
ARG ENV=production

# Stage 1: Build the project
FROM ${NODE_VERSION} AS builder # reference NODE_VERSION variable for baseimage

2. The second bug I noticed in the Dockerfile is on line 11. The COPY syntax is used to copy files and folders from a source to a destination, which is often from your local directory to a working directory on your container. But in the Dockerfile there is no indicator for the destination, only the source is indicated. We will correct this by changing that line of the code.

# Set the working directory
WORKDIR /app

# Copy All
COPY . .

We set our working directory in the container to /app, then we use the COPY keyword to copy all folders in our local directory to the /app directory in our container.

3. The next bugs in the codes are on the line 13–16, which are required to install the dependencies for the project, the backslash (\) character is used for line continuation in the context of a Dockerfile. Each line ending with a backslash indicates that the command continues on the next line. When Docker builds the image, it treats these lines as a single command. So indirectly the command is the same as this:

RUN npm ci npm run build ls

this would give us errors because we merge three different commands on the same line and the program sees it as one line. To fix this we would use the double ampersand(&&) character to separate the commands and we can still write them on the same line.

RUN npm ci && npm run build && ls

#OR

RUN npm ci && \
npm run build && \
ls

4. The next bug is in line 19, where we try to reference a ARG variable without the dollar character and curly brackets. Also according to the Dockerfile documentation, a ARG declared before a FROM is outside of the build stage, so it can’t be used in any other instruction after the FROM statement. To use the default value of the ARG declared before the first, we have to use an ARG instruction without a value as shown in the command below:

ARG NODE_VERSION

FROM ${NODE_VERSION} AS deploy

5. Our next bug is located on line 24, this is similar to the bug we experienced on line 19, also the variable name referenced is wrong. it should be ENV and not ENVIRONMENT. We would correct that line with the code below:

ARG ENV
ENV NODE_ENV=${ENV}

6. The last bug in our Dockerfile is located on line 32, where we try to copy files and folders from a previous build stage. We are trying to copy files from the /app/dist folder to the ./dist folder within the image we are currently trying to build. If you notice clearly, you would observe that the image source used in the Dockerfile is bullder instead of builder. We would correct this by changing bullder to builder in the COPY statement.

COPY --from=builder /app/dist ./dist

Putting it all together.

Now, we have successfully corrected all the bugs and errors in our code. Let’s see the cumulative correction on our Dockerfile.

We would build our docker image from the Dockerfile and spin up our containers. To build our docker image we would run the following command:

docker build -t docker-app-challenge .
docker build process.

According to the image above, we can see the docker image has successfully been built. Let us check our Docker client to verify if our image has been created.

Docker image on Docker client.

Next, we would spin our container using the following command:

docker run -p 8000:8000 --name running-container docker-challenge-app

We are running our container on the port 8000 on our local host and also on our container, the name of our container is running-container, and the docker image used to build our container is docker-challenge-app.

Docker container running.
Docker Container list.

From the images, we can that our container is running perfectly. Now we would visit the endpoint http://localhost:8000/ to see if we get the expected outcome.

API endpoint on a web browser.

Our dockerized API is working properly, and we have completed the troubleshooting challenge. I hope you learned a few things about Docker from this challenge. You can connect with me on X (formerly Twitter).

References

Thank you for reading!

--

--