使用 shell 脚本在 docker 容器中运行脚本

Posted

技术标签:

【中文标题】使用 shell 脚本在 docker 容器中运行脚本【英文标题】:Running a script inside a docker container using shell script 【发布时间】:2015-10-13 05:34:42 【问题描述】:

我正在尝试创建一个用于设置 docker 容器的 shell 脚本。我的脚本文件如下所示:

#!bin/bash

docker run -t -i -p 5902:5902 --name "mycontainer" --privileged myImage:new /bin/bash

运行此脚本文件将在新调用的 bash 中运行容器。

现在我需要运行一个脚本文件(test.sh),它已经在上面给定的 shell 脚本的容器内。(例如:cd /path/to/test.sh && ./test.sh) 该怎么做?

【问题讨论】:

为什么不使用WORKDIRCMD 您可能不想在这里使用 --privileged。见:***.com/questions/36425230/… 【参考方案1】:

您可以使用docker exec [OPTIONS] CONTAINER COMMAND [ARG...] 在正在运行的容器中运行命令:

docker exec mycontainer /path/to/test.sh

并从 bash 会话运行:

docker exec -it mycontainer /bin/bash

您可以从那里运行您的脚本。

【讨论】:

如果我需要先进入 /bin/bash 然后在那个 bash 中运行命令怎么办? 您也可以直接从主机运行本地脚本docker exec -i mycontainer bash < mylocal.sh 这会读取本地主机脚本并在容器内运行它。你可以用其他东西来做这件事(比如 .tgz 文件通过管道传输到 tar 中)——它只是使用“-i”来管道到容器进程 std 输入。 @Marvin PowerShell 中的等价物是什么? “ 我不是 powershell 大师(谢天谢地),但我在 SO 附近闲逛并找到了 ***.com/a/11788475/500902。所以,也许Get-Content mylocal.sh | docker exec -i mycontainer bash。我不知道这是否有效。 对我来说是:docker exec -i containerID /bin/sh < someLocalScript.sh【参考方案2】:

假设您的 docker 容器已启动并正在运行,您可以运行以下命令:

docker exec mycontainer /bin/sh -c "cmd1;cmd2;...;cmdn"

【讨论】:

我喜欢这个答案;您不必登录到 docker 容器来执行一个或一组命令。谢谢! 您知道如何更进一步,将整个命令 (/bin/sh -c "cmd1; cmd2; ...; cmdn") 作为 shell 变量的值传递吗?我问是因为 'docker run' 似乎需要一个命令和单个未引用的参数,而不是引用的字符串。 @meowsqueak:这个答案告诉你如何在一个已经创建并正在运行的容器中运行多个命令,而无需登录该容器,这有助于自动化。但是,如果您想在创建容器时运行多个命令(PS:docker run 命令创建并启动容器),您可以通过在同一线程***.com/a/41363989/777617 中遵循答案来实现 代替cmd1,我需要传入一个完整的for循环——但它需要;loop语句和do之后i> 声明。如何将整个 for 循环作为单个命令运行,即cmd1?有可能吗? 正是我需要的!【参考方案3】:

我正在寻找同样问题的答案,并为我找到了 ENTRYPOINT in Dockerfile 解决方案。

Dockerfile

...
ENTRYPOINT /my-script.sh ; /my-script2.sh ; /bin/bash

现在脚本在我启动容器时执行,并且在脚本执行后得到 bash 提示。

【讨论】:

【参考方案4】:

如果您不想要(或拥有)正在运行的容器,您可以使用 run 命令直接调用您的脚本。

删除迭代 tty -i -t 参数并使用它:

    $ docker run ubuntu:bionic /bin/bash /path/to/script.sh

这将(未测试)也适用于其他脚本:

    $ docker run ubuntu:bionic /usr/bin/python /path/to/script.py

【讨论】:

【参考方案5】:

您还可以将本地目录挂载到您的 docker 映像中,并在您的 .bashrc 中获取脚本。不要忘记脚本必须由函数组成,除非您希望它在每个新 shell 上执行。 (这个已经过时了,见更新通知。)

我正在使用此解决方案来更新 docker 实例之外的脚本。这样,如果发生更改,我不必重新运行图像,我只需打开一个新的 shell。 (摆脱了重新打开 shell - 请参阅更新通知)

以下是绑定当前目录的方法:

docker run -it -v $PWD:/scripts $my_docker_build /bin/bash

现在您的当前目录已绑定到您的 docker 实例的 /scripts

(已过时) 要保存您的 .bashrc 更改,请使用以下命令提交您的工作映像:

docker commit $container_id $my_docker_build

更新

为了解决为每次更改打开新外壳的问题,我现在执行以下操作:

在 dockerfile 本身中,我添加了RUN echo "/scripts/bashrc" > /root/.bashrc"。在zshrc 中,我将脚本目录导出到路径。脚本目录现在包含多个文件而不是一个。现在我可以直接调用所有脚本,而无需在每次更改时打开子 shell。

顺便说一句,您也可以在容器之外定义历史文件。这样就不再需要提交 bash 更改了。

【讨论】:

太晚了..! @javier 已经展示了一个直接的解决方案!我觉得一个更好。 @zappy javier 的解决方案对我来说并没有方便地解决这个问题 - 但我的解决方案做到了,我认为这对于那些有类似问题但不想重新启动的人来说会很有趣docker image(s) 来更新他们需要的视图功能。例如,如果您一次使用多个 docker 镜像来启动一个开发集群,您不想一直重启它们。【参考方案6】:

这个命令对我有用

cat local_file.sh | docker exec -i container_name bash

【讨论】:

【参考方案7】:

也看看入口点。您将能够使用多个 CMD https://docs.docker.com/engine/reference/builder/#/entrypoint

【讨论】:

【参考方案8】:

Thomio's answer 很有帮助,但它希望脚本存在于图像中。如果您有一个想要在容器内运行/测试的脚本之一(从命令行或在脚本中有用),那么您可以使用

$ docker run ubuntu:bionic /bin/bash -c '
  echo "Hello there"
  echo "this could be a long script"
  '

【讨论】:

【参考方案9】:

如果您想在多个实例上运行相同的命令,您可以这样做:

for i in c1 dm1 dm2 ds1 ds2 gtm_m gtm_sl; do docker exec -it $i /bin/bash -c "service sshd start"; done

【讨论】:

以上是关于使用 shell 脚本在 docker 容器中运行脚本的主要内容,如果未能解决你的问题,请参考以下文章

在容器内运行 shell 脚本

Docker

如何运行多进程Docker容器

Docker 容器需要很长时间才能通过 shell 脚本启动

Docker Compose 多容器应用

企业——Docker compose的搭建