DEV Community

Cover image for Day 6 of 90 Days of DevOps: Dockerizing a Node.js App
Arbythecoder
Arbythecoder

Posted on

Day 6 of 90 Days of DevOps: Dockerizing a Node.js App

Today, I tackled the process of Dockerizing a Node.js application, an essential skill in the DevOps toolkit.
Dockerization allows for consistent environments across various stages of development, testing, and production,
ensuring that applications run smoothly regardless of where they are deployed. However, this journey wasn't without its challenges!

Steps Taken

1. Setting Up the Project Directory:
First, I created a new directory for my Node.js application.

mkdir day6docker
cd day6docker
Enter fullscreen mode Exit fullscreen mode

2. Initializing the Node.js Project:
Next, I initialized a new Node.js project and set up a basic Express server.

npm init -y
Enter fullscreen mode Exit fullscreen mode

Created a server.js file:

const express = require("express");
const path = require("path");
const axios = require("axios");
const morgan = require("morgan");

const app = express();

const morganMiddleware = morgan(
  ":method :url :status :res[content-length] - :response-time ms",
  {
    stream: {
      write: message => console.log(message.trim()),
    },
  }
);

app.use(morganMiddleware);

app.use(express.static(path.join(__dirname, "public")));

app.set("view engine", "pug");

async function getRandomJoke() {
  const response = await axios.get("https://api.chucknorris.io/jokes/random");

  return response.data;
}

app.get("/", async (req, res, next) => {
  try {
    const response = await getRandomJoke();

    res.render("home", {
      title: "Random Chuck Norris Jokes",
      joke: response,
    });
  } catch (err) {
    next(err);
  }
});

app.get("/joke", async (req, res, next) => {
  try {
    const response = await getRandomJoke();
    res.json(response);
  } catch (err) {
    next(err);
  }
});

app.use(function (err, req, res, next) {
  console.error(err);
  res.set("Content-Type", "text/html");
  res.status(500).send("<h1>Internal Server Error</h1>");
});

const server = app.listen(process.env.PORT || 4000, () => {
  console.log(`chucknorris server started on port: ${server.address().port}`);
});

function cleanupAndExit() {
  server.close(() => {
    console.log("chucknorris server closed");
    process.exit(0);
  });
}

process.on("SIGTERM", cleanupAndExit);
process.on("SIGINT", cleanupAndExit);

Enter fullscreen mode Exit fullscreen mode

Installed Express:

npm install express
Enter fullscreen mode Exit fullscreen mode

3. Creating a Dockerfile:
I then created a Dockerfile to define the image.

# Use the official Node.js image.
FROM node:14

# Create and change to the app directory.
WORKDIR /app

# Copy application dependency manifests to the container image.
COPY package*.json ./

# Install dependencies.
RUN npm install

# Copy local code to the container image.
COPY . .

# Run the web service on container startup.
CMD [ "node", "server.js" ]

# Inform Docker that the container listens on the specified network ports at runtime.
EXPOSE 3000
Enter fullscreen mode Exit fullscreen mode

4. Building the Docker Image:
With the Dockerfile set up, I built the Docker image.

docker build -t my-node-app .
Enter fullscreen mode Exit fullscreen mode

5. Running the Docker Container:
Finally, I ran the Docker container.

docker run -d -p 3000:3000 my-node-app
Enter fullscreen mode Exit fullscreen mode

Challenges and Solutions

Challenge 1: Dependency Issues
Initially, I faced issues with my Node modules. My PowerShell commands weren't recognized properly. To resolve this, I used the following commands to clean up my environment and reinstall dependencies:

Remove-Item -Recurse -Force .\node_modules
Remove-Item -Force .\package-lock.json
npm install
Enter fullscreen mode Exit fullscreen mode

When faced with vulnerabilities, I used:

npm audit fix
npm audit fix --force
Enter fullscreen mode Exit fullscreen mode

Challenge 2: Image Not Found and Authorization Errors
When running the Docker container, I encountered errors indicating that the image wasn't found locally and pull access was denied.

To fix this, I either had to build the image from the Dockerfile or pull it from a repository:

Option A: Build the Image

docker build -t my-node-app .
Enter fullscreen mode Exit fullscreen mode

Option B: Pull the Image

docker pull <username>/my-node-app:latest
Enter fullscreen mode Exit fullscreen mode

Challenge 3: Docker Container Issues
On running the container, it initially failed to start. Checking the logs showed a missing module error. This was solved by ensuring all necessary files were included in the Docker context and correctly referenced.

Conclusion

Dockerizing an application, while challenging at times, is incredibly rewarding. It ensures that your application can run anywhere, from a local machine to a production server, with the same environment and dependencies. Mastering this skill is a significant step in the journey towards becoming a proficient DevOps engineer.

See you on Day 7 in a bit – it's not easy, but we move!

Top comments (0)