Dockerfile之CMD、ENTRYPOINT指令

ProjectDaedalus

共 5357字,需浏览 11分钟

 · 2022-08-03

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

abstract.png

CMD指令

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

# shell格式
CMD command  param1 param2

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

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

shell格式

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

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

然后我们创建一个容器

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

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

figure 1.jpeg

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

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

效果如下所示

figure 2.jpeg

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

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

效果如下所示

figure 3.png

exec格式

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

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

然后我们创建一个容器

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

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

figure 4.jpeg

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

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

效果如下所示

figure 5.jpeg

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

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

效果如下所示

figure 6.jpeg

ENTRYPOINT指令

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

# shell格式
ENTRYPOINT command  param1 param2

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

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

shell格式

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

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

然后我们创建一个容器

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

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

figure 7.jpeg

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

# 错误方式
docker run --name demo3B --rm -it demo3:test ifconfig

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

效果如下所示

figure 8.jpeg

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

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

效果如下所示

figure 9.jpeg

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

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

效果如下所示

figure 10.jpeg

exec格式

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

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

然后我们创建一个容器

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

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

figure 11.jpeg

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

# 错误方式
docker run --name demo4B  demo4:test ifconfig

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

效果如下所示

figure 12.jpeg

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

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

效果如下所示

figure 13.jpeg

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

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的镜像

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

然后我们创建一个容器

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

效果如下所示

figure 16.jpeg

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

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

效果如下所示

figure 17.jpeg

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

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

效果如下所示

figure 18.jpeg

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

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

效果如下所示

figure 19.jpeg

参考文献

  1. 第一本Docker书·修订版 James Turnbull著
  2. 深入浅出Docker Nigel Poulton著
浏览 62
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报