为什么 k8s 容器规范“命令”字段是一个数组?

Apl*_*nus 3 api-design kubernetes

根据这个官方 kubernetes 文档页面,可以向容器提供“命令”和参数。

该页面出现了 13 次字符串“a command”和 10 次出现“the command”——请注意使用单数。

(除了文件名之外)复数“命令”出现 3 次:

  1. 其中一个页面是 Get a Shell to a Running Container,我对此不感兴趣。我对容器的启动命令感兴趣。

  2. 其中提到的是在 shell 环境中运行多个管道命令,但是提供的示例使用单个字符串:command: ["/bin/sh"]

  3. 第三次出现在介绍性句子中:

本页展示了在 Pod 中运行容器时如何定义命令和参数。

command所有示例(包括给出或省略时如何交互的解释args)仅显示数组中的单个字符串。它甚至似乎只打算使用单个command,它将接收所有指定的args,因为该字段以单数命名。

问题是:为什么这个字段是一个数组?

我认为 Kubernetes 的开发者对此有充分的理由,但我想不出一个。这里发生了什么?是遗产吗?如果是这样,怎么会这样呢?是面向未来的准备吗?如果是这样,那又是为了什么?是为了兼容吗?如果是的话,为了什么呢?

编辑:

正如我在下面的评论中所写的,我现在能想到的唯一原因是:k8s 开发人员希望实现 和 的交互,commandargs允许用户 单个参数中指定命令的所有部分具有跨command和的命令范围args。所以本质上是功能和可读性之间的折衷。

谁能证实这个假设?

Dav*_*aze 5

因为execve (2) 系统调用需要一个字数组。更高层次上的一切,从根本上都归结为这一点。正如您所注意到的,容器仅运行单个命令,然后退出,因此数组语法是提供命令的本机 Unix 方式,而不是尝试指定多个命令的方式。

为了便于论证,请考虑一个名为 的文件a file; with punctuation,其中空格和分号是文件名的一部分。也许这是某个程序的输入,所以在 shell 中你可能会写

some_program 'a file; with punctuation'
Run Code Online (Sandbox Code Playgroud)

在 C 中,您可以将其写为字符串数组并运行它

char *const argv[] = {
  "some_program",
  "a file; with punctuation", /* no escaping or quoting, an ordinary C string */
  NULL
};
execvp(argv[0], argv);        /* does not return */
Run Code Online (Sandbox Code Playgroud)

类似地,在 Kubernetes YAML 中,您可以将其写为裸字的 YAML 数组

command:
  - some_program
  - a file; with punctuation
Run Code Online (Sandbox Code Playgroud)

Docker 和 Kubernetes 都不会自动为您运行 shell(除非Dockerfile shell 形式为ENTRYPOINTCMD)。问题的一部分是“哪个 shell”;自然的答案是容器中的 POSIX Bourne shell /bin/sh,但非常轻量级的容器甚至可能没有这个,有时 Linux 用户期望/bin/sh是 GNU Bash,结果会造成混乱。如果主容器进程是一个 shell 而不是它启动的东西,那么还存在潜在的生命周期问题。如果您确实需要 shell,则需要显式运行它

command:
  - /bin/sh
  - -c
  - some_program 'a file; with punctuation'
Run Code Online (Sandbox Code Playgroud)

请注意,sh -c的参数是单个单词(在我们的 C 示例中,它将是数组中的单个条目argv),因此它需要是 acommand:args:列表中的单个项目。如果您有sh -c包装器,它可以执行您在 shell 提示符下键入的任何操作,包括按顺序运行多个命令。对于很长的命令,在这里看到 YAML 块标量语法并不罕见。