云计算-7-Dockerfile深度解析
CMD
CMD指令
Docker不是虚拟机,Docker镜像启动后就是容器,容器是进程,启动的时候需要指定运行的程序和参数,CMD指令的作用就是用于指定容器进程启动命令,其格式和我们之前在云计算-6-Dockerfile制作镜像中介绍的RUN指令很相似,有两种格式,三种写法:
shell格式:CMD command arg1 arg2
exec格式:CMD [“可执行文件”,“arg1”,“arg2”]
CMD [“agr1”,“arg2”],为 ENTRYPOINT 提供默认参数
例子1
vi mynginx
文件dockerfile内容
FROM nginx:1.21.6RUN echo '<h1>Welcome My Docker!</h1>' > /usr/share/nginx/html/index.htmlCMD echo 'hello docker'
打包镜像
docker build -t mynginx:v3 -f /root/mynginx_3 .
运行镜像
docker run -it --name mynginx_3 -p 8083:80 mynginx:v3
结果
注:如果添加**-d**,
docker run -it --name mynginx_3 -p 8083:80 -d mynginx:v3
我们可以使用,docker logs查看容器日志
docker logs mynginx_3 • 1
结果为
例子2
我们使用以centos为基础镜像,使用yum的方式构建nginx,Dockerfile的进步如下:
FROM centosRUN cd /etc/yum.repos.d/ RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*RUN yum clean allRUN yum install -y yum-utilsRUN yum install -y nginxRUN echo 'hello world' > /usr/share/nginx/html/index.htmlEXPOSE 80CMD ["/usr/sbin/nginx", "-g","daemon off;"]
- 打包镜像
docker build -t mynginx:v1 . • 1
- 运行镜像
docker run -it --name mynginx_1 -p 8080:80 -d mynginx:v1
查看结果
提示:
很多人在上面的Dockerfile中经常将cmd写为
CMD service nginx start
然后发现容器执行后立即退出了,甚至还在容器中使用systemctl命令,然后发现这个命令执行不了,这主要是没有分清楚前后台概念,没有区分容器和虚拟机的差异。
对于容器,他启动程序就是容器的应用进程,容器就是为主进程存在的,主进程退出,容器就也退出了。
如果使用 CMD service nginx start 实际上就是使用
CMD ['sh','-c','service nginx start']
主进程实际上就是sh
,当service nginx start
命令结束, sh
主进程也就结束了,容器自然就退出了。
ENTRYPOINT
ENTRYPOINT指令
ENTRYPOINT的格式和RUN的指令是一样的,分为 exec 格式和 shell 格式:
shell格式:command param1 param2 (shell 形式)
exec格式:ENTRYPOINT [“executable”, “param1”, “param2”] ( exec 方式, 首选方式)
ENTRYPOINT目的和CMD一样,都是在指定容器启动程序和启动程序的参数,在运行时参数可以替代
例子3
FROM centosRUN cd /etc/yum.repos.d/RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*RUN yum clean allRUN yum install -y yum-utils#RUN yum makecache fastRUN yum install -y nginxRUN echo 'hello world' > /usr/share/nginx/html/index.htmlEXPOSE 80ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]
如果我们启动nginx的时候想查看nginx的版本
此处的-v,就是nginx -v。
当指定了 ENTRYPOINT
后,CMD
的含义就发生了改变,不再是直接的运行其命令,而是将 CMD
的内容作为参数传给 ENTRYPOINT
指令,换句话说实际执行时,将变为:
<ENTRYPOINT> "<CMD>"
例子四
FROM centosRUN cd /etc/yum.repos.d/RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*RUN yum clean allRUN yum install -y yum-utils#RUN yum makecache fastRUN yum install -y nginxRUN echo 'hello world' > /usr/share/nginx/html/index.htmlEXPOSE 80CMD ["-g","daemon off;"]ENTRYPOINT ["/usr/sbin/nginx"]
实际例子4含义和例子三是一样的。
提示
只能有一个CMD
- Dockerfile中只能有一条CMD指令。如果您列出多个CMD,则只有最后一个CMD才会生效。
- CMD的主要目的是为执行中的容器提供默认值。这些默认值可以包含可执行文件,也可以省略可执行文件,在这种情况下,您还必须指定ENTRYPOINT指令。
CMD为ENTRYPOINT提供默认参数
- 如果使用CMD为ENTRYPOINT指令提供默认参数,则CMD和ENTRYPOINT指令均应使用JSON数组格式指定。
docker run启动参数会覆盖CMD内容
# 一个示例 FROM alpine LABEL maintainer=leifengyang CMD ["1111"] ENTRYPOINT ["echo"] #构建出如上镜像后测试 docker run xxxx:什么都不传则 echo 1111echo 1111 docker run xxx arg1:传入arg1 则echo arg1