一个实验搞清Dockerfile的CMD和Entrypoint指令

达芬奇密码2018-07-03 13:22

网易蜂巢(现更名为网易云计算基础服务)最近上线了容器自定义入口的功能, 还没有试用的同学可以先从本文开始~

CMD和ENTRYPOINT都是为镜像指定容器启动命令的常用Dockerfile指令, 本文将通过实验的方法详解这俩个命令的使用方法和用法差异.

CMD使用说明

序号 格式 使用说明
1 CMD ["executable","param1","param2"] 使用 exec 执行,推荐方式
2 CMD command param1 param2 shell form,是以”/bin/sh -c”的方法执行的命
3 CMD ["param1","param2"] 为ENTRYPOINT指定参数

用法1:CMD ["executable","param1","param2"]

PRE:

准备了两个小脚本分别ADD到所有的测试镜像中, 最后由/root/test打印内容确定所执行的脚本

cmd.sh

#!/bin/bash
while [ "1" = "1" ]
do
    for args in $@
    do
      echo "Printed by cmd.sh" $args >> /root/test
    done
sleep 2
done

entrypoint.sh

#!/bin/bash
while [ "1" = "1" ]
do
    for args in $@
    do
      echo "Printed by entrypoint.sh" $args >> /root/test
    done
sleep 2
done
  • Dockerfile: df-cmd1

FROM hub.c.163.com/ncetest001/debian:ssh

ADD cmd.sh /root/
ADD entrypoint.sh /root/
RUN chmod +x /root/cmd.sh
RUN chmod +x /root/entrypoint.sh

CMD ["/root/cmd.sh","arg1"]
#ENTRYPOINT ["/root/entrypoint.sh","ARG1"]
  • 构建镜像

docker build -t hub.c.163.com/***/debian:cmd1 -f /home/yuz/docker/df-cmd1 .

这里使用了蜂巢的镜像仓库, *为注册用户的nickname;在本地docker login蜂巢账户, 就可以向自己的仓库推送镜像, 这里我的仓库名是debian.

  • 启动镜像, 查看test结果:执行了CMD命令
root@yuz-server:/home/yuz/docker# docker run -d hub.c.163.com/***/debian:cmd1 
6f4545989696a7790b16233737fc3a187d782abdeb8ad604b2f106707809b409
root@yuz-server:/home/yuz/docker# docker ps 
CONTAINER ID        IMAGE                                  COMMAND               CREATED              STATUS              PORTS               NAMES
6f4545989696        hub.c.163.com/***/debian:cmd1   "/root/cmd.sh arg1"   About a minute ago   Up About a minute                       hungry_pike
root@yuz-server:/home/yuz/docker# docker exec -it 6f4545989696 /bin/bash
root@6f4545989696:/# cd     
root@6f4545989696:~# tailf test
Printed by cmd.sh arg1
Printed by cmd.sh arg1
Printed by cmd.sh arg1
Printed by cmd.sh arg1

用法2:CMD command param1 param2

  • Dockerfile: df-cmd2

ADD cmd.sh /root/
ADD entrypoint.sh /root/
RUN chmod +x /root/cmd.sh
RUN chmod +x /root/entrypoint.sh

CMD /root/cmd.sh arg2
#ENTRYPOINT ["/root/entrypoint.sh","ARG1"]

直接查看测试结果:执行了CMD命令

root@5c78b3d7e304:~# tailf test
Printed by cmd.sh arg2
Printed by cmd.sh arg2
Printed by cmd.sh arg2
Printed by cmd.sh arg2

用法3:CMD ["param1","param2"]

  • Dockerfile: df-cmd3

Add cmd.sh /root/
Add entrypoint.sh /root/
Run chmod +x /root/cmd.sh
Run chmod +x /root/entrypoint.sh

CMD ["arg3.1","arg3.2"]
Entrypoint ["/root/entrypoint.sh","ARG1"]

直接查看测试结果:CMD作为Entrpoint的参数打印

root@e600c62f8a5c:~# tailf test
Printed by entrypoint.sh arg3.2
Printed by entrypoint.sh ARG1
Printed by entrypoint.sh arg3.1
Printed by entrypoint.sh arg3.2
Printed by entrypoint.sh ARG1
Printed by entrypoint.sh arg3.1

可以看到docker ps 的结果中第二种用法以shell运行方式执行的命令是 /bin/sh -c


root@yuz-server:/home/yuz/docker# docker ps 
CONTAINER ID        IMAGE                                  COMMAND                  CREATED             STATUS              PORTS               NAMES
e600c62f8a5c        2e9769872b5c                           "/root/entrypoint.sh "   5 minutes ago       Up 5 minutes                            focused_wing
5c78b3d7e304        400b9c8b703a                           "/bin/sh -c '/root/cm"   5 minutes ago       Up 5 minutes                            amazing_bardeen
6f4545989696        hub.c.163.com/***/debian:cmd1   "/root/cmd.sh arg1"      9 minutes ago       Up 9 minutes                            hungry_pike

Entrypoint使用说明

序号 格式 使用说明
1 ENTRYPOINT ["executable", "param1", "param2"] 使用 exec 执行,推荐方式
2 ENTRYPOINT command param1 param2 shell form

同CMD用法, 这里就不对Entrypoint的具体用法举例说明.

CMD和Entrypoint的区别

在对比区别之前再总结下共同点:

  1. 指定启动容器时执行的命令,每个 Dockerfile 只能有一条 CMD/ENTRYPOINT 命令。如果指定了多条命令,只有最后一条会被执行。
  2. 用法都支持exec和shell两种使用方式且用法相近

那么区别是什么?

CMD: 启动容器时候指定了运行的命令,则会覆盖掉镜像中 CMD 指定的命令

ENTRYPOINT: 启动容器时候指定了运行的命令,并不会覆盖掉镜像中Entrypoint的命令

通过实验验证下:

回忆下, cmd1镜像中使用CMD命令

root@yuz-server:/home/yuz/docker# docker run -d hub.c.163.com/***/debian:cmd1 /root/cmd.sh 替换
d81d02b0003d1e195a1e9016f5c6d3724cb38e4f16dd98295a69faccaa71587e
root@yuz-server:/home/yuz/docker# docker ps 
CONTAINER ID        IMAGE                                  COMMAND                  CREATED             STATUS              PORTS               NAMES
d81d02b0003d        hub.c.163.com/***/debian:cmd1   "/root/cmd.sh 替换"        5 minutes ago       Up 5 minutes                            sleepy_euclid
root@yuz-server:/home/yuz/docker# docker exec -it d81d02b0003d /bin/bash
root@d81d02b0003d:/# cd 
root@d81d02b0003d:~# tailf test
Printed by cmd.sh 替换
Printed by cmd.sh 替换
Printed by cmd.sh 替换
Printed by cmd.sh 替换

结果: 启动容器的入口命令覆盖了CMD命令

cmd2镜像中使用ENTRYPOINT命令

root@yuz-server:/home/yuz/docker# docker run -d hub.c.163.com/***/debian:cmd3 /root/cmd.sh 替换
d81d02b0003d1e195a1e9016f5c6d3724cb38e4f16dd98295a69faccaa71587e
root@yuz-server:/home/yuz/docker# docker ps 
CONTAINER ID        IMAGE                                  COMMAND                  CREATED             STATUS              PORTS               NAMES
bf2ab7c4131f        hub.c.163.com/***/debian:cmd3   "/root/entrypoint.sh "   4 minutes ago       Up 4 minutes                            serene_pike
root@yuz-server:/home/yuz/docker# docker exec -it bf2ab7c4131f /bin/bash
root@bf2ab7c4131f:/# cd 
root@bf2ab7c4131f:~# tailf test
Printed by entrypoint.sh 替换
Printed by entrypoint.sh ARG1
Printed by entrypoint.sh /root/cmd.sh
Printed by entrypoint.sh 替换
Printed by entrypoint.sh ARG1
Printed by entrypoint.sh /root/cmd.sh
Printed by entrypoint.sh 替换
Printed by entrypoint.sh ARG1
Printed by entrypoint.sh /root/cmd.sh

结果: 启动容器的入口命令并没有覆盖ENTRYPOINT命令, 而是作为dockerfile中ENTRYPOINT的参数执行

其实, 通过上面的两次docker ps 命令也可以看出启动命令的不同.

网易蜂巢容器自定义入口

蜂巢上目前也加入了容器的自定义入口选项, 当容器的启动遇到问题如: Dockerfile中没有指定运行进程; 或者想要覆盖原有镜像中的CMD命令, 都可以通过下图指定地方进行添加, 欢迎适用:)

本文来自网易实践者社区,经作者张雨授权发布。