在 Kubernetes 中,当你在 Pod 定义中指定command和args字段时,它们对应于 Docker 容器中的ENTRYPOINT和CMD指令,但以一种特定的方式进行映射。
一、command和args
在 Kubernetes 的 Pod 定义中:
-
command字段对应于 Docker 的ENTRYPOINT。
-
args字段对应于 Docker 的CMD。
这意味着当你在 Kubernetes Pod 中指定command时,它会覆盖 Docker 镜像中定义的ENTRYPOINT。同样,当你指定args时,它会覆盖 Docker 镜像中定义的CMD。但会有一些特殊情况,比如只指定配置command的时候,只指定配置args的时候,下面会对这些情况进行详细说明
二、ENTRYPOINT和CMD
-
容器应用进程 = ENTRYPOINT(入口点)+ CMD
-
Docker ENTRYPOINT 定义了容器启动时运行的命令。它可以是一个可执行文件或者一个脚本。
-
Docker CMD 提供了 ENTRYPOINT 的默认参数。如果没有提供 CMD,那么 ENTRYPOINT 需要是一个完整的命令。如果提供了 CMD,它可以作为 ENTRYPOINT 的参数。如果没有ENTRYPOINT,则CMD需要一个完整命令
-
如果在 Dockerfile 中没有显式配置 ENTRYPOINT,Docker 会使用一个默认的 ENTRYPOINT。这个默认的 ENTRYPOINT 是 /bin/sh -c。
针对 docker run 镜像id sleep 3600
命令:- 那么对于
ENTRYPOINT
,sleep 3600
参数会被追加到么Dockerfile中ENTRYPOINT
指定的命令之后。也就是说,这些参数作为ENTRYPOINT
指定命令的参数。 - 对于
CMD
,如果docker run
命令中指定了sleep 3600
参数,那么Dockerfile中CMD
指定的命令会被sleep 3600
替换。 - 如果docker run
镜像id
--entrypoint start.sh,那么Dockerfile中的ENTRYPOINT会被覆盖
- 那么对于
ENTRYPOINT 的两种格式
- ENTRYPOINT ["executable", "param1", "param2"] (exec格式,推荐)
- ENTRYPOINT command param1 param2 (shell 格式)
CMD指令有三种格式
- CMD ["executable","param1","param2"] (exec 格式,推荐)
这种格式使用 JSON 数组来运行命令。这意味着执行的命令不会被 shell 处理,而是直接执行。这种方式通常更安全,并且是推荐的方式,因为它不会受到 shell 字符串解析规则的影响。
推荐使用 exec
格式的 CMD
指令,主要是因为这种格式直接执行命令,而不是在 shell 环境中执行。这有几个优点:
-
更少的层:当你使用
exec
格式时,命令不会在 shell 中启动,这意味着没有额外的 shell 进程。这使得 Docker 容器中的进程结构更简单,容器启动时创建的进程数也更少。 -
信号传递:使用
exec
格式,执行的命令会成为容器的 PID 1 进程。这样做的好处是,发送到容器的信号(如 SIGTERM)可以直接被应用程序捕获和处理,从而使得应用程序能够更好地响应停止请求等信号。 -
不会受 shell 行为的影响:在 shell 格式中,你的命令和参数会被 shell 解释。这可能导致一些不期望的行为,比如特殊字符的解析、路径展开、变量替换等。而
exec
格式不会经过 shell 解释,执行的命令和参数会被直接传递给操作系统,避免了这些问题。 -
安全性:因为
exec
格式的命令不会被 shell 解释,所以更不容易受到 shell 注入攻击等安全问题的影响。
- CMD command param1 param2 (shell 格式)
这是最简单的格式,它在 shell 中执行命令,就像你在命令行中输入一样。当使用这种格式时,命令将在 /bin/sh -c
下执行。
- CMD ["param1", "param2", ...] (参数 格式)
当使用这种格式时,需要与 ENTRYPOINT
指令一起使用。在这种情况下,CMD
提供了参数列 表,这些参数将会被发送到 ENTRYPOINT
指定的程序。
dockerinit
dockerinit 会负责完成根目录的准备、挂载设备和目录、配置 hostname 等一系列需要在容器内进行的初始化操作。最后,它通过 execv() 系统调用,让应用进程(ENTRYPOINT + CMD)取代自己,成为容器里的 PID=1 的进程
注意
-
Dockerfile 中多个CMD 最后一个生效
-
shell和exec格式的区别,只有shell形式才会获取相关环境变量(这里环境变量指例如:$HOME)
-
docker run CMD 会覆盖 Dockerfile 中的 CMD
三、command、args、CMD、ENTRYPOINT对比
-
替换而非追加:在 Kubernetes 中,当你设置 command 或 args 时,你是在替换 Docker 镜像中的 ENTRYPOINT 和 CMD,而不是在它们后面追加命令或参数。
-
独立使用:你可以只设置 command(此时 args 会被忽略,command 将覆盖 Docker 容器的 ENTRYPOINT,但不会采用 Docker 容器的 CMD 作为参数),也可以只设置 args(此时会使用 Docker 镜像的 ENTRYPOINT)。
-
灵活性:这种方式提供了灵活性,允许 Kubernetes 用户根据需要自定义容器的启动行为。
理解 command 和 args 如何影响容器的启动行为对于正确配置和调试 Kubernetes 应用至关重要。它们让你能够控制容器的运行方式,确保它们以期望的方式执行。
k8s pod | docker | 最后生效的命令 | ||
command | args | entrypoint | cmd | |
配置 | 不配置 | 配置 | 配置 | command |
不配置 | 配置 | 配置 | 配置 | entrypoint+args |
配置 | 配置 | 配置 | 配置 | command+args |
不配置 | 不配置 | 配置 | 配置 | entrypoint+cmd |
四、示例
假设您有一个 Docker 镜像,其 Dockerfile 包含以下指令
ENTRYPOINT ["entrypoint.sh"]
CMD ["defaultArg"]
在这个 Docker 镜像中,entrypoint.sh是默认的ENTRYPOINT,而defaultArg是传递给它的默认CMD。
#### Kubernetes Pod 定义
如果您在 Kubernetes Pod 定义中如下设置command和args:
apiVersion: v1
kind: Pod
metadata:
name: example-pod
spec:
containers:
- name: example-container
image: example-image
command: ["newentrypoint.sh"]
args: ["arg1", "arg2"]
-command: ["newentrypoint.sh"]会覆盖 Docker 镜像的ENTRYPOINT为newentrypoint.sh。
-args: ["arg1", "arg2"]会覆盖 Docker 镜像的CMD为arg1和arg2。
五、总结
当您在 Kubernetes 中使用command和args时,请确保理解这些设置会如何影响容器的启动行为。如果您的容器依赖于 Dockerfile 中定义的ENTRYPOINT或CMD,更改这些值可能会导致容器以意外的方式运行或启动失败。
总结来说,Kubernetes 中的command对应于 Docker 的ENTRYPOINT,而args对应于 Docker 的CMD,并且在 Kubernetes Pod 定义中指定这些会覆盖 Docker 镜像中的相应设置。