首页 文章

Dockerfile中CMD和ENTRYPOINT有什么区别?

提问于
浏览
1139

在Dockerfiles中有两个看起来与我类似的命令: CMDENTRYPOINT . 但是我猜它们之间有一个(微妙的?)区别 - 否则对于同样的事情有两个命令没有任何意义 .

CMD 的文档说明

CMD的主要目的是为执行容器提供默认值 .

并为 ENTRYPOINT

ENTRYPOINT可帮助您配置可作为可执行文件运行的容器 .

那么,这两个命令之间的区别是什么?

9 回答

  • 146

    ENTRYPOINT 指定在容器启动时始终执行的命令 .

    CMD 指定将被提供给 ENTRYPOINT 的参数 .

    如果您想制作专用于特定命令的图像,您将使用 ENTRYPOINT ["/path/dedicated_command"]

    否则,如果您想为通用目的制作图像,可以保留 ENTRYPOINT 未指定并使用 CMD ["/path/dedicated_command"] ,因为您可以通过向 docker run 提供参数来覆盖该设置 .

    例如,如果您的Dockerfile是:

    FROM debian:wheezy
    ENTRYPOINT ["/bin/ping"]
    CMD ["localhost"]
    

    不带任何参数运行映像将ping本地主机:

    $ docker run -it test
    PING localhost (127.0.0.1): 48 data bytes
    56 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.096 ms
    56 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.088 ms
    56 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.088 ms
    ^C--- localhost ping statistics ---
    3 packets transmitted, 3 packets received, 0% packet loss
    round-trip min/avg/max/stddev = 0.088/0.091/0.096/0.000 ms
    

    现在,使用参数运行图像将ping参数:

    $ docker run -it test google.com
    PING google.com (173.194.45.70): 48 data bytes
    56 bytes from 173.194.45.70: icmp_seq=0 ttl=55 time=32.583 ms
    56 bytes from 173.194.45.70: icmp_seq=2 ttl=55 time=30.327 ms
    56 bytes from 173.194.45.70: icmp_seq=4 ttl=55 time=46.379 ms
    ^C--- google.com ping statistics ---
    5 packets transmitted, 3 packets received, 40% packet loss
    round-trip min/avg/max/stddev = 30.327/36.430/46.379/7.095 ms
    

    为了比较,如果您的Dockerfile是:

    FROM debian:wheezy
    CMD ["/bin/ping", "localhost"]
    

    不带任何参数运行映像将ping本地主机:

    $ docker run -it test
    PING localhost (127.0.0.1): 48 data bytes
    56 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.076 ms
    56 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.087 ms
    56 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.090 ms
    ^C--- localhost ping statistics ---
    3 packets transmitted, 3 packets received, 0% packet loss
    round-trip min/avg/max/stddev = 0.076/0.084/0.090/0.000 ms
    

    但是使用参数运行图像将运行参数:

    docker run -it test bash
    root@e8bb7249b843:/#
    

    有关更多详细信息,请参阅Brian DeHamer的这篇文章:https://www.ctl.io/developers/blog/post/dockerfile-entrypoint-vs-cmd/

  • 1

    Docker有一个默认入口点 /bin/sh -c 但没有默认命令 .

    当你像这样运行docker时: docker run -i -t ubuntu bash ,入口点是默认的 /bin/sh -c ,图像是 ubuntu ,命令是 bash .

    该命令通过入口点运行 . 即,执行的实际内容是 /bin/sh -c bash . 这允许Docker依靠shell的解析器快速实现 RUN .

    后来,人们要求能够自定义它,因此引入了 ENTRYPOINT--entrypoint .

    在上面的示例中 ubuntu 之后的所有内容都是命令并传递给入口点 . 使用 CMD 指令时,就像你在做 docker run -i -t ubuntu <cmd> 一样 . <cmd> 将是入口点的参数 .

    如果您改为输入此命令 docker run -i -t ubuntu ,也会得到相同的结果 . 您仍将在容器中启动bash shell,因为ubuntu Dockerfile指定了默认CMD: CMD ["bash"]

    当所有内容都传递到入口点时,您可以从图像中获得非常好的行为 . @Jiri示例很好,它显示了如何将图像用作"binary" . 当使用 ["/bin/cat"] 作为入口点然后执行 docker run img /etc/passwd 时,你得到它, /etc/passwd 是命令并传递给入口点,因此最终结果执行只是 /bin/cat /etc/passwd .

    另一个例子是将任何cli作为入口点 . 例如,如果你有一个redis图像,而不是运行 docker run redisimg redis -H something -u toto get key ,你可以简单地使用 ENTRYPOINT ["redis", "-H", "something", "-u", "toto"] ,然后像这样运行相同的结果: docker run redisimg get key .

  • 128

    是的,这是一个很好的问题 . 我完全不了解它,但是:

    我知道 ENTRYPOINT 是正在执行的二进制文件 . 您可以通过--entrypoint =“”覆盖入口点 .

    docker run -t -i --entrypoint="/bin/bash" ubuntu
    

    CMD是容器的默认参数 . 如果没有入口点,则default参数是执行的命令 . 使用入口点,cmd作为参数传递给入口点 . 您可以使用入口点模拟命令 .

    # no entrypoint
    docker run ubuntu /bin/cat /etc/passwd
    
    # with entry point, emulating cat command
    docker run --entrypoint="/bin/cat" ubuntu /etc/passwd
    

    因此,主要优点是使用入口点可以将参数(cmd)传递给容器 . 要实现此目的,您需要同时使用:

    # Dockerfile
    FROM ubuntu
    ENTRYPOINT ["/bin/cat"]
    

    docker build -t=cat .
    

    然后你可以使用:

    docker run cat /etc/passwd
    #              ^^^^^^^^^^^
    #                   CMD
    #          ^^^      
    #          image (tag)- using the default ENTRYPOINT
    
  • 6

    简而言之:

    • CMD设置默认命令和/或参数,当docker容器运行时,可以从命令行覆盖它们 .

    • ENTRYPOINT命令和参数不会从命令行覆盖 . 相反,所有命令行参数将在ENTRYPOINT参数之后添加 .

    如果您需要更多详细信息或想在示例中看到差异,那么有一篇博文全面地比较了CMD和ENTRYPOINT以及大量示例 - http://goinbigdata.com/docker-run-vs-cmd-vs-entrypoint/

  • 29

    CMD:

    • CMD ["executable","param1","param2"]["executable","param1","param2"] 是第一个进程 .

    • CMD command param1 param2/bin/sh -c CMD command param1 param2 是第一个进程 . CMD command param1 param2 是从第一个进程分叉的 .

    • CMD ["param1","param2"] :此表单用于为 ENTRYPOINT 提供默认参数 .

    ENTRYPOINT(以下列表不考虑CMD和ENTRYPOINT一起使用的情况):

    • ENTRYPOINT ["executable", "param1", "param2"]["executable", "param1", "param2"] 是第一个进程 .

    • ENTRYPOINT command param1 param2/bin/sh -c command param1 param2 是第一个进程 . command param1 param2 是从第一个进程分叉的 .

    正如creack所说,CMD是第一个开发的 . 然后开发了ENTRYPOINT以进行更多定制 . 由于它们不是一起设计的,因此CMD和ENTRYPOINT之间存在一些功能重叠,这常常让人感到困惑 .

  • 330

    接受的答案很棒,可以解释历史 . 我发现这张表很好地解释了它official doc on 'how CMD and ENTRYPOINT interact'

  • 1204

    关于code中的EntryPoint函数的评论

    // ENTRYPOINT / usr / sbin / nginx . //将入口点(默认为sh -c)设置为/ usr / sbin / nginx . //将接受CMD作为/ usr / sbin / nginx的参数 .

    文件的另一个参考

    您可以使用ENTRYPOINT的exec形式设置相当稳定的默认命令和参数,然后使用CMD设置更可能更改的其他默认值 .

    Example:

    FROM ubuntu:14.04.3
    ENTRYPOINT ["/bin/ping"]
    CMD ["localhost", "-c", "2"]
    

    构建:sudo docker build -t ent_cmd .

    CMD arguments are easy to override.
    
    NO argument (sudo docker -it ent_cmd)                :  ping localhost 
    argument    (sudo docker run -it ent_cmd google.com) :  ping google.com
    

    .

    To override EntryPoint argument, you need to supply entrypoint
    sudo docker run -it --entrypoint="/bin/bash" ent_cmdd
    

    p.s:在EntryPoint存在的情况下,CMD将保留参与EntryPoint的参数 . 在没有EntryPoint的情况下,CMD将成为将要运行的命令 .

  • 22

    CMD和ENTRYPOINT之间的区别 by intuition

    • ENTRYPOINT:容器启动时运行的命令 .

    • CMD:在容器启动时运行的命令或ENTRYPOINT的参数(如果已指定) .

    是的,它正在混淆 .

    运行docker run时,您可以覆盖其中任何一个 .

    CMD和ENTRYPOINT之间的区别 by example

    docker run -it --rm yourcontainer /bin/bash            <-- /bin/bash overrides CMD
                                                           <-- /bin/bash does not override ENTRYPOINT
    docker run -it --rm --entrypoint ls yourcontainer      <-- overrides ENTRYPOINT with ls
    docker run -it --rm --entrypoint ls yourcontainer  -la  <-- overrides ENTRYPOINT with ls and overrides CMD with -la
    

    更多关于 CMDENTRYPOINT 之间的区别:

    docker run 的参数如/ bin / bash会覆盖我们在Dockerfile中编写的任何CMD命令 .

    使用正常命令(如 docker run [args] )无法在运行时覆盖ENTRYPOINT . docker run [args] 末尾的 args 作为ENTRYPOINT的参数提供 . 通过这种方式,我们可以创建一个 container ,就像一个普通的二进制文件,如 ls .

    所以CMD可以作为ENTRYPOINT的默认参数,然后我们可以从[args]覆盖CMD args .

    可以使用 --entrypoint 覆盖ENTRYPOINT .

  • 7

    根据docker docs

    CMD和ENTRYPOINT指令都定义了运行容器时执行的命令 . 很少有规则描述他们的合作 . Dockerfile应至少指定一个CMD或ENTRYPOINT命令 . 使用容器作为可执行文件时,应定义ENTRYPOINT . CMD应该用作为ENTRYPOINT命令定义默认参数或在容器中执行ad-hoc命令的方法 . 使用备用参数运行容器时,将覆盖CMD .

    下表显示 what command is executed for different ENTRYPOINT / CMD combinations

    • No ENTRYPOINT
    ╔════════════════════════════╦═════════════════════════════╗
    ║ No CMD                     ║ error, not allowed          ║
    ╟────────────────────────────╫─────────────────────────────╢
    ║ CMD [“exec_cmd”, “p1_cmd”] ║ exec_cmd p1_cmd             ║
    ╟────────────────────────────╫─────────────────────────────╢
    ║ CMD [“p1_cmd”, “p2_cmd”]   ║ p1_cmd p2_cmd               ║
    ╟────────────────────────────╫─────────────────────────────╢
    ║ CMD exec_cmd p1_cmd        ║ /bin/sh -c exec_cmd p1_cmd  ║
    ╚════════════════════════════╩═════════════════════════════╝
    
    • ENTRYPOINT exec_entry p1_entry
    ╔════════════════════════════╦═══════════════════════════════════════════════════════════╗
    ║ No CMD                     ║ /bin/sh -c exec_entry p1_entry                            ║
    ╟────────────────────────────╫───────────────────────────────────────────────────────────╢
    ║ CMD [“exec_cmd”, “p1_cmd”] ║ /bin/sh -c exec_entry p1_entry exec_cmd p1_cmd            ║
    ╟────────────────────────────╫───────────────────────────────────────────────────────────╢
    ║ CMD [“p1_cmd”, “p2_cmd”]   ║ /bin/sh -c exec_entry p1_entry p1_cmd p2_cmd              ║
    ╟────────────────────────────╫───────────────────────────────────────────────────────────╢
    ║ CMD exec_cmd p1_cmd        ║ /bin/sh -c exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd ║
    ╚════════════════════════════╩═══════════════════════════════════════════════════════════╝
    
    • ENTRYPOINT [“exec_entry”, “p1_entry”]
    ╔════════════════════════════╦═════════════════════════════════════════════════╗
    ║ No CMD                     ║ exec_entry p1_entry                             ║
    ╟────────────────────────────╫─────────────────────────────────────────────────╢
    ║ CMD [“exec_cmd”, “p1_cmd”] ║ exec_entry p1_entry exec_cmd p1_cmd             ║
    ╟────────────────────────────╫─────────────────────────────────────────────────╢
    ║ CMD [“p1_cmd”, “p2_cmd”]   ║ exec_entry p1_entry p1_cmd p2_cmd               ║
    ╟────────────────────────────╫─────────────────────────────────────────────────╢
    ║ CMD exec_cmd p1_cmd        ║ exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd  ║
    ╚════════════════════════════╩═════════════════════════════════════════════════╝
    

相关问题