Operations 7 min read

Control Docker Daemon Efficiently with Node.js

This tutorial explains how to use Node.js—via child processes, HTTP requests, or the Dockerode SDK—to create, manage, and interact with Docker containers, offering code examples and practical tips for efficient daemon communication.

Node Underground
Node Underground
Node Underground
Control Docker Daemon Efficiently with Node.js

Recently, due to work requirements, I needed to use Node.js to perform various Docker operations such as creating, deleting containers and issuing commands to retrieve results. Most online resources focus on containerizing Node.js apps rather than controlling Docker from Node.js, and Docker does not provide an official Node.js SDK. This article introduces how to efficiently send commands directly to the Docker daemon from Node.js.

Brief Introduction to Docker and Container Technology

Containers provide a lightweight, standard, and fast way to package and distribute software, using fewer resources and faster startup than traditional VMs. Docker Engine follows a client‑server model: the Docker CLI (e.g., run, ps, rm) sends commands to the Docker daemon, which executes them. Docker also exposes an HTTP API for direct daemon communication.

Note: The Docker daemon on the host uses a Unix socket, which the default Axios client does not support.

Ways to Issue Commands from Node.js

Expose the Docker service on a TCP port (see linked blog).

Use Node.js built‑in http module or third‑party packages such as got.

Use dockerode (https://www.npmjs.com/package/dockerode), a third‑party Docker SDK for Node.js.

Dockerode illustration
Dockerode illustration

Ordinary CLI Commands via Child Processes

Use child_process.exec or spawn to run Docker CLI commands in a subprocess.

const { exec } = require('child_process');
// list containers info
exec('docker ps -a', (err, stdout, stderr) => {
  if (err) {
    console.error(`exec error: ${err}`);
    return;
  }
  console.log(`stdout: ${stdout}`); // print all existing containers
  console.error(`stderr: ${stderr}`);
});
const { spawn } = require('child_process');
const { Readable } = require('stream');
// use terminal to pass commands
const container = spawn('docker', ['run', '-it', 'bash']);
process.stdin.pipe(container.stdin); // connect parent stdin to child stdin

// -it flag: i enables container stdin, t attaches a pseudo‑tty

container.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});
container.stderr.on('data', (data) => {
  console.error(`stderr: ${data}`);
});
container.on('close', (code) => {
  console.log(`child process exited with code ${code}`);
});

While these methods work, creating a new subprocess for each operation incurs significant overhead and does not leverage Node.js strengths. Therefore, the article proceeds to use Dockerode and the Docker HTTP API.

Dockerode – Docker + Node.js

Dockerode wraps the Docker API (built on Docker‑modem) and resolves networking issues. It offers both callback and promise interfaces; the examples below use async/await.

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

async function wrapper() {
  const opts = {
    Image: 'bash',
    AttachStdin: true,
    AttachStdout: true,
    AttachStderr: true,
    Tty: true,
    OpenStdin: true,
    StdinOnce: true,
    // AutoRemove: true,
  };
  const container_opts = {
    stream: true,
    stdin: true,
    stdout: true,
    stderr: true,
    // hijack: true, // must be true if not using process stdin
  };
  const container = await docker.createContainer(opts);
  const stream = await container.attach(container_opts);
  // pipe terminal input to container
  process.stdin.pipe(stream);
  stream.pipe(process.stdout);
  container.start();
}
wrapper();

Note: When using streams instead of CLI, set tty to false and add hijack: true in container_opts.

Conclusion

Using Node.js with Dockerode to send HTTP requests to the Docker daemon is a clean and efficient approach. The function parameters mirror Docker’s official documentation, but some configuration pitfalls require attention because Dockerode articles are scarce.

CLIDockerNode.jsContainer ManagementHTTP APIDockerode
Node Underground
Written by

Node Underground

No language is immortal—Node.js isn’t either—but thoughtful reflection is priceless. This underground community for Node.js enthusiasts was started by Taobao’s Front‑End Team (FED) to share our original insights and viewpoints from working with Node.js. Follow us. BTW, we’re hiring.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.