DOCKERFILE的CMD指令和ENTRYPOINT指令
本关的任务是学习CMD指令和ENTRYPOINT指令,要求学习者参照示例, 使用Dockerfile构建一个名为mydisk:v1的镜像,Dockerfile的内容为:以busybox:latest为基础镜像,在默认情况下,将启动命令设置为df -Th。 其中df命令用来查看磁盘的信息。要求df命令不能被覆盖,但-Th能够被覆盖。
相关知识
这一关我们继续介绍Dockerfile的指令,本关将介绍CMD和ENTRYPOINT。
CMD指令
CMD 指定默认的容器主进程启动命令
格式:CMD <command>(shell格式)
或 CMD ["executable","param1","param2"](exec格式,推荐格式)
或 CMD["param1","param2"](为ENTRYPOINT指令提供参数)
CMD指令提供容器启动是运行的默认命令,例如ubuntu镜像默认的CMD是/bin/bash,因此我们可以直接使用 docker run -it ubuntu进入bash。
同时也可以使用docker run -it ubuntu cat /etc/os-release,执行该命令后会输出系统版本信息。因为当在执行docker run命令时,如果显示地指定了容器的启动命令,那么会将Dockerfile中CMD设置的默认启动命令覆盖,也就是说:cat /etc/os-release命令会替代成为容器的启动命令,所以输出了系统版本信息。
在指令格式上,一般推荐使用exec格式,因为使用 shell格式时,实际的命令会被包装为 sh -c的参数的形式进行执行。比如:CMD echo $HOME,在实际执行中,会将其变更为:CMD [ "sh", "-c", "echo $HOME" ]。
ENTRYPOINT指令
ENTRYPOINT 指定默认的容器主进程启动命令
注意命令和中括号之间有空格。
格式:ENTRYPOINT <command>(shell格式)
或ENTRYPOINT ["executable","param1","param2"](exec格式,推荐格式)
ENTRYPOINT和CMD一样,都可以指定容器默认的启动命令,但是它又和CMD有所不同。上面我们说过,用户在执行docker run命令创建并启动容器时,如果指定了启动命令,那么"该启动命令"会覆盖CMD指令设置的默认启动命令,但是ENTRYPOINT设置的启动命令该不能被覆盖。
细心的同学可能发现了CMD命令可以为ENTRYPOINT指令提供参数。实际上,如果使用Dockerfile构建镜像时,既使用了ENTRYPOINT指令,又指定了CMD指令,那么CMD 指令的含义就发生了改变,CMD 的内容将作为参数传给 ENTRYPOINT指令,换句话说实际执行时,变成了<ENTRYPOINT> <CMD>。同时,如果执行docker run基于该镜像创建并启动容器,并设置了启动命令时,docker run设置的"启动命令"依然会覆盖CMD的内容,但也仅仅是作为ENTRYPOINT指令的参数。
实例
假设需要一个得知使用者当前公网IP的镜像,可以使用下面的Dockerfile构建一个镜像。
- FROM centos
- RUN yum install curl
- CMD ["curl","-s","http://ip.cn"] 执行docker build -t myip .来构建一个名为myip的镜像,镜像构建完成后,如果想要查询当前公网的IP,执行docker run myip,如下所示:
- [root@localhost tempdir]#
- 当前 IP:113.247.230.194 来自:湖南省长沙市 电信 嗯,这么看起来好像可以直接把镜像当做命令使用了,不过命令总有参数,如果我们希望加参数呢?比如从上面的 CMD 中可以看到实质的命令是curl ,那么如果我们希望显示HTTP头信息,就需要加上-i参数。那么我们可以直接加 -i参数给 docker run myip么?
- [root@localhost tempdir]#-i
- container_linux.go:247:"exec: \"-i\": executable file not found in $PATH"
- docker:Errorfrom::.go:247:"exec: \"-i\": executable file not found in $PATH". 我们可以看到执行明后后输出了 executable file not found的错误信息,也就是"可执行文件找不到"。之前我们说过,跟在镜像名后面的是 command ,运行时会替换 CMD的默认值。因此这里的-i替换了原来的CMD,而不是添加在原来的 curl -s http://ip.cn 后面。而 -i 根本不是命令,所以自然找不到。
那么如果我们希望加入 -i 这参数,我们就必须重新完整的输入这个命令:docker run myip curl -s http://ip.cn –i。这显然不是很好的解决方案,而使用 ENTRYPOINT 就可以解决这个问题。现在改写Dockerfile,使用ENTRYPOINT设置启动命令: - FROM centos
- RUN yum install curl
- ENTRYPOINT ["curl","-s","http://ip.cn"] 这次我们再来尝试直接使用 docker run myip以及 docker run myip -i:可以看到,这次成功了。这是因为当存在 ENTRYPOINT 后,docker run命令ENTRYPOINT不会被覆盖。它会作为参数传给ENTRYPOINT,从而达到了我们预期的结果。
- [root@localhost tempdir]#
- 当前 IP:113.247.230.194 来自:湖南省长沙市 电信
- [root@localhost tempdir]#-i
- HTTP/1.1200
- Server:/1.11.9
- Date:Wed,09Aug201708:32:24
- Content-Type:/html;=UTF-8
- Transfer-Encoding:
- Connection:-alive
- 当前 IP:113.247.230.194 来自:湖南省长沙市 电信 任务要求
本关的编程任务是补全step3/dockerfile3.sh文件中的内容,要求使用Dockerfile构建一个名为mydisk:v1的镜像,具体要求如下:
- 补全Dockerfile的内容,该Dockerfile的内容如下:
- 以busybox:latest为基础镜像
- 默认情况下,将启动命令设置为df -Th。要求df命令不能被覆盖,但-Th能够被覆盖。(df命令用来查看磁盘的信息)
- 使用docker build基于该Dockerfile构建一个名为mydisk:v1的镜像。
- 注意命令后面要有空格。CMD之后有空格。ENTRYPOINT也是要有空格。
示例1
#创建一个空文件夹,并进入其中
mkdir newdir3
cd newdir3
#创建一个Dockerfile文件
touch Dockerfile
#假设我的Dockerfile文件为
#FROM ubuntu
#RUN mkdir dir1
#可以这么写:
# echo 'FROM ubuntu' > Dockerfile
# echo 'RUN mkdir dir1'>> Dockerfile
#输入Dockerfile文件内容
#********** Begin *********#
#以busybox为基础镜像
echo 'FROM busybox' > Dockerfile
#默认情况下,将启动命令设置为df -Th。要求df命令不能被覆盖,但-Th能够被覆盖。
echo 'CMD ["-T","-h"]'>> Dockerfile
echo 'ENTRYPOINT ["df","-Th"]'>> Dockerfile
#********** End **********#
#文件内容完毕,在当前文件夹中执行
#********** Begin *********#
#以该Dockerfile构建一个名为mydisk:latest的镜像
docker build -t mydisk:latest .
#********** End **********#
示例2[root@dockerdevops newdir3]# more Dockerfile
FROM centos
ENTRYPOINT ["df","-Th"]
root@dockerdevops newdir3]# docker build -t mydisk:latest .
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM centos
---> d123f4e55e12
Step 2/2 : ENTRYPOINT df -Th
---> Running in eb80aa1318ad
---> 5c74a196f882
Removing intermediate container eb80aa1318ad
Successfully built 5c74a196f882
Successfully tagged mydisk:latest
[root@dockerdevops newdir3]# docker run mydisk:latest
Filesystem Type Size Used Avail Use% Mounted on
overlay overlay 50G 9.1G 41G 19% /
tmpfs tmpfs 3.9G 0 3.9G 0% /dev
tmpfs tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup
/dev/mapper/cl-root xfs 50G 9.1G 41G 19% /etc/hosts
shm tmpfs 64M 0 64M 0% /dev/shm
tmpfs tmpfs 3.9G 0 3.9G 0% /sys/firmware