在Dockerfile中运行脚本

175

我尝试在我的Dockerfile构建过程中运行一个脚本,但看起来没有成功。

我是这样尝试的:

FROM php:7-fpm
ADD bootstrap.sh /
ENTRYPOINT ["/bin/bash", "/bootstrap.sh"]

同样的方法:

FROM php:7-fpm    
ADD bootstrap.sh /
RUN bash -c "/bootstrap.sh"

同时也可以通过执行我的正在运行的容器来完成:

docker exec symfony /bin/bash -c "/bootstrap.sh"

似乎什么都不起作用。

你知道怎么做吗?


bootstarp.sh 是否设置了可执行位? - jwodder
像这样运行 chmod +x /bootstarp.sh? - Kevin
2
“不起作用”指的是什么?它显示了一个错误吗?文件是否存在于镜像中?如果您在容器内执行 docker exec -it symfony bash,能否手动运行脚本并检查其内容 (cat bootstarp.sh)? - thaJeztah
尝试运行以下命令:docker exec symfony /bin/bash /bootstarp.sh,并告诉我输出结果。 - Boynux
28
哎呀,太棒了!(原文非标准英语,表达惊喜和兴奋) - Bruno Bronosky
有时候,使用脚本的绝对路径而不是相对路径可能会更有帮助,例如 "/bootstrap.sh" --> <绝对路径>/bootstrap.sh - abk
6个回答

212

RUNENTRYPOINT是两种执行脚本的不同方式。

RUN表示它创建一个中间容器、运行脚本并将该容器的新状态冻结在一个新的中间镜像中。此后脚本将不再运行:您的最终镜像应该反映出该脚本的结果。

ENTRYPOINT表示您的镜像(尚未执行脚本)将创建一个容器,并运行该脚本。

在这两种情况下,都需要添加脚本,而且建议使用 RUN chmod +x /bootstrap.sh 命令进行许可操作。

脚本还应该以shebang(例如#!/bin/sh)开头。

考虑到您的脚本(bootstrap.sh:一些git config --global命令),最好在您的 Dockerfile 中用 RUN 命令运行该脚本一次,但务必使用正确的用户(全局git config文件是 %HOME%/.gitconfig,默认为/root)。

将以下内容添加到您的Dockerfile中:

RUN /bootstrap.sh

接着,在运行容器时,检查/root/.gitconfig的内容以确认脚本已经运行。


11
你可能是想说 bootstrap.sh 而不是 bootstarp.sh:查看 https://dev59.com/cHM_5IYBdhLWcg3wt1vD#1254561。 - VonC
1
第一行的shebang对我有用,谢谢! :) - GDICommander
请查看开箱即用的 Docker 镜像 - https://hub.docker.com/repository/docker/myset/bootstrap - Cristian Florescu
@myset 有趣的想法:执行 $BOOTSTRAP,并在运行时将该变量设置为您想要执行的内容。 - VonC

59

除了上面的答案:

如果你在Windows中创建/编辑.sh脚本文件,请确保它保存为Unix格式的行结尾。默认情况下,Windows中的许多编辑器会将Unix换行符转换为Windows格式,并且Linux将无法识别文件开头的shebang(#!/bin/sh)。因此,Linux会产生类似于没有shebang的错误消息。

提示:

  • 如果您使用Notepad ++,则需要单击“编辑/ EOL转换/ UNIX(LF)”
  • 如果您使用Visual Studio,则建议安装“End Of Line”插件。然后,您可以通过按Ctrl-R、Ctrl-W使行结束符可见。要设置Linux样式的行结束符,可以按Ctrl-R、Ctrl-L。对于Windows样式,请按Ctrl-R、Ctrl-C。

1
我的VSCode在Windows中自动将shell脚本的行结尾设置为CRLF。由于一些随机字符,Docker构建失败了。我更改了VS Code中的设置,它立即开始工作了。谢谢!我已经点赞了。 - Adithya Upadhya
在Windows上,git默认使用CR+LF进行检出,这会导致在创建Docker镜像时对shell脚本造成问题,因此您的答案非常有帮助! - AntonK
1
提示:最好给从docker运行的脚本添加扩展名(例如.sh),并在您的git存储库根目录中添加一个.gitattributes文件,其中包含以下内容:*.sh text eol=lf。然后您就不必担心换行符了。 - Marinos An
@MarinosAn,好建议,尽管当你编辑文件时文本编辑器可能会放置错误的结尾。但是,我同意,无论如何拥有那个git设置都是好的。 - VeganHunter

28

尝试使用ADD命令并指定工作目录来创建脚本,例如("script"是脚本的名称,/root/script.sh是您希望其位于容器中的位置,它可以是不同的路径:

ADD script.sh /root/script.sh

在这种情况下,如果您有一个,ADD 必须放在 CMD 之前。顺便说一句,这是从主机机器导入脚本到容器中的酷方法。

CMD 中放置 [./script]

它应该自动执行您的脚本

您还可以将 WORKDIR 指定为 /root,然后在启动容器时会自动放置在根目录中。


Docker 是如何最初识别 script.sh 的位置的呢?我的意思是,第一个参数 script.sh - sunsets
由于您正在构建容器,因此您也负责放置路径。 - Michael
第一个参数 script.sh 的路径和名称是相对于 Dockerfile 的。 - eja
@eja 看起来不是这样的:“源代码需要在运行docker build命令的目录内。” - David Dahan

22

当你从本地文件系统复制到镜像时,最好使用COPY而不是ADD。此外,我建议创建一个子文件夹来放置您的内容。即使别的都不行,也要保持整洁。确保使用chmod将脚本标记为可执行。

在这里,我正在创建一个名为scripts的子文件夹来放置我的脚本并从中运行:

RUN mkdir -p /scripts
COPY script.sh /scripts
WORKDIR /scripts
RUN chmod +x script.sh
RUN ./script.sh

4
WORKDIR /scripts
COPY bootstrap.sh .
RUN ./bootstrap.sh 

4
在容器创建时运行bash脚本的方法:
创建一个名为 script.sh 的文件:
#!/bin/bash
you commands

如果您正在使用Windows操作系统,您必须更改script.sh文件的约定。为此,在Notepad ++中,转到编辑-> EOL转换->从CRLF更改为LF,这样您的bash文件就可以有效地执行。
如果您正在使用Alpine映像,则必须在您的bash文件的第一行中使用#!/bin/sh而不是#!/bin/bash
然后,在Dockerfile中,将您的bash文件复制到映像中,并在创建容器时使用ENTRYPOINT指令运行该文件:
COPY script.sh /
RUN chmod +x /script.sh
ENTRYPOINT ["/script.sh"]

请注意,ENTRYPOINT指令使用您复制到镜像中的bash文件的位置。
现在,当您创建容器时,script.sh文件将会执行。

1
注意:如果您正在使用Alpine镜像,则必须在Bash文件的第一行中使用“#!/bin/sh”而不是“#!/bin/bash”。感谢您的发现。 - Benny

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