CMD指令和ENTRYPOINT指令作用都是指定一个容器启动时要运行的命令。
CMD指令, 支持三种格式:
CMD ["executable","param1","param2"] :使用 exec 执行,推荐方式;CMD command param1 param2 :在 /bin/sh 中执行,提供给需要交互的应用;CMD ["param1","param2"] :提供给 ENTRYPOINT 的默认参数;每个Dockerfile只能生效一条CMD指令。如果指定了多条CMD指令,只有最后一条生效。
如果用户启动容器时候指定了运行的命令,则会覆盖掉CMD指定的命令。
ENTRYPOINT指令,支持两种格式:
ENTRYPOINT ["executable", "param1", "param2"]ENTRYPOINT command param1 param2 :shell中执行每个Dockerfile中只能生效一个ENTRYPOINT指令,当有多个ENTRYPOINT指令时,只有最后一个起效。
如果用户启动容器时候指定了运行的命令,不会被docker run执行的命令参数覆盖。(追加效果:docker run命令之后的参数,会被当做参数传递给ENTRYPOINT,之后形成新的命令组合)
CMD指令是一个容器中默认的可执行命令。也就是容器启动以后,默认执行的命令。(默认是重点)
换句话说,给出了CMD指令的一个角色定位,它主要作用是定义默认的容器启动后执行的命令。
提示:
这也就是网上所说,只有最后一条CMD指令会生效,之前的都会被覆盖掉。
就是因为CMD指令的角色定位就是默认,如果你不进行额外指定,那么就执行CMD指令。否则,你要自己指定了命令,那么就不会执行CMD指令,这也就是相当于CMD指令会被覆盖。
而ENTRYPOINT指令,才是正统地用于定义容器启动以后的执行体,从名字上我们也可以看出,entrypoint 入口点的意思,一个容器的“入口”。
我们以ContOS镜像为基础,对该镜像进行修改。
(1)准备测试环境
进入宿主机/home/mydockerfile目录中,创建Dockerfil文件Dockerfile_cmd。
# mydockerfile目录中创建Dockerfile_cmd文件[root@192 mydockerfile]# pwd/home/mydockerfile[root@192 mydockerfile]# touch Dockerfile_cmd编辑Dockerfile_cmd文件,内容如下:
FROM centos # 继承了本地的centos镜像CMD ["ls","-a"] # 执行ls -a 命令说明:我们之前CMD执行都是
/bin/bash,这回改成ls -a命令是一样的,就是启动容器后执行ls -a命令。
根据Dockerfile_cmd生成cmd镜像。
[root@192 mydockerfile]# docker build -f /home/mydockerfile/Dockerfile_cmd -t wukong/cmd:1.0 .Sending build context to Docker daemon 3.072kBStep 1/2 : FROM centos ---> 300e315adb2fStep 2/2 : CMD ["ls","-a"] ---> Running in e34a0fc14329Removing intermediate container e34a0fc14329 ---> de211d4ca7f3Successfully built de211d4ca7f3Successfully tagged wukong/cmd:1.0(2)进行验证
运行wukong/cmd镜像,查看结果。
# 查看本地Docker镜像[root@192 mydockerfile]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEwukong/cmd 1.0 de211d4ca7f3 2 minutes ago 209MBwokong_centos 1.6 6441f63090d4 3 hours ago 291MBcentos latest 300e315adb2f 3 months ago 209MB# 直接运行该容器,查看结果,输出了默认工作目录中的内容。[root@192 mydockerfile]# docker run wukong/cmd:1.0....dockerenvbindevetchomeliblib64lost+foundmediamntoptprocrootrunsbinsrvsystmpusrvar# 容器启动,执行完ls -a 命令后,就会停止。[root@192 mydockerfile]# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES接下来,我们在docker run命令后,加入-l命令,我们再来查看一下结果。
[root@192 mydockerfile]# docker run wukong/cmd:1.0 -ldocker: Error response from daemon: OCI runtime create failed: container_linux.go:367: starting container process caused: exec: "-l": executable file not found in $PATH: unknown.说明:
我的意思是想追加一个-l参数,让容器启动后,执行ls -al命令。结果我们看到是,可执行文件找不到的报错, exec: "-l":executable file not found。
这就是我们之前说过的,跟在镜像名后面的是command(命令),运行时会替换CMD的默认值。也就是-l参数替换了Dockerfile文件中的CMD ["ls","-a"]命令,而不是添加在原来的命令里。
而单独的-l参数不是Linux命令,不能单独的命令,自然找不到,所以就报错了。
所以综上所述,CMD指令会被docker run之后的参数替换。
那么如果我们希望加入-l这个参数,就必须重新完整的输入整个命令,如下:
[root@192 mydockerfile]# docker run wukong/cmd:1.0 ls -altotal 0drwxr-xr-x. 1 root root 6 Mar 20 11:13 .drwxr-xr-x. 1 root root 6 Mar 20 11:13 ..-rwxr-xr-x. 1 root root 0 Mar 20 11:13 .dockerenvlrwxrwxrwx. 1 root root 7 Nov 3 15:22 bin -> usr/bindrwxr-xr-x. 5 root root 340 Mar 20 11:13 devdrwxr-xr-x. 1 root root 66 Mar 20 11:13 etcdrwxr-xr-x. 2 root root 6 Nov 3 15:22 homelrwxrwxrwx. 1 root root 7 Nov 3 15:22 lib -> usr/liblrwxrwxrwx. 1 root root 9 Nov 3 15:22 lib64 -> usr/lib64drwx------. 2 root root 6 Dec 4 17:37 lost+founddrwxr-xr-x. 2 root root 6 Nov 3 15:22 mediadrwxr-xr-x. 2 root root 6 Nov 3 15:22 mntdrwxr-xr-x. 2 root root 6 Nov 3 15:22 optdr-xr-xr-x. 122 root root 0 Mar 20 11:13 procdr-xr-x---. 2 root root 162 Dec 4 17:37 rootdrwxr-xr-x. 11 root root 163 Dec 4 17:37 runlrwxrwxrwx. 1 root root 8 Nov 3 15:22 sbin -> usr/sbindrwxr-xr-x. 2 root root 6 Nov 3 15:22 srvdr-xr-xr-x. 13 root root 0 Mar 20 06:42 sysdrwxrwxrwt. 7 root root 145 Dec 4 17:37 tmpdrwxr-xr-x. 12 root root 144 Dec 4 17:37 usrdrwxr-xr-x. 20 root root 262 Dec 4 17:37 var和上面CMD指令演示相似。
我们以ContOS镜像为基础,对该镜像进行修改。
(1)准备测试环境
进入宿主机/home/mydockerfile目录中,创建Dockerfil文件Dockerfile_entrypoint。
# mydockerfile目录中创建Dockerfile_entrypoint文件[root@192 mydockerfile]# pwd/home/mydockerfile[root@192 mydockerfile]# touch Dockerfile_entrypoint编辑Dockerfile_entrypoint文件,内容如下:
FROM centos # 继承了本地的centos镜像ENTRYPOINT ["ls","-a"] # 执行ls -a 命令根据Dockerfile_entrypoint生成entrypoint镜像。
[root@192 mydockerfile]# docker build -f /home/mydockerfile/Dockerfile_entrypoint -t wukong/entrypoint:1.0 .Sending build context to Docker daemon 4.096kBStep 1/2 : FROM centos ---> 300e315adb2fStep 2/2 : ENTRYPOINT ["ls","-a"] ---> Running in ecd4a636d8beRemoving intermediate container ecd4a636d8be ---> e641401b4ea5Successfully built e641401b4ea5Successfully tagged wukong/entrypoint:1.0(2)进行验证
运行wukong/entrypoint镜像,查看结果。
# 查看本地Docker镜像[root@192 mydockerfile]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEwukong/entrypoint 1.0 e641401b4ea5 2 minutes ago 209MBwukong/cmd 1.0 adda4543a402 3 minutes ago 209MBwokong_centos 1.6 6441f63090d4 4 hours ago 291MBcentos latest 300e315adb2f 3 months ago 209MB# 直接运行该容器,查看结果,输出了默认工作目录中的内容。[root@192 mydockerfile]# docker run wukong/entrypoint:1.0....dockerenvbindevetchomeliblib64lost+foundmediamntoptprocrootrunsbinsrvsystmpusrvar接下来,我们在docker run命令后,加入-l命令,我们再来查看一下结果。
[root@192 mydockerfile]# docker run wukong/entrypoint:1.0 -ltotal 0drwxr-xr-x. 1 root root 6 Mar 20 12:03 .drwxr-xr-x. 1 root root 6 Mar 20 12:03 ..-rwxr-xr-x. 1 root root 0 Mar 20 12:03 .dockerenvlrwxrwxrwx. 1 root root 7 Nov 3 15:22 bin -> usr/bindrwxr-xr-x. 5 root root 340 Mar 20 12:03 devdrwxr-xr-x. 1 root root 66 Mar 20 12:03 etcdrwxr-xr-x. 2 root root 6 Nov 3 15:22 homelrwxrwxrwx. 1 root root 7 Nov 3 15:22 lib -> usr/liblrwxrwxrwx. 1 root root 9 Nov 3 15:22 lib64 -> usr/lib64drwx------. 2 root root 6 Dec 4 17:37 lost+founddrwxr-xr-x. 2 root root 6 Nov 3 15:22 mediadrwxr-xr-x. 2 root root 6 Nov 3 15:22 mntdrwxr-xr-x. 2 root root 6 Nov 3 15:22 optdr-xr-xr-x. 124 root root 0 Mar 20 12:03 procdr-xr-x---. 2 root root 162 Dec 4 17:37 rootdrwxr-xr-x. 11 root root 163 Dec 4 17:37 runlrwxrwxrwx. 1 root root 8 Nov 3 15:22 sbin -> usr/sbindrwxr-xr-x. 2 root root 6 Nov 3 15:22 srvdr-xr-xr-x. 13 root root 0 Mar 20 06:42 sysdrwxrwxrwt. 7 root root 145 Dec 4 17:37 tmpdrwxr-xr-x. 12 root root 144 Dec 4 17:37 usrdrwxr-xr-x. 20 root root 262 Dec 4 17:37 var说明:想给Dockerfile文件中的ENTRYPOINT ["ls","-a"]命令追加一个-l参数,让容器启动后执行ls -al命令,结果顺利执行。
结论:这就说明了,ENTRYPOINT指令是可以在容器启动的时候追加命令。
docker run命令后面的命令行参数替换(也就是可被重写覆盖)。docker run命令时指定了其他命令(也就是可被重写覆盖)。说明:
对于 Dockerfile 来说,CMD 和 ENTRYPOINT 是非常重要的指令。它们不是在构建镜像的过程中执行,而是在启动容器时执行,所以主要用来指定容器默认执行的命令。
Dockerfile中很多命令的功能都十分的相似,我们需要了解它们的区别,我们最好的学习就是对比他们,然后测试效果。
以上就是CMD指令和ENTRYPOINT指令的区别。