深入解析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 命令行中覆盖这个默认命令。

相关推荐
小安运维日记11 分钟前
CKA认证 | Day3 K8s管理应用生命周期(上)
运维·云原生·容器·kubernetes·云计算·k8s
陈小肚18 分钟前
k8s 1.28.2 集群部署 docker registry 接入 MinIO 存储
docker·容器·kubernetes
程序猿麦小七25 分钟前
基于springboot的景区网页设计与实现
java·spring boot·后端·旅游·景区
蓝田~33 分钟前
SpringBoot-自定义注解,拦截器
java·spring boot·后端
theLuckyLong34 分钟前
SpringBoot后端解决跨域问题
spring boot·后端·python
A陈雷35 分钟前
springboot整合elasticsearch,并使用docker desktop运行elasticsearch镜像容器遇到的问题。
spring boot·elasticsearch·docker
.生产的驴36 分钟前
SpringCloud Gateway网关路由配置 接口统一 登录验证 权限校验 路由属性
java·spring boot·后端·spring·spring cloud·gateway·rabbitmq
小扳39 分钟前
Docker 篇-Docker 详细安装、了解和使用 Docker 核心功能(数据卷、自定义镜像 Dockerfile、网络)
运维·spring boot·后端·mysql·spring cloud·docker·容器
v'sir1 小时前
POI word转pdf乱码问题处理
java·spring boot·后端·pdf·word
李少兄1 小时前
解决Spring Boot整合Redis时的连接问题
spring boot·redis·后端