使用插件扩展 kubectl
本指南演示如何为 kubectl 安装和编写扩展。将核心 kubectl
命令视为与 Kubernetes 集群交互的基本构建块,集群管理员可以将插件视为利用这些构建块来创建更复杂行为的一种手段。插件使用新的子命令扩展 kubectl
,从而允许在 kubectl
的主发行版中不包含新的和自定义的功能。
开始之前
你需要安装一个可用的 kubectl
二进制文件。
安装 kubectl 插件
插件是一个独立的、可执行的文件,其名称以 kubectl-
开头。要安装插件,请将其可执行文件移动到 PATH
中的任何位置。
你也可以使用 Krew 来发现和安装开源中的 kubectl 插件。 Krew 是 Kubernetes SIG CLI 社区维护的插件管理器。
注意
通过 Krew 插件索引 提供的 Kubectl 插件未经过安全审计。你应该自行承担风险安装和运行第三方插件,因为它们是在你的机器上运行的任意程序。发现插件
kubectl
提供了一个命令 kubectl plugin list
,它会在你的 PATH
中搜索有效的插件可执行文件。执行此命令会导致遍历你 PATH
中的所有文件。任何可执行并以 kubectl-
开头的文件都将按照它们在 PATH
中出现的顺序显示在此命令的输出中。对于任何以 kubectl-
开头但不可执行的文件,都会包含警告。对于任何名称相互重叠的有效插件文件,也会包含警告。
你可以使用 Krew 从社区管理的 插件索引 中发现和安装 kubectl
插件。
创建插件
kubectl
允许插件通过在 PATH
中提供 kubectl-create-something
二进制文件,来添加 kubectl create something
形状的自定义创建命令。
局限性
目前无法创建覆盖现有 kubectl
命令或扩展 create
之外的命令的插件。例如,创建插件 kubectl-version
将导致该插件永远不会被执行,因为现有的 kubectl version
命令将始终优先于它。由于此限制,也*不能*使用插件向现有的 kubectl
命令添加新的子命令。例如,通过将插件命名为 kubectl-attach-vm
来添加子命令 kubectl attach vm
将导致该插件被忽略。
kubectl plugin list
会显示任何尝试执行此操作的有效插件的警告。
编写 kubectl 插件
你可以使用任何允许你编写命令行命令的编程语言或脚本来编写插件。
不需要插件安装或预加载。插件可执行文件接收来自 kubectl
二进制文件的继承环境。插件根据其名称确定它希望实现的命令路径。例如,名为 kubectl-foo
的插件提供命令 kubectl foo
。你必须将插件可执行文件安装在 PATH
中的某个位置。
示例插件
#!/bin/bash
# optional argument handling
if [[ "$1" == "version" ]]
then
echo "1.0.0"
exit 0
fi
# optional argument handling
if [[ "$1" == "config" ]]
then
echo "$KUBECONFIG"
exit 0
fi
echo "I am a plugin named kubectl-foo"
使用插件
要使用插件,请使插件可执行
sudo chmod +x ./kubectl-foo
并将其放置在 PATH
中的任何位置
sudo mv ./kubectl-foo /usr/local/bin
你现在可以将你的插件作为 kubectl
命令调用
kubectl foo
I am a plugin named kubectl-foo
所有参数和标志都会按原样传递给可执行文件
kubectl foo version
1.0.0
所有环境变量也会按原样传递给可执行文件
export KUBECONFIG=~/.kube/config
kubectl foo config
/home/<user>/.kube/config
KUBECONFIG=/etc/kube/config kubectl foo config
/etc/kube/config
此外,传递给插件的第一个参数将始终是调用它的位置的完整路径(在上面的示例中,$0
将等于 /usr/local/bin/kubectl-foo
)。
命名插件
如上面的示例所示,插件根据其文件名确定它将实现的命令路径。插件所针对的命令路径中的每个子命令都用破折号 (-
) 分隔。例如,一个希望在用户调用命令 kubectl foo bar baz
时调用的插件,其文件名将为 kubectl-foo-bar-baz
。
标志和参数处理
注意
插件机制*不*会为插件进程创建任何自定义的、特定于插件的值或环境变量。
旧版本的 kubectl 插件机制提供了环境变量,例如 KUBECTL_PLUGINS_CURRENT_NAMESPACE
;这种情况不再发生。
kubectl 插件必须解析并验证传递给它们的所有参数。有关面向插件作者的 Go 库的详细信息,请参阅 使用命令行运行时包。
以下是一些用户在提供其他标志和参数时调用你的插件的其他情况。这建立在上述场景中的 kubectl-foo-bar-baz
插件之上。
如果你运行 kubectl foo bar baz arg1 --flag=value arg2
,kubectl 的插件机制将首先尝试查找具有最长名称的插件,在本例中为 kubectl-foo-bar-baz-arg1
。在没有找到该插件时,kubectl 然后将最后一个破折号分隔的值视为参数(在本例中为 arg1
),并尝试查找下一个最长名称 kubectl-foo-bar-baz
。在找到具有此名称的插件后,kubectl 然后调用该插件,并将插件名称之后的所有参数和标志作为参数传递给插件进程。
示例
# create a plugin
echo -e '#!/bin/bash\n\necho "My first command-line argument was $1"' > kubectl-foo-bar-baz
sudo chmod +x ./kubectl-foo-bar-baz
# "install" your plugin by moving it to a directory in your $PATH
sudo mv ./kubectl-foo-bar-baz /usr/local/bin
# check that kubectl recognizes your plugin
kubectl plugin list
The following kubectl-compatible plugins are available:
/usr/local/bin/kubectl-foo-bar-baz
# test that calling your plugin via a "kubectl" command works
# even when additional arguments and flags are passed to your
# plugin executable by the user.
kubectl foo bar baz arg1 --meaningless-flag=true
My first command-line argument was arg1
如你所见,根据用户指定的 kubectl
命令找到了你的插件,并且一旦找到插件,所有额外的参数和标志都会按原样传递给插件可执行文件。
带有破折号和下划线的名称
虽然 kubectl
插件机制在插件文件名中使用破折号 (-
) 来分隔插件处理的子命令序列,但仍然可以通过在其文件名中使用下划线 (_
) 来创建在其命令行调用中包含破折号的插件命令。
示例
# create a plugin containing an underscore in its filename
echo -e '#!/bin/bash\n\necho "I am a plugin with a dash in my name"' > ./kubectl-foo_bar
sudo chmod +x ./kubectl-foo_bar
# move the plugin into your $PATH
sudo mv ./kubectl-foo_bar /usr/local/bin
# You can now invoke your plugin via kubectl:
kubectl foo-bar
I am a plugin with a dash in my name
请注意,在插件文件名中引入下划线并不会阻止你拥有诸如 kubectl foo_bar
之类的命令。可以通过使用破折号 (-
) 或下划线 (_
) 来调用上面示例中的命令。
# You can invoke your custom command with a dash
kubectl foo-bar
I am a plugin with a dash in my name
# You can also invoke your custom command with an underscore
kubectl foo_bar
I am a plugin with a dash in my name
名称冲突和覆盖
有可能在 PATH
中不同位置存在具有相同文件名的多个插件。例如,给定具有以下值的 PATH
:PATH=/usr/local/bin/plugins:/usr/local/bin/moreplugins
,插件 kubectl-foo
的副本可能存在于 /usr/local/bin/plugins
和 /usr/local/bin/moreplugins
中,因此 kubectl plugin list
命令的输出为
PATH=/usr/local/bin/plugins:/usr/local/bin/moreplugins kubectl plugin list
The following kubectl-compatible plugins are available:
/usr/local/bin/plugins/kubectl-foo
/usr/local/bin/moreplugins/kubectl-foo
- warning: /usr/local/bin/moreplugins/kubectl-foo is overshadowed by a similarly named plugin: /usr/local/bin/plugins/kubectl-foo
error: one plugin warning was found
在上面的场景中,/usr/local/bin/moreplugins/kubectl-foo
下的警告会告诉你,此插件永远不会被执行。相反,PATH
中首先出现的可执行文件 /usr/local/bin/plugins/kubectl-foo
将始终被 kubectl
插件机制首先找到和执行。
解决此问题的一种方法是确保你希望与 kubectl
一起使用的插件的位置始终位于 PATH
中的首位。例如,如果你希望在调用 kubectl
命令 kubectl foo
时始终使用 /usr/local/bin/moreplugins/kubectl-foo
,请将 PATH
的值更改为 /usr/local/bin/moreplugins:/usr/local/bin/plugins
。
调用最长的可执行文件名
插件文件名也可能出现另一种形式的覆盖。假设用户的 PATH
中存在两个插件:kubectl-foo-bar
和 kubectl-foo-bar-baz
,那么对于给定的用户命令,kubectl
插件机制将始终选择最长的插件名称。下面的示例进一步阐明了这一点。
# for a given kubectl command, the plugin with the longest possible filename will always be preferred
kubectl foo bar baz
Plugin kubectl-foo-bar-baz is executed
kubectl foo bar
Plugin kubectl-foo-bar is executed
kubectl foo bar baz buz
Plugin kubectl-foo-bar-baz is executed, with "buz" as its first argument
kubectl foo bar buz
Plugin kubectl-foo-bar is executed, with "buz" as its first argument
这种设计选择确保了插件子命令可以在多个文件中实现(如果需要),并且这些子命令可以嵌套在“父”插件命令下。
ls ./plugin_command_tree
kubectl-parent
kubectl-parent-subcommand
kubectl-parent-subcommand-subsubcommand
检查插件警告
你可以使用前面提到的 kubectl plugin list
命令来确保你的插件对 kubectl
可见,并验证是否有任何警告阻止它作为 kubectl
命令被调用。
kubectl plugin list
The following kubectl-compatible plugins are available:
test/fixtures/pkg/kubectl/plugins/kubectl-foo
/usr/local/bin/kubectl-foo
- warning: /usr/local/bin/kubectl-foo is overshadowed by a similarly named plugin: test/fixtures/pkg/kubectl/plugins/kubectl-foo
plugins/kubectl-invalid
- warning: plugins/kubectl-invalid identified as a kubectl plugin, but it is not executable
error: 2 plugin warnings were found
使用命令行运行时软件包
如果你正在为 kubectl 编写插件并且你正在使用 Go 语言,你可以使用 cli-runtime 实用程序库。
这些库提供了帮助程序,用于解析或更新用户的 kubeconfig 文件,用于向 API 服务器发出 REST 风格的请求,或者用于绑定与配置和打印相关的标志。
有关 CLI Runtime 仓库中提供的工具的示例用法,请参阅 示例 CLI 插件。
分发 kubectl 插件
如果你已经开发了一个供他人使用的插件,你应该考虑如何打包、分发它以及向用户交付更新。
Krew
Krew 提供了一种跨平台的方式来打包和分发你的插件。通过这种方式,你可以为所有目标平台(Linux、Windows、macOS 等)使用单一的打包格式,并向用户交付更新。Krew 还维护了一个 插件索引,以便其他人可以发现并安装你的插件。
原生/平台特定的软件包管理
或者,你可以使用传统的软件包管理器,例如 Linux 上的 apt
或 yum
、Windows 上的 Chocolatey 和 macOS 上的 Homebrew。如果任何软件包管理器可以将新的可执行文件放置在用户的 PATH
中的某个位置,那么它都是合适的。作为插件作者,如果你选择此选项,那么你还需要承担在每个版本中跨多个平台更新 kubectl 插件分发包的负担。
源代码
你可以发布源代码;例如,作为 Git 仓库。如果你选择此选项,那么想要使用该插件的人必须获取代码、设置构建环境(如果需要编译)并部署插件。如果你还提供已编译的软件包或使用 Krew,这将使安装更加容易。
下一步
- 请查看示例 CLI 插件仓库,其中包含一个用 Go 编写的插件的 详细示例。如有任何疑问,请随时联系 SIG CLI 团队。
- 阅读有关 Krew 的信息,这是一个 kubectl 插件的软件包管理器。