CMD与ENTRYPOINT都可以代表容器的启动命令,单丛语义上来理解,CMD是一个命令或者口令,而ENTRYPOINT则是一个入口(相当于容器启动时的入口),那么其实就可以理解为每当我们开启一个容器都需要带着口令去进入容器的入口。虽然两者可以单独使用,但根据业务需求往往是将两者搭配起来使用更加方便与规范。
先来看一张表
这是在Dockerfile中使用CMD与ENTRYPOINT的几种组合情况,两者可以定义在运行容器时执行了什么命令。
注意事项:
- CMD与ENTRYPOINT在Dockerfile里应该至少指定一个
- 当容器作为可执行文件使用时,应该定义ENTRYPOINT
- CMD应该用作定义ENTRYPOINT命令或在容器中执行特别命令的默认参数的方法
- 当运行带有替代参数的容器时,CMD将被覆盖
两者单独使用
从表中可以看出两者均可单独当做启动命令使用,但是灵活性并不是很高,比如传参等。
1. 对于CMD来讲,有三种写法:
- CMD ["executable","p1","p2"] (exec方式, 首选方式)
- CMD ["p1","p2"] (为ENTRYPOINT提供默认参数,需与ENTRYPOINT结合使用)
- CMD command p1 p2 (shell形式)
当在Dockerfile中单独使用CMD作为容器启动命令(CMD ["executable","p1","p2"] )时,只允许使用一个CMD,若有多个则以最后一个为主。
此外,CMD作为启动命令,当外部(命令行)传入启动命令时,外部命令会覆盖CMD中的启动命令。
2. 对于ENTRYPOINT来讲,有两种写法:
- ENTRYPOINT ["executable", "p1", "p2"] (exec方式, 首选方式)
- ENTRYPOINT command param1 param2 (shell 形式)
当在Dockerfile中单独使用ENTRYPOINT作为容器启动命令时,外部传入的启动命令不会覆盖ENTRYPOINT中的命令。
另外需要注意的是两者通过exec的方式取不出来环境变量,但是通过shell方式可以取出环境变量。
如果既想要使用exec方式又要取环境变量,则可以通过/bin/sh -c的方式(RUN指令也类似)
例如:ENTRYPOINT ["/bin/sh", "-c", "echo ${p1}"] (["/bin/sh", "-c", "指令均写在这里"] = shell形式)
两者结合使用
官方推荐:ENTRYPOINT(提供可执行命令+参数(可选)) + CMD(只提供参数) = 容器的完整命令
如果使用CMD为ENTRYPOINT指令提供默认参数,则CMD和ENTRYPOINT指令均应使用JSON数组格式指定。
在CMD中自定义的参数必须要传完整,容器才可成功启动。