CMD¶
指令¶
EXEC格式:CMD ["executable","param1","param2"]
SHELL格式:CMD command param1 param2
做为ENTRYPOINT参数:CMD ["param1","param2"]
描述¶
CMD 提供容器运行时的默认主进程命令及参数。
一个Dockerfile中只能有一行 CMD 有效,如果定义了多行 CMD,则只有最后一行生效。
该指令不是在镜像 docker build 构建时执行,而是在镜像构建完成后 docker run 运行容器时默认执行的指令。
如果在 docker run 时指定了启动命令时,那么该 Dockerfile 中定义的 CMD 指令将会被覆盖不会执行。
比如,ubuntu 镜像默认的 CMD 是 /bin/bash
,如果直接 docker run -it ubuntu
的话,会直接进入 bash。也可以在运行时指定其他的运行命令,如 docker run -it ubuntu cat /etc/os-release
。这就是用 cat /etc/os-release
命令替换了默认的 /bin/bash
命令,输出了系统版本信息。
EXEC格式 和 SHELL格式 的差异¶
EXEC格式 和 SHELL格式 是两种不同的进程运行方式。使用 SHELL 格式 时是Docker调用 SHELL 来执行命令,而 EXEC 格式 是由Docker直接进行系统调用的方式执行命令。所以在使用 EXEC格式 执行时是无法获取SHELL的信息的,例如:
这是无法获取 $HOME
的变量内容的,因为该变量是SHELL中的环境变量,系统调用时是没有该环境变量信息的。使用EXEC格式时获取SHELL信息可以使用如下方法:
这时docker会调用 sh 来执行命令,就可以获取到 $HOME
的内容了
如果希望容器每次都运行相同的可执行文件,则应考虑将 ENTRYPOINT 结合使用 CMD,使用 CMD 来指定运行参数,而实际执行的命令由 ENTRYPOINT 来指定。
当 Dockerfile 中指定了 ENTRYPOINT 时,CMD 将作为该指令的参数。这时 CMD 和 ENTRYPOINT 指令都需要使用 EXEC参数 的形式,他将会被解析为 JSON 数组的格式。需要使用双引号 “
括起来而不能单引号 ‘
。
容器中应用在前台执行和后台执行的问题¶
Docker 不是虚拟机,容器中的应用都应该以前台执行,而不是像虚拟机、物理机里面那样,用 systemd 去启动后台服务,容器内不建议使用后台服务。
错误的CMD使用:
在运行容器时会发现容器执行后就立即退出了。甚至在容器内去使用 systemctl 命令结果却发现根本执行不了。这就是因为没有搞明白前台、后台的概念,没有区分容器和虚拟机的差异,依旧在以传统虚拟机的角度去理解容器。
对于容器而言,其启动的程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出,其它辅助进程不是它需要关心的东西。
而使用 service nginx start 命令,则是希望以后台守护进程形式启动 nginx 服务。 CMD service nginx start
会被理解为 CMD [ "sh", "-c", "service nginx start"]
,因此主进程实际上是 sh。
那么当 service nginx start 命令结束后,sh 也就结束了,sh 作为主进程退出了,自然就会令容器退出。
正确的做法是直接执行 nginx 可执行文件,并且要求以前台形式运行。比如:
Dockerfile中的CMD
指令详解¶
文章摘要¶
本文聚焦于Dockerfile中的CMD
指令,详细解析其功能、语法、使用场景以及与其他相关指令(如ENTRYPOINT
)的区别。CMD
指令用于指定容器启动时默认执行的命令或参数,是Dockerfile中定义容器行为的关键指令之一。
核心内容¶
1. 功能与语法¶
- 功能:
CMD
指令用于定义容器启动时默认执行的命令或参数。- 如果用户在运行容器时未指定命令,则使用
CMD
定义的默认命令。 - 如果用户指定了命令,则
CMD
定义的命令会被覆盖。
- 语法格式:
- Exec形式:
CMD ["executable","param1","param2"]
(推荐使用,避免shell解析问题)。 - Shell形式:
CMD command param1 param2
。
- Exec形式:
2. 使用场景¶
- 定义容器的默认启动命令:
- 例如启动一个Web服务器或运行一个脚本。
- 与
ENTRYPOINT
指令结合使用:CMD
可以作为ENTRYPOINT
的默认参数。
3. CMD
与ENTRYPOINT
的区别¶
ENTRYPOINT
:- 定义了容器启动时的主命令,不可被覆盖。
CMD
:- 提供默认命令或参数,可以被
docker run
命令行参数覆盖。
- 提供默认命令或参数,可以被
- 同时存在时:
CMD
的内容会作为ENTRYPOINT
的默认参数。
4. 最佳实践¶
- 使用Exec形式:
- 避免Shell形式可能导致的信号传递问题。
- 灵活覆盖默认命令:
- 在需要灵活覆盖默认命令时使用
CMD
,在需要固定主命令时使用ENTRYPOINT
。
- 在需要灵活覆盖默认命令时使用
5. 示例¶
- 示例1:
- 启动Nginx并保持前台运行。
- 示例2:
- 启动Python应用。
与其他章节的区别¶
- 与
docker_Dockerfile_dockerfile-entrypoint
章节的区别: - 本文专注于
CMD
指令的详细解析,与后者形成对比分析,帮助读者理解两者的区别与适用场景。 - 与
docker_Dockerfile_dockerfile-run
章节的区别: - 本文不涉及构建阶段的命令执行,而是专注于容器启动时的默认行为定义。
适用读者¶
- Docker初学者:
- 希望了解Dockerfile中
CMD
指令的使用方法。 - 中级用户:
- 需要深入理解
CMD
与ENTRYPOINT
的区别及最佳实践。 - 开发者和运维人员:
- 需要在容器化应用中灵活定义启动命令。
通过本文,读者将掌握CMD
指令的核心用法,并能够在实际项目中合理使用该指令,优化容器的启动行为。