如何在 Node 中实现类似于 docker-cli 的效果

查看 14|回复 0
作者:JerryYuan   
在给 Cronicle 开发一个 plugin,调用 docker 接口来启动一个任务实例,想把任务实例的 stdout 输出到 Cronicle 提供的任务日志功能里,目前可以实现一个字节不少的输出,只是我模拟了一下程序隔一段时间输出一次,但是因为 nodejs 的 http 收到数据后不会立刻触发 data 事件,需要等待一个缓冲区满了再一次性触发.
然后现象就是卡一段时间出一批,然后再卡一段时间出一批,而不是如 docker-cli 一样时间均匀地输出.
我试了一下,plugin 中直接定时输出一些数据,cronicle 是支持运行时实时展示程序输出的.
我使用的是 nodejs 的 dockerode 库来连接 docker,写了如下程序,基本排除了 cronicle 的问题,发现就是 node 在拷贝 docker attach 响应的流到 stdout 时有个缓冲区:
#!/usr/local/bin/node
//const JSONStream = require('pixl-json-stream');
//const Logger = require('pixl-logger');
const Docker = require('dockerode')
// setup stdin / stdout streams
process.stdin.setEncoding('utf8');
process.stdout.setEncoding('utf8');
async function run() {
    const client = new Docker({ host: "http://dockerhost", port: 2375 });
    console.log("client created")
    const container = await client.createContainer({
        Image: 'jerry/test:latest',
        AttachStdin: false,
        AttachStdout: true,
        AttachStderr: true,
        Tty: false,
        OpenStdin: false,
        StdinOnce: false,
        Env: [
            "TIMES=2000"
        ]
    })
    // 启动容器
    console.log("container created!")
    await container.start();
    console.log("container started!")
    // 连接到容器的输出流
    const attachOpts = { stream: true, stdout: true, stderr: true };
    const stream = await container.attach(attachOpts);
    console.log("container attached!")
    stream.setEncoding("utf-8")
   
        // 方案 1:dockerode 给的方案,数据不会丢,但不够实时
    //container.modem.demuxStream(stream, process.stdout, process.stderr);
        // 方案 2:data 事件触发
    stream.on('data',function(data){
            console.log(data);
    });
        // 方案 3:发现 readable 和 data 一样
    //// 按行读取容器的输出
    //stream.on('readable', function () {
    //    while ((line = stream.read()) != null) {
    //        logger.debug(1, new Date().getTime() + line)
    //    }
    //});
    // 等待容器自动退出
    await new Promise((resolve, reject) => {
        container.wait((err, data) => {
            clearInterval(timer)
            if (err) {
                reject(err);
            } else {
                console.log('Container exited with code:', data.StatusCode);
                resolve();
            }
        });
    });
    // 停止并删除容器
    await container.remove();
    console.log('Container removed.');
}
run()
想知道 node 是否有接口可以干掉那个缓冲区,或者把缓冲区搞得足够小,亦或者每隔 1 秒强制刷一次缓冲区.
模拟的用的程序,打包在了 jerry/test 中:
#!/bin/python
import time
import os
times = os.environ.get('TIMES')
if times:
    times = int(times)
else:
    times = 10
for i in range(times):
    print(f"Running {i}...")
    time.sleep(0.01)
您需要登录后才可以回帖 登录 | 立即注册

返回顶部