Dockerfile之CMD、ENTRYPOINT指令

这里对Dockerfile中的CMD、ENTRYPOINT指令进行介绍

abstract.png

CMD指令

该指令可以用于指定容器被启动时需要运行的命令。具体地,其支持shell、exec两种形式的语法

1
2
3
4
5
# shell格式
CMD command  param1 param2

# exec格式
CMD ["command", "param1", "param1"]

通常Docker中推荐使用exec格式语法,原因有二。一方面,shell格式语法下会通过/bin/sh -c来执行命令;另一方面,某些镜像甚至不包含Shell,致使shell格式下的命令无法被正常执行。但使用exec格式时,会无法获取环境变量的值。此时则可以考虑使用shell格式语法

shell格式

下面通过Dockerfile定义一个名为demo1:test的镜像

1
2
3
4
# 镜像 demo1:test
FROM busybox:1.35.0
# 使用 shell 格式的CMD
CMD ping baidu.com

然后我们创建一个容器

1
docker run --name demo1A --rm -it demo1:test

如下所示,其会使用CMD指令设置的命令、参数执行

figure 1.jpeg

对于CMD指定的命令而言,不可以通过 docker run命令行实现传递参数。因为 CMD指令的命令、参数 会被 docker run命令行参数中指定的命令、参数 完全覆盖。例如我们创建一个容器,期望执行 ping weibo.com。则需要重新传递命令、参数

1
2
3
4
# 错误方式: 
docker run --name demo1B --rm -it demo1:test weibo.com
# 正确方式
docker run --name demo1B --rm -it demo1:test ping weibo.com

效果如下所示

figure 2.jpeg

又比如按下述方式创建命令,同理

1
docker run --name demo1C --rm -it demo1:test top -H

效果如下所示

figure 3.png

exec格式

下面通过Dockerfile定义一个名为demo2:test的镜像

1
2
3
4
# 镜像 demo2:test
FROM busybox:1.35.0
# 使用 exec 格式的CMD
CMD ["ping", "baidu.com"]

然后我们创建一个容器

1
docker run --name demo2A --rm -it demo2:test

如下所示,其会使用CMD指令设置的命令、参数执行

figure 4.jpeg

对于CMD指定的命令而言,不可以通过 docker run命令行实现传递参数。因为 CMD指令的命令、参数 会被 docker run命令行参数中指定的命令、参数 完全覆盖。例如我们创建一个容器,期望执行 ping weibo.com。则需要重新传递命令、参数

1
2
3
4
# 错误方式
docker run --name demo2B --rm -it demo2:test weibo.com
# 正确方式
docker run --name demo2B --rm -it demo2:test ping weibo.com

效果如下所示

figure 5.jpeg

又比如按下述方式创建命令,同理

1
docker run --name demo2C --rm -it demo2:test top -H

效果如下所示

figure 6.jpeg

ENTRYPOINT指令

该指令同样可以用于指定容器被启动时需要运行的命令。同理,其同样支持shell、exec两种形式的语法

1
2
3
4
5
# shell格式
ENTRYPOINT command  param1 param2

# exec格式
ENTRYPOINT ["command", "param1", "param1"]

对于ENTRYPOINT指令而言,Docker中同样推荐使用exec格式语法,理由与CMD指令同理

shell格式

下面通过Dockerfile定义一个名为demo3:test的镜像

1
2
3
4
# 镜像 demo3:test
FROM busybox:1.35.0
# 使用 shell 格式的ENTRYPOINT
ENTRYPOINT top -b

然后我们创建一个容器

1
docker run --name demo3A --rm -it demo3:test

如下所示,其会使用ENTRYPOINT指令设置的命令、参数执行

figure 7.jpeg

ENTRYPOINT指令 所设置命令、参数可被 docker run命令行参数中指定要运行的命令 覆盖, 但需要使用 —entrypoint 选项进行显式覆盖。否则将会忽略命令行参数

1
2
3
4
5
# 错误方式
docker run --name demo3B --rm -it demo3:test ifconfig

# 正确方式
docker run --name demo3C --rm -it --entrypoint ifconfig demo3:test

效果如下所示

figure 8.jpeg

当我们使用 —entrypoint 选项进行显式覆盖命令时,还可以传递参数

1
docker run --name demo3D --rm -it --entrypoint ping demo3:test bing.com.cn

效果如下所示

figure 9.jpeg

对于shell格式的ENTRYPOINT指令设置的命令而言,如果没有使用—entrypoint 选项。当通过 docker run命令行传递参数时, 其会被忽略

1
docker run --name demo3E --rm -it demo3:test -H -m

效果如下所示

figure 10.jpeg

exec格式

下面通过Dockerfile定义一个名为demo4:test的镜像

1
2
3
4
# 镜像 demo4:test
FROM busybox:1.35.0
# 使用 exec 格式的ENTRYPOINT
ENTRYPOINT ["top", "-b"]

然后我们创建一个容器

1
docker run --name demo4A --rm -it demo4:test

如下所示,其会使用ENTRYPOINT指令设置的命令、参数执行

figure 11.jpeg

ENTRYPOINT指令 所设置命令、参数可被 docker run命令行参数中指定要运行的命令 覆盖, 但需要使用 —entrypoint 选项进行显式覆盖。否则将会忽略命令行参数

1
2
3
4
5
# 错误方式
docker run --name demo4B demo4:test ifconfig

# 正确方式
docker run --name demo4C --rm -it --entrypoint ifconfig demo4:test

效果如下所示

figure 12.jpeg

当我们使用 —entrypoint 选项进行显式覆盖命令时,还可以传递参数

1
docker run --name demo4D --rm -it --entrypoint ping demo4:test weibo.com

效果如下所示

figure 13.jpeg

对于exec格式的ENTRYPOINT指令设置的命令而言,如果没有使用—entrypoint 选项。当通过 docker run命令行实现传递参数时, 其会被追加

1
docker run --name demo4E --rm -it demo4:test -H -m

效果如下所示

figure 14.jpeg

组合使用

对于大多数场景下,CMD、ENTRYPOINT指令都是互相通用的,而且一般也会只使用其中一种指令。具体地,CMD指令方便镜像使用者更改容器运行的命令,故适用于较为灵活的场景;而如果不期望镜像使用者去轻易更改容器运行的命令,故推荐使用ENTRYPOINT指令。同时如前文所述,exec格式较shell格式更为推荐。而对于CMD、ENTRYPOINT指令二者组合使用时,其效果可参考下图

figure 15.jpeg

事实上对于组合使用二者来说,更为常见的一种实践方式是通过exec格式的ENTRYPOINT设置固定的命令、参数,而利用exec格式的CMD 设置默认的可变参数

下面通过Dockerfile定义一个名为demo5:test的镜像

1
2
3
4
5
6
# 镜像 demo5:test
FROM busybox:1.35.0
# 使用 exec 格式的ENTRYPOINT 设置固定的命令、参数
ENTRYPOINT ["top", "-b"]
# 使用 exec 格式的CMD 设置默认的可变参数
CMD ["-H"]

然后我们创建一个容器

1
docker run --name demo5A --rm -it demo5:test

效果如下所示

figure 16.jpeg

由于此场景下CMD指令提供的是一个默认的可变参数,故我们可以通过docker run命令行参数 来覆盖 CMD指定的默认可变参数

1
docker run --name demo5B --rm -it demo5:test -m

效果如下所示

figure 17.jpeg

同理,ENTRYPOINT指令 所设置命令、参数可被 docker run命令行参数中指定要运行的命令 覆盖, 使用 —entrypoint 选项进行显式覆盖即可。当然此时CMD指令设置的默认可变参数也将失效

1
docker run --name demo5C --rm -it --entrypoint ifconfig demo5:test

效果如下所示

figure 18.jpeg

当然使用 —entrypoint 选项进行显式覆盖命令时,依然可以传递参数

1
docker run --name demo5D --rm -it --entrypoint ping demo5:test weibo.com

效果如下所示

figure 19.jpeg

参考文献

  1. 第一本Docker书·修订版 James Turnbull著
  2. 深入浅出Docker [英]Nigel Poulton著
0%