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 模式
FROM ubuntu
CMD ["top"]
1
2
2
将上面代码保存到Dockerfile中,然后构建镜像并启动一个容器。
# 构建镜像
docker build -t ubuntu/test:1 .
# 启动容器
docker run -itd --name ubuntu-test-1 ubuntu/test:1
1
2
3
4
2
3
4
检查一下容器是否在运行:docker ps -a
可以看出容器在后台正常运行,查看一下容器的进程:
docker exec ubuntu-test-1 ps aux
1
可以看到top
命令正在运行,pid为1。
# shell 模式
FROM ubuntu
CMD "top"
1
2
3
2
3
将上面代码保存到Dockerfile中,同样构建镜像并启动一个容器。
# 构建镜像
docker build -t ubuntu/test:2 .
# 启动容器
docker run -itd --name ubuntu-test-2 ubuntu/test:2
1
2
3
4
2
3
4
查看当前所有容器:docker ps -a
可以看到当前容器运行的命令是:/bin/sh -c \"top\"
, 而之前容器运行的命令是:"top"
, 验证了exec模式和shell模式的差异。
查看一下当前容器的进程:
docker exec ubuntu-test-2 ps aux
1
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指令,就要分很多种情况,可见官方说明:
在日常开发中,ENTRYPOINT指令,往往用于设置容器启动后的第一个命令,CMD指令,往往用于设置容器启动的第一个命令的默认参数,这对一个容器来说可以是变化的。
上次更新: 2022/12/01, 11:09:34