【问题标题】:stdout being buffered in docker container标准输出在 docker 容器中缓冲
【发布时间】:2017-01-22 00:24:36
【问题描述】:

我不完全确定这里发生了什么,但是当我在容器中运行我的代码时,stdout 似乎正在被缓冲,但如果我在主机或 OSX 上运行它则不会。

https://github.com/myles-mcdonnell/procwrap/blob/master/procwrap.go

相关部分(为简洁而修改):

    cmd := exec.Command("ping", "127.0.0.1")

    logger := &lumberjack.Logger{
        Filename:   conf.LogFile,
        MaxSize:    conf.MaxLogSizeMb,
        MaxBackups: conf.MaxLogBackups,
        MaxAge:     conf.MaxLogAgeDays,
    }

    cmd.Stdout = io.MultiWriter(os.Stdout, logger)  

    err := cmd.Run()

在容器中运行,子进程运行良好,但我只能看到输出(到标准输出和日志文件)的间隔,就像正在刷新缓冲区一样。在容器外运行它并在生成时输出。我正在使用 go 1.6.3。我看到以交互方式和在后台运行容器的行为相同。

Docker 版本:

Client:
 Version:      1.10.3
 API version:  1.22
 Go version:   go1.5.3
 Git commit:   20f81dd
 Built:        Thu Mar 10 21:49:11 2016
 OS/Arch:      darwin/amd64

Server:
 Version:      1.12.0
 API version:  1.24
 Go version:   go1.6.3
 Git commit:   8eab29e
 Built:        Thu Jul 28 23:54:00 2016
 OS/Arch:      linux/amd64

======= 更新 ======

我看到基于基本图像的不同行为。在 debian:wheezy 基础上运行 procwrap 我得到缓冲输出。在 ubuntu:trusty 上做同样的事情是同步的。下面的 Dockerfiles,只需在每个上执行 'docker run {image_name}' 即可观察。在 wheezy VM(不涉及 docker)上运行 procwrap 不会缓冲输出。

信任:

FROM ubuntu:trusty
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y git
RUN curl -O https://storage.googleapis.com/golang/go1.6.3.linux-amd64.tar.gz
RUN tar -xvf go1.6.3.linux-amd64.tar.gz
RUN mv go /usr/local
ENV GOROOT=/usr/local/go
RUN mkdir -p /go/src/github.com/myles-mcdonnell
ENV GOPATH=/go
ENV PATH=$PATH:$GOPATH/bin:$GOROOT/bin
RUN go get github.com/myles-mcdonnell/procwrap
WORKDIR /go/src/github.com/myles-mcdonnell/procwrap
CMD procwrap -v

喘息:

FROM debian:wheezy
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y git
RUN curl -O https://storage.googleapis.com/golang/go1.6.3.linux-amd64.tar.gz
RUN tar -xvf go1.6.3.linux-amd64.tar.gz
RUN mv go /usr/local
ENV GOROOT=/usr/local/go
RUN mkdir -p /go/src/github.com/myles-mcdonnell
ENV GOPATH=/go
ENV PATH=$PATH:$GOPATH/bin:$GOROOT/bin
RUN go get github.com/myles-mcdonnell/procwrap
WORKDIR /go/src/github.com/myles-mcdonnell/procwrap
CMD procwrap -v

【问题讨论】:

    标签: go docker


    【解决方案1】:

    我遇到了同样的问题,看起来根本原因是“stdout 缓冲”。 如果有任何其他问题,您可以开始阅读http://www.pixelbeat.org/programming/stdio_buffering/ 和谷歌。 我无法通过“stdbuf”或任何 linux/app 设置来解决它,并更改了我想要 dockerize 以在每次写入时进行文件刷新的控制台应用程序的源代码。

    (由于很多原因,我的配置很奇怪,但它是:应用程序已将日志输出配置到名为“/dev/stdout”的文件中,并在每次写入日志时执行file_flush,docker可以真实显示消息“docker logs -f XXXXX”上的时间)

    【讨论】:

      【解决方案2】:

      这是你要问的吗?

      为什么我看到我的输出是成块的?它是否在某处被缓冲和刷新?

      是的。您的 Docker 容器在 Docker engine(可能由 Docker machine 包装)上运行,并且您的命令正在从客户端运行。即使您的引擎安装在本地并且您在交互模式下运行容器,您输入的命令和您看到的输出基本上仍然是针对localhost 的 HTTP 请求的结果。 (或 Unix Socket 或 TTY 通信。)(我在简化。)Docker 通过您的网络驱动程序路由 I/O,即它的标准输出必须刷新到(虚拟?)网络连接,然后客户端刷新 那个到你的标准输出。

      在后台模式下,引擎会捕获标准输出并将 (by default) 写入文件。 docker logs 命令从客户端向引擎发送请求,引擎通过读回该文件的内容来响应。

      【讨论】:

      • 我不明白为什么这可以解释为什么我会根据使用的基本图像得到不同的结果?详情请看我的更新。谢谢
      • 必须是weezy和trusty之间的低级差异。码头设施本身是非阻塞的。您甚至不应该在实际场景中手动刷新它,因为这会破坏 IO。我猜 trusty 中的某些组件是在实际缓冲设备上伪造同步行为。可能是兼容性问题。
      猜你喜欢
      • 2013-11-28
      • 2013-10-27
      • 1970-01-01
      • 2014-12-07
      • 2016-10-25
      • 1970-01-01
      • 2012-07-05
      • 2018-05-14
      • 1970-01-01
      相关资源
      最近更新 更多