对比分析 Dockerfile 中的 ENTRYPOINT 和 CMD
5 min read · November 15th 2017
概述
Dockerfile 中的 ENTRYPOINT 指令和 CMD 指令都可以设置容器启动时要执行的命令。
ENTRYPOINT 有两种形式:
- exec 模式,如
ENTRYPOINT ["executable", "param1", "param2"] - shell 模式, 如
ENTRYPOINT command param1 param2
而 CMD 也有两种形式:
-
exec 模式,如
CMD ["executable","param1","param2"]- 当有 entrypoint 时,executable 等价于 param, 官方手册将其也作为了一种模式,严格来讲这仍是 exec 模式。
- shell 模式,
CMD command param1 param2
实验过程
为了研究它们的不同之处,我们通过实验,任意组合各种情形,分析其执行结果。
ENTRYPOINT 和 CMD 分别有好多种情形,彼此间的组合情况更多,为了简化描述,我们引入代号。
规则如下:
- e -> 表示 ENTRYPOINT
- c -> 表示 CMD
- 0 -> 表示 Dockerfile 中没有指令。
- 1 -> 表示 Dockerfile 中指令采用 exec 形式,且仅有一个参数。
- 2 -> 表示 Dockerfile 中指令采用 shell 形式,且仅由一个参数。
- 3 -> 表示 Dockerfile 中指令采用 exec 形式, 有多个参数。
- 4 -> 表示 Dockerfile 中指令采用 shell 形式, 有多个参数。
举例说明,e1c1 表示 Dockerfile 中同时存在 ENTRYPOINT 和 CMD,且是 exec 形式,仅用一个参数。 其 Dockerfile 如下:
// ./Dockerfile.e1c1
FROM alpine
COPY ./mycmd /usr/bin/
ENTRYPOINT ["/usr/bin/mycmd"]
CMD ["arg"]mycmd 命令用来打印命令行参数,其内容如下:
#!/bin/sh
echo $@实验中任意组合各种情况下的 ENTRYPOINT 和 CMD, 生成 Dockerfile。
创建和执行过程:
docker build -t e1c1 -f Dockerfile.e1c1 .
docker run -rm e1c1
docker run -rm e1c1 a收集 docker run 的输出,可以得到下表:
| N.O. | ENTRYPOINT | CMD | RUN | OUPUT |
|---|---|---|---|---|
| e1c1 | ["/usr/bin/mycmd"] | ["arg"] | arg | |
| ["/usr/bin/mycmd"] | ["arg"] | a | a | |
| e1c0 | ["/usr/bin/mycmd"] | |||
| ["/usr/bin/mycmd"] | a | a | ||
| e1c2 | ["/usr/bin/mycmd"] | arg | /bin/sh -c "arg" | |
| ["/usr/bin/mycmd"] | arg | a | a | |
| e2c0 | /usr/bin/mycmd | |||
| /usr/bin/mycmd | a | |||
| e2c1 | /usr/bin/mycmd | ["arg"] | ||
| /usr/bin/mycmd | ["arg"] | a | ||
| e2c2 | /usr/bin/mycmd | arg | ||
| /usr/bin/mycmd | arg | a | ||
| e0c0 | ||||
| a | docker: Error..."exec: "a": executable file not found... | |||
| mycmd a | a | |||
| e0c1 | ["mycmd"] | |||
| ["mycmd"] | a | docker: Error..."exec: "a": executable file not found... | ||
| e0c2 | mycmd | |||
| mycmd | a | docker: Error..."exec: "a": executable file not found... | ||
| e0c3 | ["mycmd", "a"] | a | ||
| ["mycmd", "a"] | a | docker: Error..."exec: "a": executable file not found... | ||
| e0c4 | mycmd a | a | ||
| mycmd a | a | docker: Error..."exec: "a": executable file not found... | ||
| e3c0 | ["/usr/bin/mycmd", "a"] | a | ||
| ["/usr/bin/mycmd", "a"] | b | a b | ||
| e3c1 | ["/usr/bin/mycmd", "a"] | ["b"] | a b | |
| ["/usr/bin/mycmd", "a"] | ["b"] | c | a c | |
| e3c2 | ["/usr/bin/mycmd", "a"] | b | a /bin/sh -c "b" | |
| ["/usr/bin/mycmd", "a"] | b | c | a c | |
| e4c0 | /usr/bin/mycmd a | a | ||
| /usr/bin/mycmd a | b | a | ||
| e4c1 | /usr/bin/mycmd a | ["b"] | b: line 1: /usr/bin/mycmd a: not found | |
| /usr/bin/mycmd a | ["b"] | c | c: line 1: /usr/bin/mycmd a: not found | |
| e4c2 | /usr/bin/mycmd a | b | /bin/sh: line 1: /usr/bin/mycmd a: not found | |
| /usr/bin/mycmd a | b | c | c: line 1: /usr/bin/mycmd a: not found |
- N.O. -> 组合情形编号。
- ENTRYPOINT -> Dockerfile 中指令 ENTRYPOINT 的值。
- CMD -> Dockerfile 中指令 CMD 的值。
- RUN 表示执行时传递给容器的值。
- OUTPUT 时执行后打印的结果。
结论
- e2 时 cmd 值全部无效,可以得出 ENTRYPOINT 采用 shell 模式且没有参数时会忽略 cmd 。
- e4 有 cmd 值全部报错,可以得出 ENTRYPOINT 采用 shell 模式有参数时传入 cmd 会报错 。
- 从 e2 和 e4 可以看出, 推荐使用 exec 模式配置 ENTRYPOINT ,它接受 cmd 且更安全。
- docker run 中 命令行传入的 cmd 会覆盖 Dockerfile 中的 CMD。
- 根据 e1c2 和 e3c2, Dockerfile 中 CMD 在 shell 模式下内部会被转换为前部拼接 ["/bin/sh", "-c"] 的 exec 模式。
- 结合 e1c2 和 e3c2, 推荐使用 exec 模式配置 CMD 。
- 从 e3 可以得出: Dockerfile 中的 ENTRYPOINT 在 exec 模式下自带的参数会与 cmd 参数拼接