【问题标题】:How to run command during Docker build which requires a tty?如何在需要 tty 的 Docker 构建期间运行命令?
【发布时间】:2016-01-13 06:12:51
【问题描述】:

我有一些脚本需要在 Docker 构建期间运行,它需要一个 tty(Docker 在构建期间不提供)。在后台,脚本使用read 命令。 有了一个tty,我可以做(echo yes; echo no) | myscript.sh之类的事情。

没有它,我会收到一些我不完全理解的奇怪错误。那么有什么方法可以在构建过程中使用这个脚本(鉴于它不是我的修改?)

编辑:这是一个更明确的错误示例:

FROM ubuntu:14.04
RUN echo yes | read

失败:

Step 0 : FROM ubuntu:14.04
 ---> 826544226fdc
Step 1 : RUN echo yes | read
 ---> Running in 4d49fd03b38b
/bin/sh: 1: read: arg count
The command '/bin/sh -c echo yes | read' returned a non-zero code: 2

【问题讨论】:

  • 您确定没有 tty 是问题所在吗?根据this answer,“read: arg count”错误是由于 /bin/sh 中的 read 内置函数需要一个参数(存储标准输入回复的变量)而 /bin/bash 不需要(它使用$REPLY 作为默认值)。
  • 我发布了赏金,为了赢得它,我正在寻找手头问题的解决方案,而不是“你不需要那个”的答案。我知道原始问题“可以”在没有 tty 的情况下解决,我想知道它是否可以根据问题“使用”tty 来解决。如果我们都可以假设 OP 发布了一个虚拟问题来演示该问题,而不是对于这个论坛来说太长的真正复杂的实际问题,那么我们都会相处得很好。我知道如何解决我遇到的特定 sudo 问题,但我仍然需要一个 tty 来处理其他事情,例如当执行到正在运行的容器中时......
  • @EngineerDollery 你有没有在构建 Dockerfile 期间需要 TTY 的示例? docker exec 不是这样的示例,因为您没有进行构建,并且您在该命令上有 -t 选项。目前,构建的答案是它不是一种选择,也没有人提供一个例子来证明它甚至是需要的。
  • Sudo 就是一个很好的例子。在我这里,我们使用 ansible 来配置机器,包括 docker 映像,并且由于我们必须对所有机器使用相同的脚本,因此我们不允许将任何 docker 特定的东西放在那里,所以我 yum install ansible 并运行在再次卸载 ansible 之前适当的剧本(ssh 是不可能的)。 Ansible 使用 sudo,而 sudo 被破坏(至少在 centos 上)因为它需要 tty(这是一个众所周知的错误)。
  • 如果一切都失败了,请调查expect

标签: linux docker tty dockerfile


【解决方案1】:

您不需要 tty 将数据输入脚本。只需按照您的建议执行(echo yes; echo no) | myscript.sh 之类的操作即可。还请确保在尝试执行之前先复制文件。类似COPY myscript.sh myscript.sh

【讨论】:

    【解决方案2】:

    您很可能不需要 tty。正如对问题的评论所示,即使提供的示例也是read 命令未被正确调用的情况。 tty 会将构建转变为交互式终端过程,这不能很好地转化为可以从没有终端的工具运行的自动化构建。

    如果您需要一个 tty,则可以在派生包含伪 tty 的进程时使用对 openpty 的 C 库调用。您也许可以使用expect 之类的工具来解决您的问题,但是时间太长了,我不记得它是否创建了 ptty。或者,如果您的应用程序无法自动构建,您可以在正在运行的容器中手动执行这些步骤,然后在生成的容器中 docker commit 制作镜像。

    我建议不要使用其中任何一种方法,并制定出构建应用程序并以非交互方式安装它的过程。根据应用程序,修改安装程序本身可能更容易。

    【讨论】:

      【解决方案3】:

      RUN <command> in Dockerfile 参考:

      shell形式,命令在shell中运行,Linux默认为/bin/sh -c,Windows默认为cmd /S /C

      让我们看看 /bin/sh 在 ubuntu:14.04 中到底是什么:

      $ docker run -it --rm ubuntu:14.04 bash
      root@7bdcaf403396:/# ls -n /bin/sh
      lrwxrwxrwx 1 0 0 4 Feb 19  2014 /bin/sh -> dash
      

      /bin/sh是dash的符号链接,见dash中的read函数:

      $ man dash
      ...
      read [-p prompt] [-r] variable [...]
                  The prompt is printed if the -p option is specified and the standard input is a terminal.  Then a line
                  is read from the standard input.  The trailing newline is deleted from the line and the line is split as
                  described in the section on word splitting above, and the pieces are assigned to the variables in order.
                  At least one variable must be specified.  If there are more pieces than variables, the remaining pieces
                  (along with the characters in IFS that separated them) are assigned to the last variable.  If there are
                  more variables than pieces, the remaining variables are assigned the null string.  The read builtin will
                  indicate success unless EOF is encountered on input, in which case failure is returned.
      
                  By default, unless the -r option is specified, the backslash ``\'' acts as an escape character, causing
                  the following character to be treated literally.  If a backslash is followed by a newline, the backslash
                  and the newline will be deleted.
      ...
      

      read 中的dash 函数:

      必须至少指定一个变量。

      让我们看看bash中的read函数:

      $ man bash
      ...
      read  [-ers]  [-a aname] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name...]
      If  no names are supplied, the line read is assigned to the variable REPLY.  The return code is zero,
                    unless end-of-file is encountered, read times out (in which case the  return  code  is  greater  than
                    128), or an invalid file descriptor is supplied as the argument to -u.
      ...
      

      所以我猜你的脚本myscript.sh 是以#!/bin/bash 或其他东西开头,但不是/bin/sh

      另外,您可以更改您的Dockerfile,如下所示:

      FROM ubuntu:14.04
      RUN echo yes | read ENV_NAME
      

      链接:

      【讨论】:

      • 不过,这完全没有意义;命令退出后,该变量将丢失。
      猜你喜欢
      • 1970-01-01
      • 2023-03-24
      • 2022-11-09
      • 2021-07-28
      • 2020-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多