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

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

ยท

3 min read

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

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

npm init -y

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);

Installed Express:

npm install express

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


FROM node:14


WORKDIR /app


COPY package*.json ./


RUN npm install


COPY . .


CMD [ "node", "server.js" ]


EXPOSE 3000

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

docker build -t my-node-app .

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

docker run -d -p 3000:3000 my-node-app

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

When faced with vulnerabilities, I used:

npm audit fix
npm audit fix --force

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 .

Option B: Pull the Image

docker pull <username>/my-node-app:latest

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!

ย