使用 Node.js 操作 Docker,不是使用 Dcoker 容器化 Node.js 服务哦!

大厂技术  高级前端  Node进阶

点击上方 程序员成长指北,关注公众号

回复1,加入高级Node交流群

最近因为工作,需要通过 Node.js 对 Docker 进行一系列操作如,创建删除容器以及下发指令获取结果等。找了一圈网上大部分资源都是如何容器化 Node.js App 而非通过 Node.js 操作 Docker,Docker 官方也并未提供针对 Node.js 的 sdk,所以这篇文章就简单带大家了解一下如何通过 Node.js 相对高效的向 Docker daemon 直接下发指令。

Docker 及容器技术简单介绍

  • 因为本公众号之前已经介绍过 Docker 的基本用法,所以在这里只做简单回顾。有需要的读者可以去翻一下之前的文章或者直接上官网查看。https://docs.docker.com/reference/

  • 容器化出现的目的是以一种更加轻量、标准、快速的方式对软件代码进行打包以及分发。相比于传统 VM,容器化技术使用更少的系统资源占用率且拥有更快的应用启动速度。

  • Docker Engine 类似 Client-sever 模式。用户通过 Docker CLI 如 run、ps、rm 等将指令下发给 Docker daemon 再由 daemon 去执行对应操作Docker 官方同时也提供了一系列 http 协议的接口也可以对 daemon 直接下发指令。

    参考:https://docs.docker.com/engine/api/v1.41/#section/Versioning

注意: Docker daemon 在本机上使用 Unix-socket,常用的 Axios 并不支持。

在这提供几种解决方式有兴趣的同学可以动手操作看看:

  1. 让 Docker 服务监听 Tcp 端口。
    参考:

    https://blog.k4nz.com/adb7b5a9eeef48def89317ea9b808f7d/

  2. 使用 Node.js 原生的 http 模组或者其他 npm 包,如 got

  3. 使用 Dockerode,第三方 Docker sdk on Node.js89bfca18260bf6b81e993138821e662f.png

如何通过 Node.js 向 Docker daemon 下发指令

普通 cli 指令

使用 child_process 模组中的 exec、spawn 函数,通过子进程执行 Docker 提供的 cli 指令。

如下所示:

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')
// 使用terminal传入指令
const container = spawn('docker', ['run', '-it', 'bash']);
process.stdin.pipe(container.stdin); // connect parent stdin to child stdin


// -it flag: i是开启容器stdin,t是attach一个pseudo-tty,具体参考docker官方reference


// 通过stream的的方式传入指令
// const container = spawn('docker', ['run', '-i', 'bash']);
// const buffer = new Readable();
// buffer.pipe(container.stdin);
// buffer.push('ls');
// buffer.push(null);
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}`);
});

通过上面两种方式可以实现向 Docker daemon 下发指令,但是对于每次操作都需要创建并维护一个新的子进程,因此开销会很大,而且也不是 Node.js 的优势所在,因此接下来会结合第三方 docker-node sdk Dockerode 和 Docker http Api,通过 http 请求的方式实现上面的目标。

Dockerode = Docker + Node.js (https://www.npmjs.com/package/dockerode)

Dockerode 是基于 Docker-modem 在已经解决了所有网络问题(端口、协议)的基础上将 Docker Api 封装而成的 sdk。
Dockerode 中所有函数都提供了两种写法,callback 和 promise 的写法。官网提供的大多是 callback 的写法,在这里我们主要会使用 promise 结合 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, // tty is set false if not using process stdin
    OpenStdin: true,
StdinOnce: true,
// AutoRemove: true,
  };


const container_opts = {
stream: true,
stdin: true,
stdout: true,
stderr: true,
// hijack: true, !! must be set true here if not using process stdin
  };


const container = await docker.createContainer(opts);
const stream = await container.attach(container_opts);


// 通过terminal传入指令
  process.stdin.pipe(stream);
  stream.pipe(process.stdout);


// 通过buffer传入指令
// const d = new Duplex();
// d._write = () => {}; // avoid trivial error
// d.pipe(stream);
// stream.pipe(d);
// stream.on('data', (data) => {
//   // do some work on result here
// });
// d.push('ls');
// d.push(null);


  container.start();
}


wrapper();

以上介绍两种使用 Dockerode 替代 cli 命令的写法。

请注意作为区别于 cli 方式,使用 stream 将指令传入的方式,务必将 tty 设定成 false,在 container_opts 中添加 hijack:true

参考:https://github.com/apocas/dockerode/issues/455#issuecomment-489436370

总结

Dockerode 使用 Node.js 最擅长的方式通过 http 请求对 Docker daemon 下发指令,干净且高效。调用Dockerode 中函数的参数配置同 Docker 的官方文案。只是网上关于 Dockerode 文章不多,且使用时,有些配置有坑需要注意。

以上

Node 社群

我组建了一个氛围特别好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你对Node.js学习感兴趣的话(后续有计划也可以),我们可以一起进行Node.js相关的交流、学习、共建。下方加 考拉 好友回复「Node」即可。

6558854d089dffbaaa319ac04139c1f4.jpeg

如果你觉得这篇内容对你有帮助,我想请你帮我2个小忙:

1. 点个「在看」,让更多人也能看到这篇文章

2. 订阅官方博客 www.inode.club 让我们一起成长

点赞和在看就是最大的支持

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值