Dockerfile里的ENTRYPOINT和CMD

这篇具有很好参考价值的文章主要介绍了Dockerfile里的ENTRYPOINT和CMD。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

环境

  • RHEL 9.3
  • Docker Community 24.0.7

总结

如果懒得看详细介绍,可以直接看总结:

  • ENTRYPOINTCMD 都可以单独使用,指定启动容器时所运行的命令以及参数。
  • 更常见的用法是把 ENTRYPOINTCMD 组合使用:
    • ENTRYPOINT 指定启动容器时所运行的命令和不变的参数。在启动容器时可以显式覆盖,但一般不这么做。
    • CMD 指定运行参数。在启动容器时可以显式覆盖。
  • ENTRYPOINTCMD 都强烈推荐使用“exec形式”。

例如:

ENTRYPOINT ["ping", "-c", "20"]
CMD ["localhost"]

讲解

ENTRYPOINTCMD 指定启动容器时所运行的命令以及参数。二者都可以单独使用,也可以把二者组合使用。接下来通过示例来看一下二者的用法。

(一)不指定ENTRYPOINT和CMD

创建 Dockerfile 文件如下:

FROM ubuntu:trusty

构建:

docker build -t kaidemo0 .

启动容器:

docker run kaidemo0

结果什么也没有发生:既没有报错,也没有任何输出。

通过 docker ps -a 查看容器:

➜  ~ docker ps -a
CONTAINER ID   IMAGE                    COMMAND                  CREATED          STATUS                      PORTS                      NAMES
f3aeb967fdd2   kaidemo0                 "/bin/bash"              49 seconds ago   Exited (0) 48 seconds ago                              affectionate_noyce

可以看到,在没有指定 ENTRYPOINTCMD 时,实际运行的命令是 /bin/bash

要想与容器交互,可以加上 -it 选项:

➜  ~ docker run -it kaidemo0
root@1389cac2f57e:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@1389cac2f57e:/# ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 09:07 pts/0    00:00:00 /bin/bash
root          18       1  0 09:07 pts/0    00:00:00 ps -ef
root@1389cac2f57e:/# exit
exit

注:

  • -i :interactive,交互式的,接收用户输入
  • -t :tty,分配一个伪终端

也可在 docker run 时指定运行的命令,比如:

➜  ~ docker run kaidemo0 ping localhost
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.069 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.032 ms
64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.024 ms

在另一个命令行窗口,查看容器:

➜  test1 docker ps
CONTAINER ID   IMAGE            COMMAND                  CREATED         STATUS         PORTS                      NAMES
ab8ed71eae08   kaidemo0         "ping localhost"         3 seconds ago   Up 3 seconds                              interesting_dijkstra

最后,在第一个窗口,按下“Ctrl + C”停止ping命令,同时退出容器。

总结:若不指定ENTRYPOINT和CMD,启动容器时,默认运行的命令是 /bin/bash 。要显式加上 -it 选项才能进入容器做事。也可以在启动容器时显式指定运行的命令。

(二)CMD

创建 Dockerfile 文件如下:

FROM ubuntu:trusty
CMD ping localhost

构建:

docker build -t kaidemo1 .

启动容器:

docker run kaidemo1

由于 CMD 指令指定了 ping localhost 命令,容器启动时会自动运行该命令,如下:

➜  ~ docker run kaidemo1      
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.145 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.199 ms
64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.065 ms
^C64 bytes from localhost (127.0.0.1): icmp_seq=4 ttl=64 time=0.084 ms
64 bytes from localhost (127.0.0.1): icmp_seq=5 ttl=64 time=0.030 ms
......

注意:按下 “Ctrl + C” 无法停止ping命令,原因稍后解释。

在另一个命令行窗口,查看docker容器:

➜  ~ docker ps
CONTAINER ID   IMAGE            COMMAND                  CREATED         STATUS         PORTS                      NAMES
25e553984c8a   kaidemo1         "/bin/sh -c 'ping lo…"   7 seconds ago   Up 7 seconds                              sleepy_lalande

同样,尝试停止容器也无效:

➜  ~ docker stop 25e553984c8a
^C

docker stop 命令hang住了,只能按“Ctrl + C”中止。

最后,运行 docker rm -f 强制删除容器:

➜  ~ docker rm -f 25e553984c8a
25e553984c8a

原因解释:通过刚才的 docker ps 可以看到,实际运行的命令是 /bin/sh -c 'ping localhost'

  • docker run kaidemo0 ping localhost 时,在容器里查看进程:
➜  docker docker exec <container ID> ps -ef       
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 02:08 ?        00:00:00 ping localhost
root           7       0  0 02:09 ?        00:00:00 ps -ef
  • docker run kaidemo1 时,在容器里查看进程:
➜  docker docker exec <container ID> ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 02:12 ?        00:00:00 /bin/sh -c ping localhost
root           7       1  0 02:12 ?        00:00:00 ping localhost
root           8       0  0 02:12 ?        00:00:00 ps -ef
  • docker run -it kaidemo1 时,在容器里查看进程:
➜  docker docker exec <container ID> ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 02:16 pts/0    00:00:00 /bin/sh -c ping localhost
root           8       1  0 02:16 pts/0    00:00:00 ping localhost
root           9       0  0 02:16 ?        00:00:00 ps -ef

注意PID为1的进程,分别为:

  • ping localhost
  • /bin/sh -c ping localhost (没有TTY)
  • /bin/sh -c ping localhost (有TTY)

当我们在容器外部发送POSIX信号(比如“Ctrl + C”)到容器里,对于 docker run kaidemo1/bin/sh 命令不会转发消息给实际运行的ping命令,所以无法停止ping。

之所以出现这样的问题,是因为我们在Dockerfile里使用了“shell形式”,即:

CMD ping localhost

Docker会把该命令作为shell的子命令(即 /bin/sh -c xxxxx ),这就带来了问题。

为了避免这个问题,可以使用“exec形式”。

创建 Dockerfile 文件如下:

FROM ubuntu:trusty
CMD ["ping", "localhost"]

构建:

docker build -t kaidemo2 .

启动容器:

docker run kaidemo2

在另一个命令行窗口,查看容器:

➜  docker docker ps
CONTAINER ID   IMAGE            COMMAND                  CREATED         STATUS         PORTS                      NAMES
a6e67096ca3a   kaidemo2         "ping localhost"         6 seconds ago   Up 4 seconds                              stupefied_euler

查看容器里的进程:

➜  ~ docker exec <container ID> ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 02:33 ?        00:00:00 ping localhost
root           7       0  0 02:33 ?        00:00:00 ps -ef

可见,应尽量使用“exec形式”,以避免子shell的问题。

可以在启动容器时,显式指定要运行的命令,覆盖 CMD 的命令。例如:

➜  ~ docker run kaidemo2 ls -l 
total 8
drwxr-xr-x.   2 root root 4096 Dec 17  2019 bin
drwxr-xr-x.   2 root root    6 Apr 10  2014 boot
drwxr-xr-x.   5 root root  340 Jan  6 02:39 dev
......

总结:假设没有指定 ENTRYPOINT 指令,则 CMD 指令可以指定启动启动时要运行的命令。强烈推荐使用“exec形式”,以避免子shell的问题。可以在启动容器时,显式指定要运行的命令,覆盖 CMD 指定的命令。

(三)ENTRYPOINT

创建 Dockerfile 文件如下:

FROM ubuntu:trusty
ENTRYPOINT ping localhost

构建:

docker build -t kaidemo3 .

启动容器,可以发现, ENTRYPOINTCMD 的表现几乎一模一样。

因此,应尽量使用“exec形式”:

ENTRYPOINT ["ping", "localhost"]

另外,在启动容器时,覆盖 ENTRYPOINT 的方法和 CMD 不同,例如:

➜  ~ docker run kaidemo4 ls       
ping: unknown host ls

可见,运行的还是ping命令,只不过参数变成了 ls 。这是因为覆盖的是 CMD 指令,而不是 ENTRYPOINT 指令。关于二者的组合,稍后会有介绍。

要想覆盖 ENTRYPOINT 指令,可以使用 --entrypoint 选项:

➜  ~ docker run --entrypoint ls kaidemo4 
bin
boot
dev
......

但是,不推荐使用这种做法,原因稍后会有介绍。

总结: ENTRYPOINT 的表现几乎和 CMD 完全一致。假设没有指定 CMD 指令,则 ENTRYPOINT 指令可以指定启动启动时要运行的命令。强烈推荐使用“exec形式”,以避免子shell的问题。可以在启动容器时,通过 --entrypoint 选项显式指定要运行的命令,覆盖 ENTRYPOINT 指定的命令,但一般不这么做。

(四)ENTRYPOINT和CMD的组合

前面说了这么多, ENTRYPOINTCMD 貌似也没什么本质的区别,那为什么Dockerfile里要有两个相似的指令呢?

实际上,二者的设计理念不一样,典型的用法是把它们组合起来使用:

  • ENTRYPOINT :指定默认的启动程序
  • CMD :指定默认的运行参数

创建 Dockerfile 文件如下:

FROM ubuntu:trusty
ENTRYPOINT ["ping", "-c", "20"]
CMD ["localhost"]

注: -cping 命令的选项,c表示count, -c 20 就是ping 20次。

构建:

docker build -t kaidemo5 .

启动容器:

docker run kaidemo5

在另一个命令行窗口,查看容器:

➜  ~ docker ps                      
CONTAINER ID   IMAGE            COMMAND                  CREATED         STATUS         PORTS                      NAMES
135c6466f888   kaidemo5         "ping -c 20 localhost"   3 seconds ago   Up 2 seconds                              upbeat_vaughan

查看容器里的进程:

➜  ~ docker exec <container ID> ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 03:16 ?        00:00:00 ping -c 20 localhost
root           7       0  0 03:17 ?        00:00:00 ps -ef

可见,实际运行的命令,是把 ENTRYPOINT 的内容和 CMD 的内容组合起来了

  • ENTRYPOINT["ping", "-c", "20"]
  • CMD["localhost"]

最终命令是: ping -c 20 localhost

如果我们想ping另外一台主机,只需在 docker run 时覆盖 CMD 的值:

docker run kaidemo5 127.0.0.1

在另一个命令行窗口,查看容器:

➜  ~ docker ps
CONTAINER ID   IMAGE            COMMAND                  CREATED         STATUS         PORTS                      NAMES
b438242b4e84   kaidemo5         "ping -c 20 127.0.0.1"   3 seconds ago   Up 2 seconds                              intelligent_torvalds

查看容器里的进程:

➜  ~ docker exec <container ID> ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 03:25 ?        00:00:00 ping -c 20 127.0.0.1
root           8       0  0 03:25 ?        00:00:00 ps -ef

可见,通过覆盖 CMD 的值,就可以改变运行的参数。

在上面的例子里, -c 20 是写死在 ENTRYPOINT 里的,如果想要用户可以配置ping的次数,则应放在 CMD 里,以便用户在 docker run 时覆盖。

创建 Dockerfile 文件如下:

FROM ubuntu:trusty
ENTRYPOINT ["ping"]
CMD ["-c", "20", "localhost"]

构建:

docker build -t kaidemo6 .

启动容器:

docker run kaidemo6

效果和 docker run kaidemo5 是一样的,运行的都是 ping -c 20 localhost

启动容器时替换 CMD 参数:

docker run kaidemo6 -c 30 127.0.0.1

在另一个命令行窗口查看容器:

➜  ~ docker ps                      
CONTAINER ID   IMAGE            COMMAND                  CREATED         STATUS         PORTS                      NAMES
7885692cb508   kaidemo6         "ping -c 30 127.0.0.1"   4 seconds ago   Up 3 seconds                              wizardly_shtern

查看容器里的进程:

➜  ~ docker exec <container ID> ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 03:38 ?        00:00:00 ping -c 30 127.0.0.1
root           7       0  0 03:38 ?        00:00:00 ps -ef

可见,实际运行的是 ping -c 30 127.0.0.1

另外要注意的是,二者一定都要使用“exec形式”。如果使用“shell形式”,则会转为 /bin/sh xxx ,二者组合后,会造成混乱。

CMD localhost CMD [“localhost”]
ENTRYPOINT ping -c 10 /bin/sh -c ‘ping -c 10’ /bin/sh -c localhost /bin/sh -c ‘ping -c 3’ localhost
ENTRYPOINT [“ping”,“-c”,“10”] ping -c 10 /bin/sh -c localhost ping -c 3 localhost

可见,只有 二者都是“exec形式”时,才能组合出期望的结果。

总结: ENTRYPOINTCMD 组合使用:把运行命令和不变的参数放到 ENTRYPOINT 里,把可变的参数放到 CMD 里,以便在 docker run 时替换。二者都要使用“exec形式”。可用 --entrypoint 覆盖命令,但一般不这么做,因为 ENTRYPOINT 代表的是容器用途,一般不会改变,可变的是运行参数。文章来源地址https://www.toymoban.com/news/detail-819759.html

参考

  • https://spacelift.io/blog/docker-entrypoint-vs-cmd (里面有些内容和我实际测试结果不同,可能是Docker版本不同?)
  • https://zhuanlan.zhihu.com/p/30555962 (里面有些内容和我实际测试结果不同,可能是Docker版本不同?)
  • https://docs.docker.com/engine/reference/builder

到了这里,关于Dockerfile里的ENTRYPOINT和CMD的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • docker: CMD和ENTRYPOINT的区别

    ENTRYPOINT: 容器的执行命令(属于正统命令) 可以使用 --build-arg ENVIROMENT=integration 参数覆盖 ocker build --build-arg ENVIROMENT=integration 两者同时存在时 CMD 作为 ENTRYPOINT 的默认参数使用 外部提供参数会覆盖 CMD 提供的参数。 CMD单独存在时 CMD 替代 ENTRYPOINT 作为容器的执行命令 外部命

    2024年02月14日
    浏览(54)
  • Docker中,CMD 和 ENTRYPOINT 的区别,简单!明了!

    目录 CMD 和 ENTRYPOINT的区别:结论篇 CMD 和 ENTRYPOINT的其他细节结论 测试篇 一、 CMD的两种格式完全等效,但是ENTRYPOINT两种格式是有区别的 二、 docker run 命令替代了dockerfile的CMD命令 三、 docker run 命令在ENTRYPOINT的键值对格式下,是作为ENTRYPOINT命令的参数,docker run wx-centos ls -

    2024年02月05日
    浏览(39)
  • docker的run,cmd,entrypoint分析和对比

    本文一起看下Dockerfile中经常用到的几个类似命令,RUN,CMD,ENTRYPOINT。 想要有容器我们就必须先创建镜像,而想要有镜像,我们则必须写一个用来描述想要创建的镜像的文件,这个文件我们一般叫做Dockerfile (非强制) ,则容器怎么来的就如下图: 经过上图的 过程1 我们就有

    2024年02月01日
    浏览(34)
  • Dockerfile——ENTRYPOINT详解

      Entrypoint的作用是,把整个container变成了一个可执行的文件,这样不能够通过替换CMD的方法来改变创建container的方式。但是可以通过参数传递的方法影响到container内部。 ENTRYPOINT 有两种格式: ENTRYPOINT [“executable”, “param1”, “param2”] (exec 格式,首选) ENTRYPOINT command param

    2024年02月08日
    浏览(35)
  • Dockerfile ENTRYPOINT 使用变量

    如下 Dockerfile 文件中: 本意是想在 entrypoint 执行的命令中添加变量参数 JAVA_OPTS 和 PARAMS,如果按照这样写,变量是不被解析的,会报错。 那么正确的写法是使用 sh -c 命令来执行后面的命令,示例如下: (END)

    2024年02月16日
    浏览(36)
  • dockerfile ENTRYPOINT 执行.sh脚本提示找不到文件或文件不存在 No such file or directory

    我这里记录的是我遇到的一种特殊情况,如果你也遇到了这个问题,且都试了在百度中找到的解决方法还没有解决可以看看是不是和我遇到的问题一样。 在Dockerfile中,我ADD了两个文件,一个是jar包,一个是一个执行jar包的.sh文件 但是在使用命令: 就会提示 /bin/sh: 0: cannot

    2024年01月21日
    浏览(43)
  • Dockerfile(5) - CMD 指令详解

    指定容器默认执行的命令 重点 一个 Dockerfile 只有一个 CMD 指令,若有多个,只有最后一个 CMD 指令生效 CMD 主要目的:为容器提供默认执行的命令,这个默认值可以包含可执行文件 也可以不包含可执行文件,意味着必须指定 ENTRYPOINT 指令(第二种写法) exec 模式下使用环境变

    2024年03月23日
    浏览(38)
  • docker ENTRYPOINT 执行多条命令

    如何在docker里面同时启动多个pm2进程_祥仔先生的博客-CSDN博客_docker pm2 ENTRYPOINT 命令1 命令2 命令3 dockerfile中添加: RUN chmod -x setup.sh ENTRYPOINT [\\\"sh\\\", \\\"./setup.sh\\\"]

    2024年02月12日
    浏览(41)
  • 【云计算 | Docker】Docker容器后台运行不了?entrypoint在作妖?

    使用镜像 alpine 起个容器,使其保持后台运行,正常情况有如下的效果,可以发现容器保持运行状态。 但是有时候一些容器镜像按照上述方法却达不到预期效果。比如下面这个容器,一创建完就退出了。 那么问题出在哪个环节呢? 首先明确一个Docker容器的特性, docker容器运

    2024年02月14日
    浏览(39)
  • Docker之RUN、COMMAND、ENTRYPOINT辨析

    一  回顾docker一些命令 ①  run create start 的辨析 ②  获取 容器在宿主机 的PID docker inspect --format详解  ③  容器 资源 使用 ④  查看容器的 完整 命令     悬浮镜像dangling image 产生的原因和处理方法   ④  save 和 load ⑤⑥⑦⑧⑨⑩  二    Dockerfile指令的回顾 官网Dockerfile参考

    2024年02月06日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包