一、 ENTRYPOINT指令
ENTRYPOINT 的两种格式:
• ENTRYPOINT ["executable", "param1", "param2"] (exec格式,推荐使用此格式)
• ENTRYPOINT command param1 param2 (shell 格式)
ENTRYPOINT 的目的和 CMD 一样,都是指定容器的启动程序及参数。ENTRYPOINT 在运行时也可以通过 docker run 的参数 --entrypoint 来替代镜像中默认的ENTRYPOINT,通过 --entrypoint 传的必须是可执行的二进制程序, 即不会以sh -c 形式执行。
当指定了 ENTRYPOINT (exec格式)后,CMD 的含义就发生了改变,不再是直接运行的命令,而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令,换句话说实际执行时,将变为:
通过docker run
CMD作为 ENTRYPOINT 的参数时需要是exec格式,如果是shell格式将转化成/bin/sh -c 式的exec格式,作为参数传给 ENTRYPOINT 时可能会出错;
当指定了ENTRYPOINT 为shell格式, CMD将无效, 即dockerfile里的CMD和 启动容器时传的命令行参数都将无效,此时ENTRYPOINT 将以 /bin/sh –c 的形式启动,即作为sh的子命令来执行,这种形式下ENTRYPOINT的执行程序不能通过Unix 信号控制,因进程号不是容器的PID 1 (sh的进程PID为1),也就不能以docker stop
和shell格式不同,当ENTRYPOINT是exec格式时不会调用shell,通常的shell变量将不会被解析执行,ENTRYPOINT [ "echo", "$HOME" ] 中的$HOME不会被替换,如果需要变量替换,则可以用shell格式的ENTRYPOINT。
二、 CMD指令
启动容器的时候,需要指定所运行的程序及参数。CMD 指令就是用于指定默认的容器主进程的启动命令的。
CMD指令有三种格式:
• CMD ["executable","param1","param2"] (exec 格式,推荐用此格式)
• CMD ["param1","param2"] (作为ENTRYPOINT 的默认参数)
• CMD command param1 param2 (shell 格式)
在dockerfile中只能有1个CMD指令,如有多个,最后一个生效。CMD的目的是提供默认的执行程序或执行程序的参数给容器,如果是参数,需要有ENTRYPOINT提供执行程序。
如果dockerfile中同时指定了ENTRYPOINT和CMD,CMD将作为ENTRYPOINT的默认参数,这里两个指令都指的是exec 格式,都将解析为JSON数组,所以只能用双引号;
exec格式不会解析shell环境变量,如CMD [ "echo", "$HOME" ] 将无法解析变量HOME变量,dockerfile里如果CMD用shell格式,在实际执行时将以 /bin/sh -c 执行,如:
CMD echo $HOME
在实际执行时将变成CMD [ "sh", "-c", "echo $HOME" ] 也就会解析出HOME变量。
CMD用exec格式执行系统的命令时,需要命令的全路径和JSON数组格式,就是得使用双引号,每个参数单独分别地追加在数组中,如下用法:
CMD [“/usr/bin/wc”, ”--help”]
三、 理解和结合使用CMD和ENTRYPOINT
- Dockerfile 应该至少指定CMD或ENTRYPOINT其中的1个;
- 容器用作可执行的程序应用时应该用ENTRYPOINT;
- CMD应该用作ENTRYPOINT的默认参数来使用,或是在容器中执行临时的命令;
- 启动容器时如果传递参数将覆盖dockerfile中指定的CMD参数;
下表列出了在CMD和ENTRYPOINT结合使用的情况下,哪个命令最终生效:
以上内容参考官方文档:
https://docs.docker.com/engine/reference/builder/#usage