在Node中通过Dockerode操作Docker

Docker作为轻量级的虚拟化技术已经发展到了1.1的版本,然而从版本0.3.4开始,它就已经开始提供一套 Remote API。这套API是完全基于RESTful方式组织和设计的,通过它,常规的Docker操作都可以完成,例如:可以通过发送POST请求到/container/create创建一个Container,通过发送GET请求到/container/{id}/json对某个Container执行inspect操作等等。这就为我们提供一种可以远程操作Docker的方式。

当前,基于这套API的基于不同语言的客户端已经有很多了,大家可以访问这里找到他们:Remote API client libraries

这篇文章要介绍的是Dockerode,它是基于Javascript的一个客户端,项目地址:https://github.com/apocas/dockerode 。在Node使用它非常简单,首先使用NPM安装:

npm install --save dockerode

下面的代码可以列出所有Image的信息:

var Docker = require('dockerode');
var docker = new Docker({ socketPath: '/var/run/docker.sock' });

docker.listImages({}, function (err, data) {
  console.log(data);
});

在我本机得到的输出是:

[ { Created: 1404876476,
    Id: 'c13376ac176f3de146ef5dc895fac2135e322b746070ee8c368f206b2e636ab3',
    ParentId: '84773e31a0d1fd7a0498fd2d4cf6d6f16c756c030f0a7ddcf1077cb653f4d3bb',
    RepoTags: [ 'sshd:latest' ],
    Size: 0,
    VirtualSize: 314749357 },
  { Created: 1404164147,
    Id: '58faa899733f1db4bf5722b12da74e6edf3c67c8f6d8db6559f547f9416f3c7e',
    ParentId: '6c3df001ea12dcf848ff51930954e2129ac8f5717ce98819237d2d5d3e8ddd25',
    RepoTags: [ 'ubuntu:14.10', 'ubuntu:utopic' ],
    Size: 0,
    VirtualSize: 195975166 },
  { Created: 1403128455,
    Id: 'c5881f11ded97fd2252adf93268114329e985624c5d7bb86e439a36109d1124e',
    ParentId: '5796a7edb16bffa3408e0f00b1b8dc0fa4651ac88b68eee5a01b088bedb9c54a',
    RepoTags: [ 'ubuntu:quantal' ],
    Size: 70975627,
    VirtualSize: 172064416 },
  { Created: 1403128361,
    Id: 'e54ca5efa2e962582a223ca9810f7f1b62ea9b5c3975d14a5da79d3bf6020f37',
    ParentId: '6c37f792ddacad573016e6aea7fc9fb377127b4767ce6104c9f869314a12041e',
    RepoTags: [ 'ubuntu:14.04', 'ubuntu:latest', 'ubuntu:trusty' ],
    Size: 8,
    VirtualSize: 276100357 } ]

其他例子就不再说了,大家有兴趣可以看看官方提供的例子。不过,这里有一点需要特别指出就是Dockerode对Stream支持的很好。有了它,我们就可以实现很多好玩的东西,比如:实现在Web页面上的Terminal,这个在我后续的文章会介绍如何实现,这里先给一个命令行版本:

var Docker = require('../lib/docker');
var fs     = require('fs');

var socket = process.env.DOCKER_SOCKET || '/var/run/docker.sock';
var stats  = fs.statSync(socket);

if (!stats.isSocket()) {
  throw new Error("Are you sure the docker is running?");
}

var docker = new Docker({ socketPath: socket });
var optsc = {
  'Hostname': '',
  'User': '',
  'AttachStdin': true,
  'AttachStdout': true,
  'AttachStderr': true,
  'Tty': true,
  'OpenStdin': true,
  'StdinOnce': false,
  'Env': null,
  'Cmd': ['bash'],
  'Dns': ['8.8.8.8', '8.8.4.4'],
  'Image': 'ubuntu',
  'Volumes': {},
  'VolumesFrom': ''
};

function handler(err, container) {
  var attach_opts = {stream: true, stdin: true, stdout: true, stderr: true};

  container.attach(attach_opts, function handler(err, stream) {
    // Show outputs
    stream.pipe(process.stdout);

    // Connect stdin
    var isRaw = process.isRaw;
    process.stdin.resume();
    process.stdin.setRawMode(true);
    process.stdin.pipe(stream);

    container.start(function(err, data) {
      // Resize tty
      var resize = function() {
        var dimensions = {
          h: process.stdout.rows,
          w: process.stderr.columns
        };

        if (dimensions.h != 0 && dimensions.w != 0) {
          container.resize(dimensions, function() {});
        }
      };

      resize();
      process.stdout.on('resize', resize);

      container.wait(function(err, data) {
        process.stdout.removeListener('resize', resize);
        process.stdin.removeAllListeners();
        process.stdin.setRawMode(isRaw);
        process.stdin.resume();
        stream.end();
        process.exit();
      });
    });
  });
}

docker.createContainer(optsc, handler);

这个例子也是官方提供的,有了它,我们就可以实现像连接SSH那样来操作一个Docker Container了。

Written on July 11, 2014