深入解析Docker镜像构建:RUN, CMD, 与 ENTRYPOINT 的全面解析

在 Dockerfile 中,RUN、CMD 和 ENTRYPOINT 这三条指令看起来相似,它们的作用都是在 Docker 镜像构建过程中运行指定的命令。有时候很容易造成混淆,接下来我们来详细探讨它们之间的区别。

RUN、CMD、ENTRYPOINT的作用

  • RUN:执行命令并创建新的镜像层。当你需要在镜像构建过程中安装软件包或应用程序时,就会用到 RUN。每执行一次 RUN 就会在镜像上添加一个新的层。

  • CMD:设置容器启动后默认执行的命令及其参数。不过,CMD 指定的命令可以通过 docker run 命令行参数来覆盖。它主要用于为容器设定默认启动行为。如果 Dockerfile 中有多个 CMD 指令,只有最后一个生效。

  • ENTRYPOINT:配置容器启动时运行的命令,功能上与 CMD 类似,但有一个关键区别------即使在 docker run 时指定了其他命令,ENTRYPOINT 也不会被忽略,而是会与这些命令结合使用(除非使用 --entrypoint 覆盖)。当容器作为应用程序或服务运行时,推荐使用 ENTRYPOINT,并且最好采用 Exec 格式。

我们可以通过两种方式指定 RUN、CMD 和 ENTRYPOINT 要运行的命令:Shell格式和Exec格式,这两种格式在使用上有一些微妙的差异。

Shell格式 和 Exec格式

Docker中的 RUN, CMD, 和 ENTRYPOINT 指令都可以采用两种不同的运行格式来指定要执行的命令:

Shell格式

Shell格式如下所示:

xml 复制代码
<instruction> <command>

例如:

bash 复制代码
RUN apt-get install python3
CMD echo "Hello world"
ENTRYPOINT echo "Hello world"

当执行命令时,Shell 格式的底层会使用 /bin/sh -c <command>。当你以Shell格式运行命令时,由 ENV 命令定义的环境变量可以被获取到。

bash 复制代码
ENV name Cloud Man
ENTRYPOINT echo "Hello, $name"

输出:

复制代码
Hello, Cloud Man

Exec格式

Exec格式如下所示:

css 复制代码
<instruction> ["executable", "param1", "param2", ...]

例如:

css 复制代码
RUN ["apt-get", "install", "python3"]
CMD ["/bin/echo", "Hello world"]
ENTRYPOINT ["/bin/echo", "Hello world"]

当执行命令时,<command>将被直接调用,不会被shell解析。在 ENV 中定义的环境变量也没法获取到。

bash 复制代码
ENV name Cloud Man

ENTRYPOINT ["/bin/echo", "Hello, $name"]

输出:

bash 复制代码
Hello, $name

推荐使用Exec格式进行CMD和ENTRYPOINT的指定,因为这样指令更易于阅读和理解。

RUN

RUN命令通常用于安装应用程序和软件包。RUN 在当前镜像之上执行命令,并通过创建一个新的镜像层。Dockerfile 通常包含多个RUN指令。

CMD

CMD指令允许用户指定容器默认执行的命令。当容器启动并且没有为docker run指定其他命令时,此命令将运行。

  1. 如果docker run指定了另一个命令,CMD指定的默认命令将被忽略。

  2. 如果Dockerfile中有多个CMD指令,只有最后一个CMD有效。

CMD有三种格式:

  • Exec格式:CMD ["executable","param1","param2"]

  • CMD ["param1", "param2"],这种格式与ENTRYPOINT结合使用,以提供额外的参数

  • Shell格式:CMD command param1 param2

推荐使用Exec格式,因为它提供了更好的可读性。

ENTRYPOINT

The ENTRYPOINT directive allows the container to run as an application or service.

ENTRYPOINT在指定要执行的命令及其参数方面与CMD相似。不同之处在于,即使在运行docker run时指定了其他命令,ENTRYPOINT也不会被忽略,并且会被执行。

ENTRYPOINT有两种格式:

  • Exec格式:ENTRYPOINT ["executable", "param1", "param2"] 这是ENTRYPOINT推荐使用的格式。

  • Shell格式:ENTRYPOINT command param1 param2

ENTRYPOINT中的参数始终被使用,而CMD的额外参数可以在容器启动时动态替换。例如:

css 复制代码
ENTRYPOINT ["/bin/echo", "Hello"]

CMD ["world"]

# Output
Hello world

请注意,ENTRYPOINT的Shell格式会忽略CMD或docker run提供的任何参数。

bash 复制代码
FROM busybox
ENTRYPOINT echo hello
CMD world


hello

Docker中的 --entrypoint 命令行选项允许你在运行容器时覆盖Docker镜像中指定的ENTRYPOINT指令。

ini 复制代码
$ docker run --entrypoint="path/to/custom/entrypoint" imagename

默认情况下,当你运行一个Docker容器时,会执行镜像中ENTRYPOINT指令指定的命令。但是,如果你想覆盖这种行为,可以使用 --entrypoint 选项来指定一个不同的入口点来使用。有时这对容器内部环境问题的调试很有帮助。

总结

  1. 使用 RUN 命令来安装应用程序和包,并创建新的镜像层。

  2. 如果Docker镜像的目的是运行一个应用程序或服务,例如运行 MySQL,那么应该优先使用 Exec 格式的 ENTRYPOINT 命令。CMD 可以为 ENTRYPOINT 提供额外的默认参数,并且这些默认参数可以被 docker run 命令行替换。

  3. 如果你想为容器设置默认的启动命令,可以使用 CMD 命令。用户可以在 docker run 命令行中覆盖这个默认命令。

相关推荐
小码哥_常6 小时前
Spring Boot 牵手Spring AI,玩转DeepSeek大模型
后端
0xDevNull6 小时前
Java反射机制深度解析:从原理到实战
java·开发语言·后端
华洛6 小时前
我用AI做了一个48秒的真人精品漫剧,不难也不贵
前端·javascript·后端
WZTTMoon6 小时前
Spring Boot 中Servlet、Filter、Listener 四种注册方式全解析
spring boot·后端·servlet
standovon6 小时前
Spring Boot整合Redisson的两种方式
java·spring boot·后端
Cosolar7 小时前
LlamaIndex RAG 本地部署+API服务,快速搭建一个知识库检索助手
后端·openai·ai编程
MX_93597 小时前
SpringMVC请求参数
java·后端·spring·servlet·apache
忆想不到的晖8 小时前
Codex 探索:别急着调 Prompt,先把工作流收住
后端·agent·ai编程
weixin_408099678 小时前
【实战对比】在线 OCR 识别 vs OCR API 接口:从个人工具到系统集成该怎么选?
图像处理·人工智能·后端·ocr·api·图片文字识别·文字识别ocr
维度攻城狮9 小时前
Docker优雅地运行OpenClaw
运维·docker·容器·openclaw·openclaw安装