Dockerfile中CMD与ENTERPOINT差异比较

在我们编写Dockerfile时,CMD 和 ENTRYPOINT 指令都可以用来指定容器启动时运行的命令,从程序设计角度来说,Docker不可能提供两种一样的指令,它们之间究竟有什么差异和关联呢?

在了解两者差异之前,我们先了解一下Dockerfile中两种启动命令编写模式:

  • exec模式:CMD ["a", "b", "c"], 容器启动后会执行命令:a b c
  • Shell:CMD "a" , 容器启动后会执行命令:/bin/sh a

可以看出,exec模式采用数组的形式,容器启动时会把数组中的值依次转化组合成shell命令,而shell模式则是采用字符串的形式,字符串会作为/bin/sh -c的参数。

下面通过 CMD 指令来验证 exec 模式和 shell 模式。

exec 模式

1
2
FROM ubuntu
CMD ["top"]

将上面代码保存到Dockerfile中,然后构建镜像并启动一个容器。

1
2
3
4
# 构建镜像
docker build -t ubuntu/test:1 .
# 启动容器
docker run -itd --name ubuntu-test-1 ubuntu/test:1

检查一下容器是否在运行:docker ps -a

docker

可以看出容器在后台正常运行,查看一下容器的进程:

1
docker exec ubuntu-test-1 ps aux

docker

可以看到top命令正在运行,pid为1

shell 模式

1
2
3
FROM ubuntu

CMD "top"

将上面代码保存到Dockerfile中,同样构建镜像并启动一个容器。

1
2
3
4
# 构建镜像
docker build -t ubuntu/test:2 .
# 启动容器
docker run -itd --name ubuntu-test-2 ubuntu/test:2

查看当前所有容器:docker ps -a

docker

可以看到当前容器运行的命令是:/bin/sh -c \"top\", 而之前容器运行的命令是:"top", 验证了exec模式和shell模式的差异。

查看一下当前容器的进程:

1
docker exec ubuntu-test-2 ps aux

docker

1号进程是/bin/sh -c "top"top命令pid是6。

CMD与ENTRYPOINT差异

关于CMD与ENTRYPOINT有几条铁律:

  • 在Dockerfile中,只能有一个ENTRYPOINT指令,如果有多个ENTRYPOINT指令则以最后一个为准;
  • 在Dockerfile中,只能有一个CMD指令,如果有多个CMD指令则以最后一个为准;
  • 执行docker run如果带有其他命令参数,将会覆盖CMD指令;

同时Docker官方文档中,给出了CMD指令的用法:

  • CMD [“executable”,”param1”,”param2”] (exec form, this is the preferred form)
  • CMD [“param1”,”param2”] (as default parameters to ENTRYPOINT)
  • CMD command param1 param2 (shell form)

结合以上几点,我们可以知道,当同时存在CMD指令和ENTRYPOINT指令时,只会执行ENTRYPOINT指令,至于如何处理CMD指令,就要分很多种情况,可见官方说明:

docker

在日常开发中,ENTRYPOINT指令,往往用于设置容器启动后的第一个命令,CMD指令,往往用于设置容器启动的第一个命令的默认参数,这对一个容器来说可以是变化的。

有用就打赏一下作者吧!