前言
在上一篇中,对于CMD
和ENTRYPOINT
只是简单介绍了它们使用上的差别。即有两个方式书写。分别是exec模式和shell模式。具体格式如下:
- exec模式
CMD /ENTRYPOINT ["executable", "param1", "param2"]
, - shell模式
CMD /ENTRYPOINT command param1 param2
想要了解清楚这两个命令的区别,需要先明白这两个模式有什么区别。
shell模式
先来看看什么是shell。shell可以理解为与内核程序沟通的组软件,类似于Windows下的cmd.exe
命令行窗口。在Linux中的终端就是一种shell,默认是bash(Bourne-Again Shell)。
现在我在Linux终端输入以下命令:
1 | $ echo abc |
这个命令就是一种shell模式,实际上它执行的样子是如下样子:
1 | $ /bin/bash -c "echo abc" |
大概意思就是将字符串”echo abc”丢到执行器bash去解析。-c参数的意思是第一个字符串是命令的路径,后面跟着的为命令的参数。
”echo abc“,第一个字符串是echo
,默认情况下会到/bin下查找有没有echo这个文件。可以看到/bin的确存在echo的文件。
为了更加了解/bin/bash -c 的含义,我们可以自己新建一个test.sh验证一下,test.sh的内容如下,路径为/home/test.sh。$0表示第一个参数。
1 | ehco $0 |
执行该文件
1 | $ /home/test.sh param1 param2 |
实际执行的样子为:
1 | $ /bin/bash -c "/home/test.sh param1 param2" |
注意第一个参数是/home/test.sh
,而不是param1。所以输出结果如下:
1 | /home/test.sh |
上面阐述了这么多,只是想让你们理解shell命令模式下,命令实际的执行样子是/bin/bash -c “command param1 param2”
exec模式
1 | ENTRYPOINT ["executable", "param1", "param2"] |
必须清楚了解命令 “executable” 的每一个参数,一个萝卜一个坑,不能随便乱拆与合并。例如执行 jar 文件的命令
1 | $ java -Xmx256M -jar /app.jar |
写成 exec 格式就是
1 | ENTRYPOINT ["java", "-Xmx256M", "-jar", "/app.jar"] |
而不能写成
1 | ENTRYPOINT ["java", "-Xmx256M", "-jar /app.jar"] |
否则 docker run
运行它时出错, “-jar” 和 “/app.jar” 分别是两个参数。
1 | Unrecognized option: -jar /app. |
exec 格式下的ENTRYPOINT才能 接收 CMD 或 dock run <image>
后的参数作为附加参数,相当于是往这个命令中附加元素。例如 Dockerfile 中写成:
1 | ENTRYPOINT ["echo", "Hello"] |
假设置构建出的镜像名(repository) 是 test(以下都以 test 作为镜像名称), 那么执行下面 docker 命令:
1 | $ docker run test World and China |
输出是:
1 | Hello World and China |
使用 exec 格式的 ENTRYPOINT 与 CMD 同在时还能接收 CMD 送过来的参数,如 Dockerfile:
1 | ENTRYPOINT ["echo", "Hello"] |
执行 docker run 命令
1 | $ docker run test |
输出
1 | Hello World |
另外,如果执行如下 docker 命令
1 | $ docker run test China Haha |
输出就是
1 | Hello China Haha |
原因是 CMD 在运行容器时由 docker run <image>
后的命令覆盖的了,所以 World
不见了。
shell 格式的下ENTRYPOINT不能接受参数
有了上面 shell 到 exec 格式的映射关系之后,我们就不难理解为什么 shell 格式的 ENTRYPOINT 不能接收 CMD 或 docker run
传过来的参数。因为参数将作为 “/bin/sh” 的参数而非 shell 的参数,举例说明:
对于 shell 格式
1 | ENTRYPOINT java -Xmx256M -jar /app.jar |
从 CMD 或 docker run
而来的参数( 比如 Hello World) 最终将会组成下面完整的 ENTRYPOINT
1 | ENTRYPOINT ["/bin/sh", "-c", "java -Xmx256M -jar /app.jar", "Hello", "World"] |
“Hello”, “World” 在这里是作为/bin/sh的参数的,而 “/bin/sh” 因为没有对应的参数,所以会忽略掉它们。而当采用了exec格式,就变成如下格式
1 | ENTRYPOINT ["java", "-Xmx256M", "-jar", "/app.jar","Hello","World"] |
这个时候从CMD或者docker run接受到的参数表示的就是java的参数了。