1. 概述
Docker 容器在启动时会执行一个应用或命令。这个命令通常来源于镜像的配置。此外,我们也可以在运行容器时通过命令行参数来指定或覆盖这个命令。通常,我们构建的镜像来自于公共仓库中的父镜像,作者可能已经定义了默认命令。定义默认命令的主要方式是通过 Dockerfile 中的 ENTRYPOINT
和 CMD
指令。
本教程将简要介绍 ENTRYPOINT
和 CMD
的作用,并演示如何在不同场景下覆盖它们。
2. CMD
与 ENTRYPOINT
指令
我们可以使用 CMD
和 ENTRYPOINT
来指定容器启动时执行的命令。它们可以单独使用,也可以配合使用。
2.1 ENTRYPOINT
指令
ENTRYPOINT
的作用是定义容器启动时执行的主程序。 它有两种写法:
- exec 形式(推荐):
ENTRYPOINT ["echo", "Hello World of Docker"]
- shell 形式:
ENTRYPOINT echo Hello World of Docker
虽然两种形式执行结果相同,但 shell 形式会在 /bin/sh -c
中执行,且无法通过 CMD
或 docker run
添加额外参数。
2.2 CMD
指令
CMD
有两个主要用途:
- 定义容器默认执行命令(可被覆盖)
- 与
ENTRYPOINT
配合使用,提供默认参数
示例:
CMD ["echo","Hello World of Docker with CMD"]
或配合 ENTRYPOINT
使用:
ENTRYPOINT ["echo","-e"]
CMD ["Hello\tWorld"]
此时容器执行的完整命令是:echo -e Hello\tWorld
3. 使用 docker run
命令覆盖命令
docker run
提供了参数用于覆盖 Dockerfile 中的 CMD
和 ENTRYPOINT
。
3.1 构建一个示例 Dockerfile
我们创建一个简单的 Dockerfile:
FROM ubuntu:latest
ENTRYPOINT ["echo","-e"]
CMD ["Hello\tWorld"]
构建并运行容器:
$ sudo docker run -it example1
Hello World
3.2 覆盖 CMD
内容
我们可以通过在 docker run
后面添加参数来覆盖 CMD
:
$ sudo docker run -it example1 "Hello\tWorld\tof Docker Run"
Hello World of Docker Run
✅ 这样无需重新构建镜像即可修改运行参数。
4. 通过继承父镜像覆盖 CMD
我们可以基于上一步构建的镜像 example1
创建新的 Dockerfile:
FROM example1:latest
CMD ["Hello World\tOverriding parent image"]
构建并运行新镜像:
$ sudo docker run -it example2
Hello World Overriding parent image
✅ 父镜像中的 CMD
被成功覆盖。
5. 使用 Docker Compose 覆盖 CMD
Docker Compose 可以通过 command
字段覆盖镜像的默认命令。
创建 docker-compose.yaml
文件:
version: '2.2'
services:
echoer:
image: example1
command: "Hello World, from docker-compose"
运行服务:
$ sudo docker-compose up
Creating network "example1_default" with the default driver
Creating example1_echoer_1 ... done
Attaching to example1_echoer_1
echoer_1 | Hello World, from docker-compose
example1_echoer_1 exited with code 0
✅ CMD
被成功覆盖。
6. 使用 docker-compose run
覆盖 CMD
除了 docker-compose up
,我们还可以使用 docker-compose run
命令覆盖命令:
$ sudo docker-compose run echoer "Hello World, CMD Overriden from docker-compose run"
Hello World, CMD Overriden from docker-compose run
✅ 效果等同于 docker run
,适用于临时运行某个命令。
7. 小结
本文介绍了多种方式来覆盖 Docker 镜像的默认启动命令:
方式 | 覆盖目标 | 是否需要重建镜像 |
---|---|---|
docker run 命令 |
CMD |
❌ |
继承父镜像 | CMD |
✅ |
docker-compose.yaml |
CMD |
❌ |
docker-compose run |
CMD |
❌ |
--entrypoint 参数 |
ENTRYPOINT |
❌ |
✅ 推荐使用 ENTRYPOINT
固定程序入口,CMD
提供默认参数,便于灵活覆盖。
⚠️ 踩坑提醒:使用 shell 形式的 ENTRYPOINT
会导致参数无法传递,慎用!建议始终使用 exec 形式。