升级docker-java到3.2.7版本如何获取容器运行命令的实时输出InputStream
docker-java 3.2.7版本attachContainerCmd适配方案
问题原因
docker-java从3.x版本开始重构了流式操作的实现逻辑:
- 无参
exec()方法不再返回InputStream,改为void类型 - 旧版
AttachContainerResultCallback已被废弃,官方推荐使用通用的ResultCallback接口处理流式返回 - 之前的代码报错是因为带回调参数的
exec()本身返回void,无法直接赋值给InputStream类型变量,同时回调类类型不匹配
方案1:通过管道流桥接获取InputStream(适配原有业务逻辑)
如果你的业务逻辑强依赖InputStream输入流,可以通过Piped流对回调输出做桥接,示例代码如下:
import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.model.Frame; import java.io.PipedInputStream; import java.io.PipedOutputStream; // 初始化管道流 PipedOutputStream pos = new PipedOutputStream(); PipedInputStream response = new PipedInputStream(pos); dockerClient.attachContainerCmd(container.getId()) .withLogs(true) .withStdErr(true) .withStdOut(true) .withFollowStream(true) .exec(new ResultCallback.Adapter<Frame>() { @Override public void onNext(Frame frame) { try { // 将容器输出的帧内容写入管道输出流 pos.write(frame.getPayload()); pos.flush(); } catch (Exception e) { onError(e); } } @Override public void onComplete() { try { pos.close(); } catch (Exception e) { // 处理流关闭异常 } super.onComplete(); } @Override public void onError(Throwable throwable) { try { pos.close(); } catch (Exception e) { // 忽略关闭异常 } super.onError(throwable); } }); // 后续可以正常使用response这个InputStream读取输出,注意读取操作要放在独立线程,避免阻塞回调线程
注意事项:
- 管道流的读写要放在不同线程,否则会出现死锁
- 要做好异常场景下的流关闭操作,避免资源泄漏
方案2:直接通过回调实现实时输出(推荐)
你的场景需要实时展示容器输出,直接用回调处理更简单,不需要额外维护输入流,示例代码如下:
dockerClient.attachContainerCmd(container.getId()) .withLogs(true) .withStdErr(true) .withStdOut(true) .withFollowStream(true) .exec(new ResultCallback.Adapter<Frame>() { @Override public void onNext(Frame frame) { // 直接将帧内容转为字符串,推送给展示层 String output = new String(frame.getPayload(), java.nio.charset.StandardCharsets.UTF_8); // 这里补充你的实时展示逻辑 System.out.print(output); } @Override public void onError(Throwable throwable) { // 处理执行异常,返回错误提示 throwable.printStackTrace(); } @Override public void onComplete() { // 容器执行结束,处理收尾逻辑,比如发送结束通知 } });
内容的提问来源于stack exchange,提问作者Matthew
相关产品推荐
相关产品推荐

