在使用shell脚本在Docker容器内运行脚本时,如何操作?

151

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

#!bin/bash

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

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

现在我需要从上面给出的shell脚本中运行已经存在于容器内部的脚本文件(test.sh)。(例如:cd /path/to/test.sh && ./test.sh)如何做到这一点?


1
为什么不使用WORKDIRCMD呢? - Dharmit
1
在这里,您可能不想使用--privileged。请参见:https://dev59.com/ZVoV5IYBdhLWcg3wTdQc - CMP
10个回答

186

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

docker exec mycontainer /path/to/test.sh

要从bash会话中运行:

docker exec -it mycontainer /bin/bash

从那里,你可以运行你的脚本。


9
如果我需要先进入/bin/bash,然后在该bash内运行命令,该怎么办? - zappy
97
您还可以直接从主机运行本地脚本docker exec -i mycontainer bash < mylocal.sh。这将读取本地主机脚本并在容器内部运行它。您可以对其他事物执行相同的操作(例如.tgz文件通过管道传输到tar中)- 只需使用“-i”将其传递到容器进程标准输入即可。 - Marvin
2
我不是PowerShell大师(谢天谢地),但我在Stack Overflow上闲逛,发现了https://dev59.com/VWgu5IYBdhLWcg3wRlFh#11788475。所以,也许可以尝试```Get-Content mylocal.sh | docker exec -i mycontainer bash```。不过我不确定这是否有效。 - Marvin
4
对我来说,这句话的意思是:使用命令 docker exec -i containerID /bin/sh < someLocalScript.sh,在容器中执行本地脚本。 - Charden Daxicen
请注意,像@Marvin那样在本地脚本中使用管道的负面影响是,在执行的脚本中使用选项set -e无效 - FireEmerald
显示剩余3条评论

149
假设您的docker容器正在运行中,您可以执行以下命令:

假设您的docker容器正在运行中,您可以执行以下命令:

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

2
我喜欢这个答案;您不必登录到Docker容器中执行命令或一组命令。谢谢! - Hatem Jaber
你知道如何进一步操作并将整个命令(/bin/sh -c "cmd1; cmd2; ...; cmdn")作为一个shell变量的值传递吗?我问这个问题是因为'docker run'似乎期望一个单独的命令和未引用的参数,而不是一个带引号的字符串。 - davidA
@meowsqueak:这个答案告诉你如何在不登录容器的情况下在已创建和运行的容器内运行多个命令,这对于自动化非常有帮助。但是,如果您想在容器创建时运行多个命令(PS:docker run命令创建并启动容器),您可以通过查看此同一线程中的其他答案来实现 https://dev59.com/g1wZ5IYBdhLWcg3wVfAC#41363989 - Raghwendra Singh
我需要传递整个for循环而不是cmd1,但它期望在loop语句和do语句之后有;。我如何将整个for循环作为单个命令即cmd1运行?这可能吗? - Nicholas K
正是我所需要的! - bwl1289

28
我搜索了同样的问题,并发现Dockerfile中的ENTRYPOINT对我有用。 Dockerfile
...
ENTRYPOINT /my-script.sh ; /my-script2.sh ; /bin/bash

现在脚本是在启动容器时执行的,当脚本执行完后,我会得到bash提示符。


11

如果您不想(或没有)运行容器,可以使用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

9

这个命令对我有用

cat local_file.sh | docker exec -i container_name bash

8

Thomio的答案很有帮助,但它期望脚本存在于图像内部。如果您拥有一个想要在容器内运行/测试(从命令行或作为脚本中有用的内容)的单个脚本,则可以使用

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

7
您也可以将本地目录挂载到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

更新

为了解决每次更改都需要打开一个新的shell的问题,现在我采取以下措施:

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

顺便说一下,您也可以在容器外定义历史记录文件。这样,就不再需要在每次bash更改时进行提交了。


太晚了..!@javier已经展示了一个直截了当的解决方案!!我觉得那个更好。 - zappy
2
@zappy,Javier提供的解决方案并不能很方便地解决我的问题,但我的解决方案却可以。我认为对于那些遇到类似问题的人来说,这将是有趣的,即当他们不想重启Docker镜像以更新所需的视图函数时。例如,如果您同时使用多个Docker镜像来旋转一个开发集群,您不希望经常重启它们。 - Devpool

3

这篇文章有些旧了,而且我没有足够的声望来发表评论。不过,我认为值得分享一下如何将Marvin的想法推广到允许参数的情况。

docker exec -i mycontainer bash -s arg1 arg2 arg3 < mylocal.sh

1

0
如果您想在多个实例上运行相同的命令,可以这样做:
for i in c1 dm1 dm2 ds1 ds2 gtm_m gtm_sl; do docker exec -it $i /bin/bash -c "service sshd start"; done

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接