Guide to Node.js Dockerode with Docker and Docker Compose

Posted January 9, 2024
Guide to Node.js Dockerode with Docker and Docker Compose

Docker ships, and runs applications in containers. If you are a Node.js developer, Dockerode runs your Docker containers as Remote APIs using JavaScript. Dockerode is a library, just like other Node.js libraries like Express.

Dockerode specifically works with Docker and Node.js to control your Docker containers. This way, Dockerode will manage Docker containers, images, and other Docker-related tasks (networks, volumes, Docker Compose) using only Node.js runtime. Dive into this guide and learn how to use Node.js with Dockerode to elevate how you run and manage Docker tasks.

Along this Node.js Dockerode with Docker and Docker Compose guide, you will learn:

  • How Dockerode and Node.js make it easier to manage Docker containers with JavaScript.
  • How to use Dockerode Node.js to build Docker images, create containers, and list and remove them.
  • Using Dockerode to create Docker volumes and networks.
  • The right way to execute Dockerode with Node.js to create Docker Compose configurations and run multiple containers.

Step 1: What you Need to use Dockerode

To follow along with Dockerode, you’ll need:

Step 2: Setting up a Node.js Dockerode App

Let’s first create a Node.js project. You will head over to your working directory and initialize Node.js.

npm init -y

Now install Dockerode using NPM:

npm install dockerode

At this point, your Docker Engine should be running. Then create an app.js Node.js file, import the Dockerode module, and create a new Node.js instance of Docker:

const Docker = require("dockerode");
const docker = new Docker();

Step 3: How to Build Docker Images with Dockerode

Let’s say you have a Node.js app. So, you have a simple index.js file as follows:

// app.js
const express = require("express");
const app = express();
const port = 3000;

app.get("/", (req, res) => {
  res.send("Hello, Dockerode!");
});

app.listen(port, () => {
  console.log(`App listening at http://localhost:${port}`);
});

In this case, you have already installed Express to run this app:

npm install express

To build an image, you will use a Dockerfile and then use the image to start a container. Create your Dockerfile as follows:

# Node.js base image
FROM node:20-alpine
# working directory
WORKDIR /app
# Copy package.json to the working directory
COPY package*.json ./
# Install dependencies
RUN npm install
# Copy code to the container at /app
COPY . /app
# Expose port 3000
EXPOSE 3000
# run your app
CMD ["node", "index.js"]

From this point, you can provide Dockerode with the context of your Dockerfile while using buildImage to return a Promise of NodeJS stream and create your custom Node.js API image.

In your Dockerode file setup (app.js), proceed and create your image name and add the image tag as such:

// Define the image name and tag
const imageName = "nodejs-api";
const imageTag = "latest";
const fullImageName = `${imageName}:${imageTag}`;

Then use buildImage method from Dockerode to extract the context on your Dockerfile. This example will assume your Dockerfile is at the same path as app.js. This way, Node.js will use Dockerode to read Dockerfile and other important related files such as index.js and package.json.

Your Dockerode buildImage method should look as follows:

// Build an image from the Dockerfile
docker.buildImage(
  { context: __dirname, src: ["Dockerfile", "index.js", "package.json"] },
  { t: fullImageName },
  (err, stream) => {
    if (err) {
      console.error(err);
      return;
    }

    docker.modem.followProgress(stream, onFinished, onProgress);

    function onFinished(err, output) {
      if (err) {
        console.error(err);
      } else {
        console.log("Image built successfully:", output);
      }
    }

    function onProgress(event) {
      console.log(event);
    }
  }
);

To build your image, you now need to run this file just like any other Node.js app:

node app.js

Guide to Node.js Dockerode with Docker and Docker Compose

Guide to Node.js Dockerode with Docker and Docker Compose

This should successfully build and tag your image. Go to Docker and confirm these results:

Guide to Node.js Dockerode with Docker and Docker Compose

Step 4: Creating Docker Containers using Dockerode and Node.js

The same process used to create images goes to the next step to build containers. With Dockerode, this step works the same as you would using the docker run command or docker-compose.

Dockerode will use the createContainer method to reference all parameters required to successfully launch a Docker container. Using the already built image, add the following additional steps:

  • First, you need port mapping to expose the container. Create a variable to do so:
// port mapping
const portMapping = {
  "3000/tcp": [{ HostPort: "3000" }],
};
  • Update the buildImage method. In this case, you want to create the container immediately after onFinished (Image built successfully) as follows:
docker.buildImage(
  { context: __dirname, src: ["Dockerfile", "index.js", "package.json"] },
  { t: fullImageName },
  (err, stream) => {
    if (err) {
      console.error(err);
      return;
    }

    docker.modem.followProgress(stream, onFinished, onProgress);

    function onFinished(err, output) {
      if (err) {
        console.error(err);
      } else {
        console.log("Image built successfully:", output);

        // Run a container from the built image
        docker.createContainer(
          {
            Image: fullImageName,
            // Container name
            name: "node-app-container",
            HostConfig: {
              PortBindings: portMapping,
            },
          },

          (err, container) => {
            if (err) {
              console.error(err);
              return;
            }

            container.start((err, data) => {
              if (err) {
                console.error(err);
              } else {
                console.log("Container started successfully:", data);
              }
            });
          }
        );
      }
    }

    function onProgress(event) {
      console.log(event);
    }
  }
);

Rerun your Node.js command:

node app.js

Guide to Node.js Dockerode with Docker and Docker Compose

This should create and run a container named port 3000 as follows:

Guide to Node.js Dockerode with Docker and Docker Compose

Open http://localhost:3000/ on the web, and you should have a successfully created Dockerode container:

Guide to Node.js Dockerode with Docker and Docker Compose

Step 4: Managing Docker Tasks with Dockerode Features

Docker allows you to manage other Docker app-related elements, such as list images, get running containers, and create networks and volumes. All these tasks are possible with Dockerode.

Below is a simple code to list local images and networks on Docker Engine:

docker.listImages((err, images) => {
  if (err) {
    console.error("Error listing images:", err);
    return;
  }

  console.log("Images:", images);
});

docker.listNetworks((err, networks) => {
  if (err) {
    console.error("Error listing networks:", err);
    return;
  }

  console.log("Networks:", networks);
});

Guide to Node.js Dockerode with Docker and Docker Compose

Step 6: Using Dockerode and Node.js with Docker Compose

Is it possible to use Dockerode to run Docker Compose Commands? docker-compose commands build and start services defined in the Docker Compose file (docker-compose.yml).

Docker Compose runs multi-container Docker applications. To do that programmatically using Node.js and Dockerode, you first install dockerode-compose package:

npm i dockerode-compose

This will give you access to compose commands to build and run your Docker Compose services.

Check dockerode-compose docs and learn how to use Docker Compose with Dockerode.

Conclusion

This guide helped you learn how Dockerode and Node.js make it easier to manage Docker containers with JavaScript. I hope you found the tutorial helpful!

Guide to Node.js Dockerode with Docker and Docker Compose

Written By:

Joseph Chege