【问题标题】:Difference between RUN and CMD in a DockerfileDockerfile 中 RUN 和 CMD 的区别
【发布时间】:2016-09-24 12:25:35
【问题描述】:

我对何时应该使用 CMDRUN 感到困惑。例如,要执行 bash/shell 命令(即ls -la),我将始终使用CMD,或者是否存在使用RUN 的情况?试图了解这两个相似的Dockerfile 指令的最佳实践。

【问题讨论】:

标签: docker dockerfile


【解决方案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】:

            RUNCMD 上已有足够的答案。我只想在 ENTRYPOINT 上补充几句。 CMD 参数可以被命令行参数覆盖,而 ENTRYPOINT 参数总是被使用。

            This article 是一个很好的信息来源。

            【讨论】:

            • 那个链接太棒了!
            猜你喜欢
            • 1970-01-01
            • 2020-03-09
            • 1970-01-01
            • 2016-05-28
            • 2014-02-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-11-17
            相关资源
            最近更新 更多