Dockerfile 中 RUN 和 CMD 的区别
Posted
技术标签:
【中文标题】Dockerfile 中 RUN 和 CMD 的区别【英文标题】:Difference between RUN and CMD in a Dockerfile 【发布时间】:2016-09-24 12:25:35 【问题描述】:我对何时应该使用 CMD
和 RUN
感到困惑。例如,要执行 bash/shell 命令(即ls -la
),我将始终使用CMD
,或者是否存在使用RUN
的情况?试图了解这两个相似的Dockerfile
指令的最佳实践。
【问题讨论】:
docs.microsoft.com/en-us/virtualization/windowscontainers/… 【参考方案1】:RUN 是一个镜像构建步骤,RUN
命令之后的容器状态将提交给容器镜像。一个 Dockerfile 可以有许多 RUN
步骤,这些步骤相互叠加以构建映像。
CMD 是启动构建镜像时容器默认执行的命令。一个 Dockerfile 只会使用最终定义的CMD
。使用docker run $image $other_command
启动容器时,可以覆盖CMD
。
ENTRYPOINT也与CMD
密切相关,可以修改容器启动镜像的方式。
【讨论】:
你做了所有RUN
需要设置你的环境,并且你的(唯一的)CMD启动在你的容器中运行的进程,例如,对于nginx,从github.com/nginxinc/docker-nginx/blob/…中提取你看到@行987654332@
“一个 Dockerfile 只能有一个 CMD”——从技术上讲并不正确,但实际上除了一个之外的所有命令都将被忽略。查看 GingerBeer 的答案。
“一个 Dockerfile 将只使用最终定义的 CMD”?实际上,最终定义的 CMD 将用于启动镜像作为容器,对吧?
是的@paulcheung dockerfile 中的最终命令被写入镜像,并且是容器在启动构建镜像时默认执行的命令。
"一个 Dockerfile 将只使用最终定义的 CMD。" ——我只是浪费了过去的一个小时,因为我没有意识到这一点。如果他们要忽略这些,为什么他们至少不会给你一个警告?【参考方案2】:
RUN
- 在我们构建 docker 镜像时触发命令。
CMD
- 在我们启动创建的 docker 镜像时触发命令。
【讨论】:
【参考方案3】:我发现this 的文章对理解它们之间的区别很有帮助:
运行 - RUN 指令允许您安装应用程序和软件包 需要它。它在当前图像之上执行任何命令 并通过提交结果创建一个新层。很多时候你会发现 Dockerfile 中有多个 RUN 指令。
CMD - CMD 指令允许您设置默认命令,该命令将是 仅当您在不指定命令的情况下运行容器时执行。 如果 Docker 容器使用命令运行,则默认命令为 忽略。如果 Dockerfile 有多个 CMD 指令,除了最后一个 CMD 指令被忽略。
【讨论】:
那个链接太棒了!【参考方案4】:RUN - 安装 Python,你的容器现在已经将 python 烧入了它的镜像 CMD - python hello.py,运行你喜欢的脚本
【讨论】:
CMD - 安装 Python,我的容器现在没有将 python 烧入它的镜像吗? RUN会创建python的镜像层,CMD只会执行命令不创建镜像【参考方案5】:现有答案涵盖了查看此问题的任何人所需的大部分内容。所以我只会介绍 CMD 和 RUN 的一些小众领域。
CMD:允许重复但很浪费
GingerBeer 提出了一个重要的观点:如果您输入多个 CMD,则不会出现任何错误 - 但这样做很浪费。我想用一个例子来详细说明:
FROM busybox
CMD echo "Executing CMD"
CMD echo "Executing CMD 2"
如果你将它构建到一个镜像中并在这个镜像中运行一个容器,那么正如 GingerBeer 所说,只有最后一个 CMD 会被注意。所以该容器的输出将是:
执行 CMD 2
我的想法是“CMD”正在为正在构建的整个图像设置一个全局变量,因此连续的“CMD”语句只会覆盖之前对该全局变量的任何写入,并在最终图像中那是最后一个写胜利的人。由于 Dockerfile 是按从上到下的顺序执行的,我们知道最底层的 CMD 是获得这个最终“写入”的命令(比喻地说)。
RUN:如果图像被缓存,命令可能不会执行
关于 RUN 需要注意的一个微妙点是,即使存在副作用,它也会被视为纯函数,因此会被缓存。这意味着如果 RUN 有一些不会改变结果图像的副作用,并且该图像已经被缓存,则 RUN 将不会再次执行,因此副作用不会在后续构建中发生。例如,以这个 Dockerfile 为例:
FROM busybox
RUN echo "Just echo while you work"
第一次运行时,你会得到这样的输出,带有不同的字母数字 ID:
docker build -t example/run-echo .
Sending build context to Docker daemon 9.216kB
Step 1/2 : FROM busybox
---> be5888e67be6
Step 2/2 : RUN echo "Just echo while you work"
---> Running in ed37d558c505
Just echo while you work
Removing intermediate container ed37d558c505
---> 6f46f7a393d8
Successfully built 6f46f7a393d8
Successfully tagged example/run-echo:latest
请注意,上面执行了 echo 语句。第二次运行它,它使用缓存,你不会在构建的输出中看到任何回显:
docker build -t example/run-echo .
Sending build context to Docker daemon 9.216kB
Step 1/2 : FROM busybox
---> be5888e67be6
Step 2/2 : RUN echo "Just echo while you work"
---> Using cache
---> 6f46f7a393d8
Successfully built 6f46f7a393d8
Successfully tagged example/run-echo:latest
【讨论】:
【参考方案6】:注意:不要将 RUN 与 CMD 混淆。 RUN 实际上运行一个命令并且 提交结果; CMD 在构建时不执行任何操作,但是 指定图像的预期命令。
来自 docker 文件参考
https://docs.docker.com/engine/reference/builder/#cmd
【讨论】:
【参考方案7】:运行命令: RUN 命令基本上会在我们构建映像时执行默认命令。它还将为下一步提交图像更改。
可以有多个 RUN 命令,以帮助构建新映像。
CMD 命令: CMD 命令只会为新容器设置默认命令。这不会在构建时执行。
如果一个 docker 文件有超过 1 个 CMD 命令,那么除了最后一个之外,所有的命令都会被忽略。因为这个命令不会执行任何东西,只是设置默认命令。
【讨论】:
【参考方案8】:RUN:可以是多个,用于build过程,例如安装多个库
CMD:只能有 1 个,这是您的执行起点(例如["npm", "start"]
、["node", "app.js"]
)
【讨论】:
【参考方案9】:RUN 和 CMD 上已有足够的答案。我只想在 ENTRYPOINT 上补充几句。 CMD 参数可以被命令行参数覆盖,而 ENTRYPOINT 参数总是被使用。
This article 是一个很好的信息来源。
【讨论】:
那个链接太棒了!以上是关于Dockerfile 中 RUN 和 CMD 的区别的主要内容,如果未能解决你的问题,请参考以下文章
Dockerfile中CMD命令和ENTRYPOINT 命令的说明