CMD指令和ENTRYPOINT指令的作用都是为镜像指定容器启动后的命令,那么它们两者之间有什么各自的优点呢?
为了更好地对比CMD指令和ENTRYPOINT指令的差异,我们这里再列一下这两个指令的说明
CMD 支持三种格式 CMD ["executable","param1","param2"] 使用 exec 执行,推荐方式; CMD command param1 param2 在 /bin/sh 中执行,提供给需要交互的应用; CMD ["param1","param2"] 提供给 ENTRYPOINT 的默认参数; 指定启动容器时执行的命令,每个 Dockerfile 只能有一条 CMD 命令。如果指定了多条命令,只有最后一条会被执行。 如果用户启动容器时候指定了运行的命令,则会覆盖掉 CMD 指定的命令。
ENTRYPOINT 两种格式: ENTRYPOINT ["executable", "param1", "param2"] ENTRYPOINT command param1 param2(shell中执行)。 配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖。 每个 Dockerfile 中只能有一个ENTRYPOINT,当指定多个时,只有最后一个起效。
从上面的说明,我们可以看到有两个共同点:
都可以指定shell或exec函数调用的方式执行命令;当存在多个CMD指令或ENTRYPOINT指令时,只有最后一个生效;而它们有如下差异:
CMD指令指定的容器启动时命令可以被docker run指定的命令覆盖,而ENTRYPOINT指令指定的命令不能被覆盖,而是将docker run指定的参数当做ENTRYPOINT指定命令的参数;CMD指令可以为ENTRYPOINT指令设置默认参数,而且可以被docker run指定的参数覆盖;下面分别对上面两个差异点进行详细说明
差异1:
CMD指令指定的容器启动时命令可以被docker run指定的命令覆盖;而ENTRYPOINT指令指定的命令不能被覆盖,而是将docker run指定的参数当做ENTRYPOINT指定命令的参数。
创建一个 dockerfile [root@web build_dockerfile]# vim dockerfile_cmd FROM centos:1.0 CMD ["ls","-a"] 构建镜像 [root@web build_dockerfile]# docker build -f dockerfile_cmd -t cmd . Sending build context to Docker daemon 2.048kB Step 1/2 : FROM centos:1.0 ---> d7341af1b629 Step 2/2 : CMD ["ls","-a"] ---> Running in 80e807bc33cc Removing intermediate container 80e807bc33cc ---> 1d68b8295a8f Successfully built 1d68b8295a8f Successfully tagged cmd:latest run运行 [root@web build_dockerfile]# docker run cmd . .. .dockerenv bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var volume1 volume2 想追加一个 -l 命令,就相当于执行 ls -al 命令因为 CMD 的情况下,-l 替换了 CMD ["ls","-a"] 命令,但是 -l 又不是命令,所以就报错了。
从上面运行结果可以看到,docker run命令启动容器时指定的运行命令覆盖了Dockerfile文件中CMD指令指定的命令
ENTRYPOINT 命令做相同操作如下:
创建一个 dockerfile [root@web build_dockerfile]# vim dockerfile_entrypoint FROM centos:1.0 ENTRYPOINT ["ls","-a"] 构建镜像 [root@web build_dockerfile]# docker build -f dockerfile_entrypoint -t entrypoint . Sending build context to Docker daemon 3.072kB Step 1/2 : FROM centos:1.0 ---> d7341af1b629 Step 2/2 : ENTRYPOINT ["ls","-a"] ---> Running in 928782473d8a Removing intermediate container 928782473d8a ---> 5767331b693b Successfully built 5767331b693b Successfully tagged entrypoint:latest run运行 [root@web build_dockerfile]# docker run entrypoint . .. .dockerenv bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var volume1 volume2如上图,这一步为止,结果都跟使用CMD没有什么差别
加上 -l 测试
会发现结果不仅没报错,而且还跟执行 ls -al 一样,这样就能看出这两个命令之间的差距这里 -l 命令是直接拼接在 ENTRYPOINT 命令的后面通过上面的运行结果可以看出,docker run命令指定的容器运行命令不能覆盖Dockerfile文件中ENTRYPOINT指令指定的命令,反而被当做参数传递给ENTRYPOINT指令指定的命令。
差异2
CMD指令可以为ENTRYPOINT指令设置默认参数,而且可以被docker run指定的参数覆盖;
编写Dockerfile,内容如下所示
[root@web build_dockerfile]# vim dockerfile_cmd_entrypoint FROM centos:1.0 MAINTAINER Bertram<1111@qq.com> ENTRYPOINT ["ls","-l"] CMD ["data"]运行docker build命令生成 cmd_entrypoint 镜像
[root@web build_dockerfile]# docker build -f dockerfile_cmd_entrypoint -t cmd_entrypoint . Sending build context to Docker daemon 4.096kB Step 1/4 : FROM centos:1.0 ---> f1af3dfb4128 Step 2/4 : MAINTAINER Bertram<1111@qq.com> ---> Running in 45d74d263102 Removing intermediate container 45d74d263102 ---> 4f2871d8a9ca Step 3/4 : ENTRYPOINT ["ls","-l"] ---> Running in ba0f6c7ef244 Removing intermediate container ba0f6c7ef244 ---> d33d043a0dc3 Step 4/4 : CMD ["data"] ---> Running in 2e0a8e01ded3 Removing intermediate container 2e0a8e01ded3 ---> 6891cce51d43 Successfully built 6891cce51d43 Successfully tagged cmd_entrypoint:latest下面运行docker run启动两个cmd_entrypoint 镜像的容器,第一条docker run命令没有指定参数,第二条docker run命令指定了参数 usr,其运行结果如下
[root@web build_dockerfile]# docker run cmd_entrypoint total 0 -rw-r--r-- 1 root root 0 Oct 20 08:03 1.txt -rw-r--r-- 1 root root 0 Oct 20 08:03 10.txt -rw-r--r-- 1 root root 0 Oct 20 08:03 2.txt -rw-r--r-- 1 root root 0 Oct 20 08:03 3.txt -rw-r--r-- 1 root root 0 Oct 20 08:03 4.txt -rw-r--r-- 1 root root 0 Oct 20 08:03 5.txt -rw-r--r-- 1 root root 0 Oct 20 08:03 6.txt -rw-r--r-- 1 root root 0 Oct 20 08:03 7.txt -rw-r--r-- 1 root root 0 Oct 20 08:03 8.txt -rw-r--r-- 1 root root 0 Oct 20 08:03 9.txt [root@web build_dockerfile]# docker run cmd_entrypoint usr total 4 dr-xr-xr-x 1 root root 111 Oct 20 08:02 bin drwxr-xr-x 2 root root 6 May 11 2019 games drwxr-xr-x 3 root root 24 Aug 9 21:40 include dr-xr-xr-x 1 root root 49 Aug 9 21:40 lib dr-xr-xr-x 1 root root 90 Oct 20 08:01 lib64 drwxr-xr-x 11 root root 4096 Aug 9 21:40 libexec drwxr-xr-x 12 root root 131 Aug 9 21:40 local dr-xr-xr-x 1 root root 175 Oct 20 08:02 sbin drwxr-xr-x 1 root root 101 Oct 20 08:01 share drwxr-xr-x 4 root root 34 Aug 9 21:40 src lrwxrwxrwx 1 root root 10 May 11 2019 tmp -> ../var/tmp从上面第一个容器的运行结果可以看出CMD指令为ENTRYPOINT指令设置了默认参数;从第二个容器的运行结果看出,docker run命令指定的参数覆盖了CMD指令指定的参数。