dockerfile中CMD和ENTRYPOINT指令使用及说明

 更新时间:2025年11月28日 08:50:38   作者:赶路人儿  
介绍了Dockerfile中的CMD和ENTRYPOINT指令以及它们的执行方式,包括exec形式和shell形式,CMD提供默认命令,支持覆盖;ENTRYPOINT定义固定命令,不支持覆盖,但可以通过--entrypoint参数实现覆盖

1、exec和shell两种风格

无论是CMD还是ENTRYPOINT指令,都支持exec和shell两种风格:

语法

示例

解析方式

Exec 形式

JSON 数组

CMD ["sleep", "60"]

直接执行二进制程序,docker实际运行execve("sleep", ["sleep", "60"])

Shell 形式

字符串

CMD sleep 60

通过 shell 执行命令,相当于 /bin/sh -c "sleep 60"

说明:execve时Linux内核的一个系统调用,作用事用于一个新程序替换当前进程(把新程序加载到当前进程的内存空间,当前的进程会被丢弃

注意:生产环境中推荐使用Exec形式,更安全、可控。

1)shell风格和exec风格解析方式:

shell风格是通过shell执行的命令,

CMD sleep 60 
#Docker实际运行时会变成
/bin/sh -c "sleep 60"

也就是说,它先启动一个 Shell 进程(/bin/sh),再让这个 shell 去执行 sleep 60。所以:

• 容器的 PID 1 进程 实际是 /bin/sh,不是 sleep

• Shell 风格中,可以解释变量、重定向符、管道符等(比如 CMD echo $PATH > /tmp/p)

而对于exec风格是直接执行命令,

CMD ["sleep", "60"]
#DOcker不会提懂/bin/sh,而是直接执行命令
execve("sleep", ["sleep", "60"])

所以,

  • 容器内的 PID 1 就是 sleep 进程;
  • 命令参数直接传递给进程;
  • 不支持 shell 特性(如 $VAR、|、> 等);
  • 启动更快、行为更一致。

2)环境变量展开:(CDM和ENTRYPOINT是一样的)

FROM busybox
ENV NAME=KnowLiu

# shell 形式
CMD echo "Hello $NAME"
#运行
docker run myimage
# 输出:Hello KnowLiu

#-------------
FROM busybox
ENV NAME=KnowLiu
CMD ["echo", "Hello $NAME"]

#运行
docker run myimage
# 输出:Hello $NAME

结论:

  • Shell 形式支持变量展开;
  • Exec 形式不支持(因为没经过 shell)。

3)信号转发:(CDM和ENTRYPOINT是一样的)

FROM busybox
CMD ["sleep", "1000"]

#运行,然后停止容器会立即停止
docker run --name test mini
docker stop test

#-----------
FROM busybox
CMD sleep 1000

#运行,然后停止容器,容器停止会超时
docker run --name test mini
docker stop test

说明:由于/bin/sh是1号进程,SIGTERM 发给 shell,而 shell 默认不会转发信号,导致 sleep 不退出 → 容器停止会超时。

4)参数传递:

#docker file
FROM alpine:3.20
ENTRYPOINT ["echo", "hahaha!"]

#构建、运行
docker build -t my-test .
docker run my-test 
输出 hahaha!

docker run my-test hi
输出 hahaha! hi

docker run my-test echo hi
输出 hahaha! echo hi 

#------------------------
#docker file
FROM alpine:3.20
ENTRYPOINT echo hahaha

#构建、运行
docker build -t my-test .
docker run my-test 
输出 hahaha

docker run my-test hi
输出 hahaha

docker run my-test echo hi
输出 hahaha

可以看到,ENTRYPOINT指令的exec风格支持传递参数,shell风格不支持!关于命令覆盖,见下面!

5)总结二者的区别:

特性

Exec 形式

Shell 形式

写法

CMD ["cmd", "arg1", "arg2"]

ENTRYPOINT ["cmd", "arg1", "arg2"]

CMD cmd arg1 arg2

ENTRYPOINT cmd arg1 arg2

是否通过 /bin/sh

❌ 否

✅ 是

是否支持环境变量展开

❌ 否

✅ 是

是否支持管道、重定向等

❌ 否

✅ 是

信号传递(SIGTERM 等)

✅ 正常

⚠️ 可能被拦截

运行时参数(docker run 参数)

✅ 支持,仅针对对ENTRYPOINT指令,CMD指令是命令覆盖

❌ 否,仅针对对ENTRYPOINT指令,CMD指令是命令覆盖

PID 1 是谁

应用进程

/bin/sh

推荐场景

长期运行的服务、生产环境

临时命令、调试脚本

性能

更快、更干净

稍慢

2、CMD、ENTRYPOINT指令

1)基本:

二者都是用来提供容器启动时的命令,都支持exec和shell两种书写风格:

  • CMD提供的是默认命令,所以支持命令的覆盖;此外,还可以作为为 ENTRYPOINT 指令提供默认参数(ENTRYPOINT+CMD组合方式,并且使用exec风格)
  • ENTRYPOINT是固定的命令,不支持命令覆盖,可以进行参数的传递。

ENTRYPOINT虽然默认不能命令的覆盖,但是可以通过--entrypoint参数来实现:

docker run --entrypoint <新命令> <镜像名> [参数...]

看个例子

#dockerfile
FROM alpine:3.20
ENTRYPOINT ["echo", "hahaha!"]

#构建
docker build -t mytest
#运行
docker run mytest
#输出 hahaha!

docker run --entrypoint ls mytest /usr
输出
bin
lib
local
sbin
share

注意:在dockerfile中如果有多个CMD、ENTRYPOING指令,那么最后一个会覆盖前面的。

2)一句话区分CMD和ENTRYPOINT:

  • CMD:提供容器启动的默认命令或参数,可以被覆盖(被entrypoint覆盖,或者被docker run后面跟的命令覆盖)
  • ENTRYPOINT:定义容器启动时固定要执行的主命令,一般不会覆盖(除非使用--entrypoint)

示例1:使用CMD:

#dockerfile
FROM busybox
CMD ["echo", "hello world"]

#构建
docker build -t mytest
#运行
docker run mytest
#输出 hello world

# 运行
docker run myimage echo hi
# 输出:hi

说明:CMD 定义的命令可以被你在 docker run 中输入的新命令替换掉。

示例2:ENTRYPOINT示例:

#dockerfile
FROM busybox
ENTRYPOINT ["echo", "hello"]

# 运行
docker run myimage
# 输出:hello

#运行
docker run myimage world
# 输出:hello world

说明:这里 ENTRYPOINT 是固定命令 echo,而 docker run myimage world 中的参数 world 会被当作 ENTRYPOINT 的参数。

示例3:你可以 组合 ENTRYPOINT + CMD 来实现“固定命令 + 默认参数”模式

#dockerfile
FROM busybox
ENTRYPOINT ["sleep"]
CMD ["60"]

#运行
docker run myimage
# 等价于:sleep 60

docker run myimage 10
# 等价于:sleep 10

说明:

  • ENTRYPOINT 是固定的命令:sleep
  • CMD 提供默认参数:60
  • 用户在 docker run 中输入参数会覆盖 CMD,但不会影响 ENTRYPOINT

3、docker run运行容器时的命令覆盖和参数传递

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

[COMMAND] 和 [ARG...] 到底是「命令覆盖」还是「参数传递」,取决于 Dockerfile 的 ENTRYPOINT/CMD 组合形式。

Dockerfile 内容

启动行为

docker run IMAGE ... 的效果

1️⃣ 只有 CMD

CMD 是默认命令

运行时的 [COMMAND] 会 覆盖 CMD

2️⃣ 只有 ENTRYPOINT

ENTRYPOINT 是固定命令

对于exec风格下,运行时的 [COMMAND] 会被 当作参数传递给 ENTRYPOINT

3️⃣ ENTRYPOINT + CMD

ENTRYPOINT 是固定命令,CMD 提供默认参数

对于exec风格下,运行时的 [COMMAND] 会 覆盖 CMD(参数部分),但 不会覆盖 ENTRYPOINT

1)示例1:CMD 的shell和exec风格:

#docker file
FROM alpine:3.20
CMD echo hello

#构建、运行
docker build -t my-test .
docker run my-test 
输出 hello

docker run my-test echo hi
输出 hi

docker run my-test hi
报错,“hi” executable file not found in $PATH: unknown.

说明:将dockerfile替换成CMD ["echo", "hello"] 运行结果一样!所以,对于CMD指令来说,只有ENTRYPOINT + CMD的组合的时候,才能通过docker run传递参数给CMD,只有CMD的时候,传递的“字符串”都是当命令来执行的,无法单独为其传递参数!

2)示例2:ENTRYPOINT的shell风格:

#docker file
FROM alpine:3.20
ENTRYPOINT echo hahaha

#构建、运行
docker build -t my-test .
docker run my-test 
输出 hahaha

docker run my-test hi
输出 hahaha

docker run my-test echo hi
输出 hahaha

说明:对于ENTRYPOINT的shell风格,无法传递参数!

3)示例3:ENTRYPOINT的exec风格:

#docker file
FROM alpine:3.20
ENTRYPOINT ["echo", "hahaha!"]

#构建、运行
docker build -t my-test .
docker run my-test 
输出 hahaha!

docker run my-test hi
输出 hahaha! hi

docker run my-test echo hi
输出 hahaha! echo hi 

说明:对于ENTRYPOINT的Exec风格,传递的字符串会当作参数传递,并追加进去!

4)示例4:组合模式exec风格

#docker file
FROM alpine:3.20
ENTRYPOINT ["echo"]
CMD ["hi"]

#构建、运行
docker build -t my-test .
docker run my-test 
输出 hi

docker run my-test abc
输出 abc

docker run my-test echo 123
输出 echo 123

说明:docker run后面的字符串,会当作参数覆盖CMD。

5)示例5:组合模式shell风格

#docker file
FROM alpine:3.20
ENTRYPOINT echo
CMD hi

#构建、运行
docker build -t my-test .
docker run my-test 
输出 空

docker run my-test abc
输出 空

docker run my-test echo 123
输出 空

说明:

docker官方文档描述:

When using the exec form of ENTRYPOINT, the CMD value is passed as arguments to ENTRYPOINT.When using the shell form of ENTRYPOINT, the CMD value is ignored.

也就是说, Shell 形式的 ENTRYPOINT 会忽略 CMD 的内容。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Docker复制现有容器的实现方法

    Docker复制现有容器的实现方法

    在使用Docker进行应用开发和部署时,我们经常需要基于现有的容器创建相似的环境,本文主要介绍了Docker复制现有容器的实现方法,具有一定的参考价值,感兴趣的可以了解一下
    2024-03-03
  • ubuntu docker搭建Hadoop集群环境的方法

    ubuntu docker搭建Hadoop集群环境的方法

    这篇文章主要介绍了ubuntu docker搭建Hadoop集群环境,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-06-06
  • Docker中使用Redis配置文件的详细指南

    Docker中使用Redis配置文件的详细指南

    在现代软件开发中,Redis 因其高性能和低延迟的特性,被广泛用作数据结构服务器和消息代理,Docker 作为一个轻量级的容器化平台,使得部署和管理 Redis 变得更加简单和高效,本文给大家介绍了Docker中使用Redis配置文件的详细指南,需要的朋友可以参考下
    2024-11-11
  • Docker 网络之端口绑定的方法

    Docker 网络之端口绑定的方法

    本篇文章主要介绍了Docker 网络之端口绑定的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-02-02
  • docker安装jiacrontab可视化任务管理工具详解

    docker安装jiacrontab可视化任务管理工具详解

    jiacrontab 是基于 Web 的可视化定时任务管理工具,由 server(调度多 client)和 client(执行脚本)通过 RPC 通信构成,支持超时处理、并发控制、依赖管理及兼容 Linux crontab 格式,便于多服务器统一管理
    2025-07-07
  • Docker安装jenkins实现微服务多模块打包的示例代码

    Docker安装jenkins实现微服务多模块打包的示例代码

    本文主要介绍了Docker安装jenkins实现微服务多模块打包的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • Docker安装并使用Mysql的详细教程(实测可用!)

    Docker安装并使用Mysql的详细教程(实测可用!)

    在日常的工作中经常会需要将数据存在服务器,经常用到的数据库是mysql,下面这篇文章主要给大家介绍了关于Docker安装并使用Mysql的详细教程,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-01-01
  • docker运行容器远程挂载卷的方法

    docker运行容器远程挂载卷的方法

    本篇文章主要介绍了docker运行容器远程挂载卷的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • Docker部署mysql一主一从的操作方法

    Docker部署mysql一主一从的操作方法

    这篇文章主要介绍了Docker部署mysql一主一从,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-05-05
  • win10安装docker及遇到的坑及解决

    win10安装docker及遇到的坑及解决

    这篇文章主要介绍了win10安装docker及遇到的坑及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11

最新评论