Docker CMD和ENTRYPOINT深入详解分析

首先CMD和ENTRYPOINT,都是指定一个容器启动时要执行的命令

Dockerfile中可以有多个CMD指令,但是只有最后一个生效,CMD会被docker run之后的参数替换

Docker也有镜像仓库中心,就像Maven中央仓库一样,dockerhub地址https://www.docker.com/

我们点击某个Dockerfile链接,进入该文件的详细内容里,拉到最底下。

可以看到最后都是指向CMD["catalina.sh","run"],意思就是启动tomcat,所以我们运行tomcat容器的时候,

容器启动后,就自动启动tomcat了。

这里我们启动一个tomcat容器,对外8081端口,映射容器8080端口

[root@iZm5e3euwwjtgvn8yh8gb0Z ~]#  docker run -p 88:8080 docker.io/tomcat

这样tomcat就正常启动了

如果我们使用docker run -p 88:8080 docker.io/tomcat ls -l,这样来执行的话,最后一句CMD["catalina.sh","run"],就会被docker run后面的参数ls -l覆盖了,不会被执行

tomcat就无法启动了,而是会显示tomcat镜像WORKDIR指定的目录(落脚点)下的所有文件,如下图所示,

Dockerfile定义了WORKDIR的路径为/usr/local/tomcat
  
FROM openjdk:15-jdk-oraclelinux7

ENV CATALINA_HOME /usr/local/tomcat
ENV PATH $CATALINA_HOME/bin:$PATH
RUN mkdir -p "$CATALINA_HOME"
WORKDIR $CATALINA_HOME

查询运行中的容器,并没有tomcat,也说明tomcat是没有启动成功

接下来,我们讲下ENTRYPOINT,它不会被docker run后面的参数覆盖,而是追加。docker run 之后的参数会被当做参数传递给ENTRYPOINT,之后形成新的命令组合。

这里,我们制作可以测试的dockerfile,Dockerfile如下

FROM docker.io/centos
MAINTAINER michard michard@qq.com
CMD echo "this is echoo"
CMD ls -l
CMD ["echo","hello world"]
CMD echo "last one"

编译dockerfile,docker build -f df2 -t centos5:latest .

我们可以发现centos5镜像已经构建完成,然后启动容器。

我们可以看到,CMD只执行最后一条指令。所以一个Dockerfile可以有多条CMD指令,但是只能有一条生效,

就是最后一条。

接下来看下ENTRYPOINT,我们复制下dockerfile,进行修改,修改后内容如下

FROM docker.io/centos
MAINTAINER michard michard@qq.com
CMD echo "this is echoo"
CMD ls -l
CMD ["echo","hello world"]
CMD echo "last one"
ENTRYPOINT echo "entrypoint last two"
ENTRYPOINT echo "entrypoint last one"

官网也有讲了https://docs.docker.com/engine/reference/builder/,CMD提供了两种方式,一种是exec方式,一种是

shell方式。如果CMD是参数的形式,则看作ENTRYPOINT的默认参数,如果要作为ENTRYPOINT的参数,则CMD和ENTRYPOINT,都要使用json格式的语句。

例如

FROM docker.io/centos
MAINTAINER michard michard@qq.com
CMD ["hello world"]
ENTRYPOINT echo

docker run 镜像ID,这个输出空,因为ENTRYPOINT,没有使用json格式参数

FROM docker.io/centos
MAINTAINER michard michard@qq.com
CMD ["hello world"]
ENTRYPOINT ["echo"]

此dockerfile 启动后,docker run 镜像ID,打印出hello world。这里CMD的参数会作为ENTRYPOINT的参数。

使用CMD command param1 param2,则是使用shell方法。

The main purpose of a CMD is to provide defaults for an executing container. These defaults can include an executable, or they can omit the executable, in which case you must specify an ENTRYPOINT instruction as well. 官方文档里这句话很重要,CMD的主要目的是为执行中的容器,提供默认执行的语句。这些语句可以包括可执行语句,或者当你的dockfile里

包含ENTRYPOINT的时候,cmd语句可以不被执行。意味着当含有ENTRYPOINT语句的时候,CMD语句是不执行的。也就是说真正启动容器后,执行的是ENTRYPOINT,而不是CMD。就像上面讲的,docker run后面如果没有指定参数,那么CMD不会被覆盖,如果指定了,CMD就会被覆盖。

不同的是使用shell方式,exec方式则不会调用shell命令,意味着shell进程不会被执行。例如CMD ["echo","$HOME"]中,

$HOME不是一个变量(输出$HOME,而不是$HOME的变量)。如果你想要用shell执行它,可以使用shell方式或者直接执行cmd shell方式。例如,使用

CMD ["sh","-c","echo $HOME"](这句会执行shell,那么$HOME会被解析输出该变量值)。当使用exec方式且直接执行shell的时候,这种shell方式,运行的环境是shell环境,而不是docker。

ENTRYPOINT有两种方式来定义语句,exec和shell,也就是命令行和shell。

如果run命令后面有东西,那么后面的全部都会作为entrypoint的参数。如果run后面没有额外的东西,但是cmd有,那么cmd的全部内容会作为entrypoint的参数,这同时是cmd的第二种用法。这也是网上说的entrypoint不会被覆盖。当然如果要在run里面覆盖,也是有办法的,使用--entrypoint。

简单讲,CMD和ENTRYPOINT的区别,两者都是在容器启动时,指定要执行的命令。不同的是,CMD会被覆盖,ENTRYPOINT 会被追加组合成新命令,继续执行。

晚上,再加下RUN的解析............................

 

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值