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

相关推荐
程序员岳焱44 分钟前
Java 与 MySQL 性能优化:Java 实现百万数据分批次插入的最佳实践
后端·mysql·性能优化
FrankYoou1 小时前
Jenkins 与 GitLab CI/CD 的核心对比
java·docker
隆里卡那唔1 小时前
在dify中通过http请求neo4j时为什么需要将localhost变为host.docker.internal
http·docker·neo4j
疯子的模样1 小时前
Docker 安装 Neo4j 保姆级教程
docker·容器·neo4j
麦兜*1 小时前
Spring Boot启动优化7板斧(延迟初始化、组件扫描精准打击、JVM参数调优):砍掉70%启动时间的魔鬼实践
java·jvm·spring boot·后端·spring·spring cloud·系统架构
大只鹅2 小时前
解决 Spring Boot 对 Elasticsearch 字段没有小驼峰映射的问题
spring boot·后端·elasticsearch
ai小鬼头2 小时前
AIStarter如何快速部署Stable Diffusion?**新手也能轻松上手的AI绘图
前端·后端·github
IT_10242 小时前
Spring Boot项目开发实战销售管理系统——数据库设计!
java·开发语言·数据库·spring boot·后端·oracle
bobz9652 小时前
动态规划
后端
stark张宇3 小时前
VMware 虚拟机装 Linux Centos 7.9 保姆级教程(附资源包)
linux·后端