Dockerfile中RUN和CMD之间的区别


Answers:


424

RUN是映像构建步骤,RUN命令后将容器的状态提交到容器映像。一个Dockerfile可以具有许多RUN步骤,这些步骤相互叠加以构建映像。

CMD是启动构建映像时默认情况下容器执行的命令。Dockerfile将仅使用最终CMD定义的。使用CMD启动容器时可以覆盖docker run $image $other_command

ENTRYPOINT也与CMD容器密切相关,并且可以修改容器启动图像的方式。


15
您完成了RUN设置环境所需的所有操作,(仅)CMD启动了在容器中运行的进程,例如,对于nginx,请从github.com/nginxinc/docker-nginx/blob/中提取……,您会看到以下一行CMD ["nginx", "-g", "daemon off;"]
user2915097

“一个Dockerfile只能有一个CMD”-从技术上讲不是正确的,但实际上除一个以外的所有内容都将被忽略。请参阅GingerBeer的答案。
Colm Bhandal

“ Dockerfile将仅使用定义的最终CMD”?实际上,最终定义的CMD将在启动映像时用作容器,对吗?
保罗

1
是@paulcheung,泊坞窗文件中的最终命令已写入映像,并且是启动构建映像时容器默认执行的命令。
马特

126

RUN -在构建docker映像时触发命令。

CMD -在启动创建的docker映像时触发命令。


67

我发现这篇文章对理解它们之间的区别非常有帮助:

RUN -RUN指令可让您安装应用程序和所需的软件包。它在当前图像的顶部执行任何命令,并通过提交结果来创建新层。通常,您会在Dockerfile中找到多个RUN指令。

CMD -CMD指令允许您设置默认命令,仅当您运行容器而不指定命令时才会执行该命令。如果Docker容器使用命令运行,则默认命令将被忽略。如果Dockerfile具有多个CMD指令,则除最后一个CMD指令外的所有
指令都将被忽略。



8

RUN命令:在构建映像时,RUN命令将基本上执行默认命令。它还将提交图像更改以进行下一步。

可以有1个以上的RUN命令,以帮助构建新映像。

CMD命令:CMD命令将为新容器设置默认命令。这将不会在构建时执行。

如果docker文件具有多个1个CMD命令,则除最后一个命令外,所有其他命令都将被忽略。因为此命令将不执行任何操作,而只是设置默认命令。



4

RUN:可以很多,并且在构建过程中使用,例如,安装多个库

CMD:只能有1个,也就是你的执行起点(例如["npm", "start"]["node", "app.js"]


2

现有的答案涵盖了任何关注此问题的人所需要的大部分内容。因此,我将仅介绍CMD和RUN的一些细分领域。

CMD:允许重复但浪费

GingerBeer提出了一个重要的观点:如果您输入多个CMD,不会有任何错误-但是这样做很浪费。我想举一个例子:

FROM busybox
CMD echo "Executing CMD"
CMD echo "Executing CMD 2"

如果将其构建到映像中并在该映像中运行容器,则正如GingerBeer所述,仅注意最后一个CMD。因此,该容器的输出将是:

执行CMD 2

我的想法是,“ CMD”正在为要构建的整个映像设置单个全局变量,因此连续的“ CMD”语句仅会覆盖先前对该全局变量的所有写入操作,并覆盖最终生成的映像。最后一个写胜利。由于Dockerfile是从上到下依次执行的,因此我们知道最底层的CMD是获得最终“写入”的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

1

RUNCMD上已经有足够的答案。我只想在ENTRYPOINT上添加几句话。命令行参数可以覆盖CMD参数,而始终使用ENTRYPOINT参数。

本文是很好的信息来源。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.