Dockerfile 中的 CMD 与 ENTRYPOINT

1、概述

CMD 和 ENTRYPOINT 指令都用于定义容器启动时执行的命令,单从功能上来看,这两个命令几乎是重复的,单独使用其中的一个就可以实现绝大多数的用例。尽管如此,它们在某些情况下具有不同的用途和优势。这篇文章旨在澄清它们的用法,以帮助你在实际应用中做出明智的选择,避免混淆。

2、介绍

2.1 CMD 指令

CMD 用于指定容器启动时默认执行的命令及其参数。如果 Dockerfile 中包含多个 CMD 指令,则只有最后一个会生效。如果在运行容器时提供了命令参数,它们将覆盖 CMD 中定义的默认命令。

CMD 可以有三种形式:
  • CMD ["executable","param1","param2"](exec 形式,推荐使用,不会通过 shell 执行,更容易处理信号和参数)。
  • CMD command param1 param2(shell 形式,会通过 shell 执行)。
  • CMD ["param1","param2"](作为 ENTRYPOINT 的默认参数)。

2.2 ENTRYPOINT 指令

ENTRYPOINT 用于配置容器启动时执行的命令。如果 Dockerfile 中包含多个 ENTRYPOINT 指令,则只有最后一个会生效。ENTRYPOINT 与 CMD 一起使用时,CMD 的内容会作为参数传递给 ENTRYPOINT 指定的命令。

ENTRYPOINT 可以有两种形式:

  • ENTRYPOINT ["executable", "param1", "param2"](exec 形式,可使用CMD的参数和可使用docker run后面追加的参数)。
  • ENTRYPOINT command param1 param2(shell 形式,不会使用 CMD参数,不可使用docker run后面追加的参数)。

2.3 CMD 与 ENTRYPOINT 的Shell格式和Exec格式

Shell格式:指令 <command>,以 CMD 指令为例。

CMD java -jar test.jar

Exec格式:指令 ["executable", "param1", "param2", ...], 以 CMD 指令为例。

CMD ["nginx", "-g", "daemon off;"]

Shell格式中的命令会直接被Shell解析,Exec格式不会直接解析,需要加参数。

2.4 CMD 与 ENTRYPOINT主要区别

CMD 与 ENTRYPOINT都是用于指定启动容器执行的命令,区别在于:

  • 当docker run 命令中有参数时,守护进程会忽略CMD命令。
  • 使用ENTRYPOINT指令不会忽略,并且会接收docker run 参数附加到命令行中。

为了使构建的容器可以正常启动,我们编写的dockerfile文件必须包含一个CMD或ENTRYPOINT指令(指令在父镜像中的存在也可以)。

3、CMD 与 ENTRYPOINT的结合使用

dockerfile文件中包含多个CMD时,只有最后一个被加载使用。我们在dockerhub中搜索centos官方镜像,看一下的官方dockerfile文件。我们查看latest标签的dockerfile。

FROM scratch
ADD centos-8-x86_64.tar.xz /
LABEL org.label-schema.schema-version="1.0"     org.label-schema.name="CentOS Base Image"     org.label-schema.vendor="CentOS"     org.label-schema.license="GPLv2"     org.label-schema.build-date="20201204"
CMD ["/bin/bash"]

只有四行,这就是构建一个latest版本centos8.3.2011镜像的dockerfile全部内容。指定基镜像(这里从scratch这个空镜像开始构建),添加rootfs内容,打标签,通过CMD指定启动命令。
不止centos,其他debian、ubuntu、busybox等镜像都只需通过CMD指定启动命令,比如busybox更为简约。

FROM scratch
ADD busybox.tar.xz /
CMD ["sh"]

这种基础类、工具类镜像的构建我们只需要指定一个必要CMD来启动容器即可。但是我们编写一个dockerfile并不是为了启动容器而编写,大多数时候我们要在容器运行我们的app,运行我们的服务。

当然通过CMD也可以启动,可是如此一来有一个缺陷,我们上面说到的CMD的启动命令会被docker run 参数代替,我们有下面Dockerfile。

FROM centos
CMD ["/bin/top","-b"] 

构建后,使用参数ps启动容器。

[root@localhost dockerfiles]# docker run  -it  centos_top:v1  ps
  PID TTY          TIME CMD
    1 pts/0    00:00:00 ps

可看看到启动容器后top -b 已经被替换为ps,并非实现参数的替换。显然这不是我们想要的。有没有什么办法既可以默认启动应用,又可以加载到docker run 参数? 这就是接下来ENTRYPOINT与CMD的妙用。

在2.1章节我们提到CMD ["param1","param2"]形式可以作为ENTRYPOINT参数,同时ENTRYPOINT 指定的命令无法被docker run 参数取代。假如我们把CMD和ENTRYPOINT两个指令相结合,这样我们就可以通过CMD来接收docker run 参数,然后把参数传递给ENTRYPOINT执行。

我们以nginx官方dockerfile latest版本1.21为例,首先我们查看Dockerfile,这里我们只关注启动命令,如下:

...
COPY docker-entrypoint.sh /
COPY 10-listen-on-ipv6-by-default.sh /docker-entrypoint.d
COPY 20-envsubst-on-templates.sh /docker-entrypoint.d
COPY 30-tune-worker-processes.sh /docker-entrypoint.d
ENTRYPOINT ["/docker-entrypoint.sh"]
​
EXPOSE 80
​
STOPSIGNAL SIGQUIT
​
CMD ["nginx", "-g", "daemon off;"]

从上面我们可以看到,在启动nginx容器时首先运行docker-entrypoint.sh脚本并把CMD命令中的参数nginx -g "daemon off;"传递进来。即docker run不添加参数时启动容器相当于执行如下脚本与默认参数。

#docker-entrypoint.sh nginx -g "daemon off;"

当我们使用docker run 传入参数会怎样?传入nginx-debug

#docker run -dt nginx nginx-debug -g "daemon off;"

此时启动容器相当于执行如下脚本与参数。

#docker-entrypoint.sh nginx-debug -g "daemon off;"

我们通过ps来看一下我们启动的容器。

# docker run不添加参数
root      6327  6306  0 Aug12 pts/0    00:00:00 nginx: master process nginx -g daemon off;
101       6384  6327  0 Aug12 pts/0    00:00:00 nginx: worker process
101       6385  6327  0 Aug12 pts/0    00:00:00 nginx: worker process
# docker run添加参数
root     16800 16780  3 12:51 pts/0    00:00:00 nginx: master process nginx-debug -g daemon off;
101      16857 16800  0 12:51 pts/0    00:00:00 nginx: worker process
101      16858 16800  0 12:51 pts/0    00:00:00 nginx: worker process
​

显然我们两种参数nginx、nginx-debug的容器都启动成功!

也就是说我们通过ENTRYPOINT ["/docker-entrypoint.sh"]指定的命令在启动时无论如何都会执行,并且可以接收到了docker run 的参数。

4、总结

通过ENTRYPOINT+CMD实现命令默认参数或接收docker run 参数是一种非常流行并且有用的dockerfile编写方式。

5、其他

参考:本文大部分内容都是参考《dockerfile中ENTRYPOINT与CMD的结合》这篇博文。

优质博文:Dockerfile中CMD与ENTRYPOINT命令的区别

优质博文:Dockerfile 中的 CMD 与 ENTRYPOINT 

posted @ 2023-10-10 16:23  人艰不拆_zmc  阅读(1764)  评论(0编辑  收藏  举报