【问题标题】:Using "tail -f /dev/null" to keep container up fails unexpectedly使用“tail -f /dev/null”来保持容器运行意外失败
【发布时间】:2017-10-06 04:28:31
【问题描述】:

我正在使用 tail -f /dev/null 命令来保持容器正常运行。

该行本身被放置在一个脚本中,前后都有一个回声。 tail -f /dev/null 下的回声预计无法访问,但由于某种原因,我在日志中看到了它。

一旦出现问题,每次重新启动容器都会导致容器启动并完成。只有 rm 和重新构建解决了这个问题。

我不确定它是否已连接,但我注意到在很短的时间间隔内停止和启动计算机有助于我重现该问题。

tail -f /dev/null在什么情况下可以继续下一行?

基础镜像: ubuntu 64x, 14.0.4

计算机操作系统: ubuntu 64x、14.0.4

【问题讨论】:

  • Curios here... 您希望 /dev/null 提供什么样的输出?你希望什么?
  • @Sokre - tail -f /dev/null 是一个常见的习惯用法,用于在“真实”命令不是长期存在的情况下使容器无限期地保持活动状态。
  • 只是为tail -f /dev/null 添加一些细节。 tail -f /dev/null 通常被添加,因为你的 docker 容器中的进程(pid 1)没有在前台运行,如果前台没有运行,docker 会自动关闭。
  • 为什么不“up -d”?
  • tail -f 从不可搜索的描述符(例如管道)中读取时确实会在 EOF 上停止。据我所知, /dev/null 安装在 docker 容器内。也许发生了一些事情,并且 /dev/null 被重新安装以触发 EOF。也可以尝试 -F (--follow) 而不是 -f 以便在重新创建时跟随文件

标签: docker ubuntu-14.04


【解决方案1】:

这是保持容器运行的更好方法

sleep infinity

【讨论】:

  • 这比我一直在使用的 bash while sleep 3600 循环要好得多,谢谢!
【解决方案2】:

回答您的问题tail -f /dev/null 在什么情况下可能会完成并因此继续以类似于 shell 脚本的方式进入下一行:

/dev/null(与 Linux 中的所有内容一样)是一个文件。在任何文件上执行tail 时,必须使用文件描述符打开该文件。并不是tail -f /dev/null 终止是因为它已经完成(它永远不会完成),它终止是因为文件描述符的干扰可能由于多种原因而发生,但是,在容器本身内部(很可能)什么都没有否则会干扰文件描述符。

由于 docker 容器只是所谓的Linux namespaces 的一个有点花哨的覆盖,所有在容器内运行的进程(即使它在单独的 PID 命名空间内)实际上都在您的主机上运行。 因此,由于某种原因,您的主机正在干扰您的文件描述符。

要检查进程创建的打开文件描述符,您可以执行以下命令:

$ sudo ls -la /proc/<pid>/fd

您将在输出中看到某些数字:

  • 0 代表标准输入。
  • 1 代表标准输出。
  • 2 代表标准错误。

其余的是进程正在打开的文件。

&lt;pid&gt; 是您要查看的进程的 ID。当tail -f /dev/null 作为容器内的入口点运行时,它很可能在容器内有 pid 1。为了在您的主机上找到 pid,您可以像这样简单地 grep :

$ sudo ps aux | grep 'tail -f /dev/null'

要自己关闭文件描述符并手动重现在这些情况下会发生的情况,您可以使用GNU debugger gdb。 只需将调试器附加到您之前找到的 pid:

$ sudo gdb attach <pid>

现在您可以继续选择要关闭的文件描述符(很可能是数字3,因为该进程不会打开任何其他文件):

(gdb) call (int)close(3)
$1 = 0

现在在离开调试器时检查容器的日志:

(gdb) quit

根据您的配置,您可能会在容器日志中看到来自 tail 的错误:

tail: error reading '/dev/null': Bad file descriptor

如前所述,还有一个用于标准错误的文件描述符 (2)。 您可以在同一个调试器会话期间重复整个过程并关闭标准错误和实际文件描述符:

(gdb) call (int)close(2)
$1 = 0
(gdb) call (int)close(3)
$2 = 0
(gdb) quit

这样做后,容器日志中不会出现错误,如果是 bash 脚本,它将继续执行下一行。

要检查究竟是什么干扰了您的文件描述符,您必须在发生时广泛监控您的主机系统。

【讨论】:

    【解决方案3】:

    曾经在我的一些测试环境中,/dev/null 不知何故是一个常规文件 - 也许也是这样?

    否则我会做echo EXIT CODE=$? 作为第二个回声并从那里跳舞。 另外用于测试 - 可以尝试用长时间睡眠替换 tail,然后通过 docker exec 执行 tail 命令,看看是否可以重现相同的行为。

    【讨论】:

      【解决方案4】:

      使用您选择的基本映像(例如 Ubuntu 64 位 14.0.4)创建一个 Dockerfile。在 Dockerfile 的末尾,添加如下一行:

      ENTRYPOINT ["tail", "-f", "/dev/null"]
      

      【讨论】:

      • 这似乎不是问题的答案。
      【解决方案5】:

      你可以使用docker命令

      docker run -d --name alpine alpine tail -f /dev/null

      另见How to retain docker alpine container after "exit" is used?

      【讨论】:

      • 这似乎不能回答为什么 shell 脚本中的命令在 tail 命令之后显然正在运行的问题。
      • 他已经在使用这个了,问题是它正在退出并且容器正在重新启动。他想知道它如何退出这个tail命令。
      猜你喜欢
      • 2023-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-11
      • 2020-10-24
      • 2018-07-12
      • 2016-11-27
      • 2010-11-02
      相关资源
      最近更新 更多