如何通过docker run将参数传递给Shell Script

Aka*_*hta 108 bash shell command-line-arguments docker

我是码头工人世界的新手.我必须调用一个shell脚本,该脚本通过docker容器获取命令行参数.例如:我的shell脚本如下所示:

#!bin/bash
echo $1
Run Code Online (Sandbox Code Playgroud)

Dockerfile看起来像这样:

FROM ubuntu:14.04
COPY ./file.sh /
CMD /bin/bash file.sh
Run Code Online (Sandbox Code Playgroud)

我不确定如何在运行容器时传递参数

Par*_*udy 125

用这个脚本 file.sh

#!/bin/bash
echo Your container args are: "$@"
Run Code Online (Sandbox Code Playgroud)

还有这个 Dockerfile

FROM ubuntu:14.04
COPY ./file.sh /
ENTRYPOINT ["/file.sh"]
CMD []
Run Code Online (Sandbox Code Playgroud)

你应该能够:

% docker build -t test .
% docker run test hello world
Your container args are: hello world
Run Code Online (Sandbox Code Playgroud)

  • 如果你像我一样忘记了"/ file.sh"周围的"",它将无法正常工作. (7认同)
  • 由于某种原因,这不适用于`ENTRYPOINT./ file.sh` (6认同)
  • 不要忘记使用chmod + x file.sh来设置可执行标志。 (3认同)
  • @Nitzankin 请参阅我的答案,了解为什么需要正确的 json 格式。 (3认同)
  • @kev,你知道为什么会这样吗?`["/file.sh"]` 和 `/file.sh` 甚至 `[/file.sh]` 有什么区别 (2认同)

BMW*_*BMW 52

使用相同的 file.sh

#!bin/bash
echo $1
Run Code Online (Sandbox Code Playgroud)

使用现有的Dockerfile构建映像:

docker build -t test .
Run Code Online (Sandbox Code Playgroud)

使用参数abcxyz其他方式运行图像.

docker run -ti test /file.sh abc

docker run -ti test /file.sh xyz
Run Code Online (Sandbox Code Playgroud)

  • 如果您不希望最终用户直接了解file.sh,我认为ENTRYPOINT是可行的方法. (14认同)

小智 52

使用Docker,传递此类信息的正确方法是通过环境变量.

因此,使用相同的Dockerfile,将脚本更改为

#!/bin/bash
echo $FOO
Run Code Online (Sandbox Code Playgroud)

构建后,使用以下docker命令:

docker run -e FOO="hello world!" test
Run Code Online (Sandbox Code Playgroud)

  • 为什么这是最高的投票答案?Env vars是传递信息的另一种方式,但不是OP所要求的.当然,OP对于将args传递到容器的愿望绝对没有任何不妥之处. (16认同)
  • @PartlyCloudy我认为人们喜欢这样,因为它声称给出了"正确"的答案,尽管显然是错误的.Docker的一个主要设计原则是优先考虑常识的教条. (8认同)
  • SO上存在许多XY问题。由于OP指出他们是Docker的新手,因此给出建议的实现目标的建议是完全合理的答案。因此,这是一个很好的答案。 (2认同)
  • 完成工作的最简单方法,而不是将变量作为构建参数传递以及所有这些混乱。对于将秘密作为环境变量传递非常有用。 (2认同)

BMi*_*tch 20

这里有一些相互作用的东西:

  1. docker run your_image arg1 arg2将替代的价值CMDarg1 arg2.这完全取代了CMD,而不是为它添加更多的值.这就是为什么你经常看到docker run some_image /bin/bash在容器中运行bash shell的原因.

  2. 如果同时定义了ENTRYPOINT和CMD值,则docker会通过连接这两个并运行该连接命令来启动容器.因此,如果您将入口点定义为file.sh,则现在可以使用将作为args传递给的其他args运行容器file.sh.

  3. docker中的入口点和命令有两种语法,一种将启动shell的字符串语法,以及一种将执行exec的json语法.shell可用于处理IO重定向,将多个命令链接在一起(有类似的东西&&),变量替换等等.但是,这个shell会妨碍信号处理(如果你看到10秒延迟停止一个容器,这通常是原因)并将入口点和命令连接在一起.如果您将入口点定义为字符串,它将运行/bin/sh -c "file.sh",单独就可以了.但是如果你有一个命令被定义为一个字符串,你会看到像/bin/sh -c "file.sh" /bin/sh -c "arg1 arg2"在容器中启动的命令一样,不太好.有关这两个选项如何交互的更多信息,请参见此处的表格

  4. shell -c选项只接受一个参数.之后,一切都将获得通过的$1,$2等等,给一个参数,而不是在一个嵌入的shell脚本,除非你明确地通过了ARGS.即/bin/sh -c "file.sh $1 $2" "arg1" "arg2"工作,但/bin/sh -c "file.sh" "arg1" "arg2"不会因为file.sh没有args而被调用.

综合考虑,常见的设计是:

FROM ubuntu:14.04
COPY ./file.sh /
RUN chmod 755 /file.sh
# Note the json syntax on this next line is strict, double quotes, and any syntax
# error will result in a shell being used to run the line.
ENTRYPOINT ["file.sh"]
Run Code Online (Sandbox Code Playgroud)

然后你运行它:

docker run your_image arg1 arg2
Run Code Online (Sandbox Code Playgroud)

关于这方面有更多细节:

  • 我曾尝试将入口点设置为 `["bash", "--login", "-c"]` 以获取图像中的 /etc/profile 源,但后来想知道为什么没有参数传递给传递给 docker run 的 shell 脚本...您的回答澄清了这一点,谢谢! (2认同)

小智 18

我所拥有的是一个实际运行的脚本文件.此脚本文件可能相对复杂.我们称之为"run_container".此脚本从命令行获取参数:

run_container p1 p2 p3
Run Code Online (Sandbox Code Playgroud)

一个简单的run_container可能是:

#!/bin/bash
echo "argc = ${#*}"
echo "argv = ${*}"
Run Code Online (Sandbox Code Playgroud)

我想要做的是,在"dockering"之后,我希望能够使用docker命令行上的参数启动此容器,如下所示:

docker run image_name p1 p2 p3
Run Code Online (Sandbox Code Playgroud)

并使用p1 p2 p3作为参数运行run_container脚本.

这是我的解决方案:

Dockerfile:

FROM docker.io/ubuntu
ADD run_container /
ENTRYPOINT ["/bin/bash", "-c", "/run_container \"$@\"", "--"]
Run Code Online (Sandbox Code Playgroud)

  • 用`"/ run_container \"取代'ENTRYPOINT`数组中的第三个值$ @ \""`表示正确处理包含空格的参数(例如`docker run image_name foo'bar baz'quux`). (7认同)

Gil*_*not 5

如果要运行@build time:

CMD /bin/bash /file.sh arg1
Run Code Online (Sandbox Code Playgroud)

如果要运行@run time:

ENTRYPOINT ["/bin/bash"]
CMD ["/file.sh", "arg1"]
Run Code Online (Sandbox Code Playgroud)

然后在主机外壳中

docker build -t test .
docker run -i -t test
Run Code Online (Sandbox Code Playgroud)

  • 对于我认为需要运行时的OP,`ENTRYPOINT`是一个很好的答案,但是如果您确实想要构建时间变量,那么这个答案就被打破了。使用`ARG`和`docker build --build-arg` https://docs.docker.com/engine/reference/builder/#arg (2认同)