1.概述
在Dockerfile中,我们经常会遇到诸如run
, cmd,
或entrypoint
类的指令。乍一看,它们全部用于指定和运行命令。但是它们之间有什么区别?它们如何相互影响?
在本教程中,我们将回答这些问题。我们将介绍这些说明中的每一个做什么以及它们如何工作。我们还将研究它们在构建映像和运行Docker容器中所扮演的角色。
2.设定
首先,让我们创建一个脚本log-event.sh.
它只是在文件中添加一行,然后打印它:
#!/bin/sh
echo `date` [email protected] >> log.txt;
cat log.txt;
现在,让我们创建一个简单的Dockerfile:
FROM alpine
ADD log-event.sh /
在不同情况下,通过将行附加到log.txt
3. run
命令
当我们构建映像时,将run
这意味着传递给run
的命令将在新层的当前图像之上执行。然后将结果提交到图像。让我们看看它的实际效果。
首先,我们将run
指令添加到我们的Dockerfile中:
FROM alpine
ADD log-event.sh /
RUN ["/log-event.sh", "image created"]
其次,让我们用以下内容建立我们的形象:
docker build -t myimage .
现在,我们希望有一个包含log.txt
文件image created
行。让我们通过基于图像运行一个容器来检查这一点:
docker run myimage cat log.txt
当列出文件的内容时,我们将看到类似以下的输出:
Fri Sep 18 20:31:12 UTC 2020 image created
如果我们多次运行容器,我们将看到日志文件中的日期没有更改。这是有道理的,因为**run
步骤是在映像生成时执行的**,而不是在容器运行时执行的。
现在,让我们再次建立我们的镜像。我们注意到日志中的创建时间没有改变。发生这种情况是因为,如果Dockerfile不变,则Docker会缓存run指令的结果。如果要使缓存无效,则需要将–no-cache
选项传递给build命令。
4. cmd
命令
使用**cmd
指令,我们可以指定在容器启动时执行的默认命令。**让我们将一个cmd
条目添加到我们的Dockerfile中,并查看其工作方式:
...
RUN ["/log-event.sh", "image created"]
CMD ["/log-event.sh", "container started"]
构建完映像后,现在让我们运行它并检查输出:
$ docker run myimage
Fri Sep 18 18:27:49 UTC 2020 image created
Fri Sep 18 18:34:06 UTC 2020 container started
如果我们多次运行,我们将看到image created
的图像条目保持不变。但是container started
每次运行都会启动条目更新。这显示了每次容器启动时cmd
注意,这次我们使用了稍微不同的docker run
命令来启动我们的容器。让我们看看如果运行与之前相同的命令会发生什么:
$ docker run myimage cat log.txt
Fri Sep 18 18:27:49 UTC 2020 image created
这次将忽略Dockerfile中指定cmd
那是因为我们为docker run
命令指定了参数。
现在让我们继续前进,看看如果Dockerfile中cmd
让我们添加一个新条目,该条目将显示另一条消息:
...
RUN ["/log-event.sh", "image created"]
CMD ["/log-event.sh", "container started"]
CMD ["/log-event.sh", "container running"]
构建映像并再次运行容器后,我们将找到以下输出:
$ docker run myimage
Fri Sep 18 18:49:44 UTC 2020 image created
Fri Sep 18 18:49:58 UTC 2020 container running
如我们所见, container started
项不存在,只有container running
.
这是因为,如果指定了多个cmd,则仅调用最后一个cmd。
5. entrypoint
命令
正如我们在上面看到的,如果在启动容器时传递任何参数,则将忽略cmd
如果我们想要更大的灵活性怎么办?假设我们要自定义附加文本并将其作为参数传递给docker run
命令。为此,让我们使用entrypoint.
我们将指定在容器启动时运行的默认命令。而且,我们现在能够提供额外的参数。
让我们用entrypoint:
cmd
...
RUN ["/log-event.sh", "image created"]
ENTRYPOINT ["/log-event.sh"]
现在,通过提供一个自定义文本条目来运行容器:
$ docker run myimage container running now
Fri Sep 18 20:57:20 UTC 2020 image created
Fri Sep 18 20:59:51 UTC 2020 container running now
我们可以看到**entrypoint
行为与****cmd** .
另外,它允许我们自定义在启动时执行的命令。
与cmd
一样,在有多个entrypoint
条目的情况下,仅考虑最后一个条目。
cmd
与entrypoint
之间的交互
我们已经使用cmd
和entrypoint
来定义运行容器时执行的命令。现在让我们继续前进,看看如何结合使用cmd
和entrypoint
。
一种这样的用例是为entrypoint.
让我们在Dockerfile中的入口点之后cmd
entrypoint
...
RUN ["/log-event.sh", "image created"]
ENTRYPOINT ["/log-event.sh"]
CMD ["container started"]
现在,让我们在不提供任何参数的情况下运行容器,并使用cmd
指定的默认值:
$ docker run myimage
Fri Sep 18 21:26:12 UTC 2020 image created
Fri Sep 18 21:26:18 UTC 2020 container started
如果选择这样做,我们也可以覆盖它们:
$ docker run myimage custom event
Fri Sep 18 21:26:12 UTC 2020 image created
Fri Sep 18 21:27:25 UTC 2020 custom event
需要注意的是entrypoint
以外壳形式使用时的不同行为。让我们更新Dockerfile中entrypoint
...
RUN ["/log-event.sh", "image created"]
ENTRYPOINT /log-event.sh
CMD ["container started"]
在这种情况下,运行容器时,我们将看到Docker如何忽略传递给docker run
或cmd
任何参数。
7.结论
在本文中,我们已经看到了Docker指令之间的差异和相似之处: run
, cmd,
和entrypoint
。我们已经观察到它们在什么时候被调用。此外,我们还研究了它们的用途以及它们如何协同工作。
0 评论