![25e9dee04a7ee19b64d8f3c9fe251380.png](https://i-blog.csdnimg.cn/blog_migrate/c29663d0c75d6f7d188e3b87b1691653.jpeg)
Kubernetes目前支持对Kubectl命令行工具进行拓展,也就是所谓的 kubectl plugins
, 具体可以查看官方文档:
![4c9be44b9be56d1644a05c7ccafb6ae5.png](https://i-blog.csdnimg.cn/blog_migrate/9cbbdf6559b7635898251cb8f6da6671.jpeg)
那么我们就试着来实现一个小的Demo,为了方便,我们就使用官方的实例。
首先实现一个Kubectl Plugin的要求总结如下:
- 可执行文件
- 名称以
kubectl-
开头,命令以-
来分割,比如kubectl gpu version
的可执行文件名称是kubectl-gpu-version
。命令名称中如果包含-
,用_
表示,比如kubectl gpu-version
的可执行文件名称是kubectl-gpu_version
- 可执行文件位于
PATH
路径下 - 不能和
kubectl
命令或者子命令重复,比如kubectl version
在实现的时候我们需要注意几点:
- Kubectl查找时按照最长匹配原则,比如存在
kubectl-gpu
和kubectl-gpu-version
,那么输入kubectl gpu verson
时执行的是kubectl-gpu-version
。 - 运行命令名称重复,但是只有一个会执行,具体哪个可以通过
kubectl plugin list
查看
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
明确了上面的需求和注意点,我们来写一个脚本文件 kubectl-foo
#!/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"
然后一道$PATH
目录下:
sudo chmod +x ./kubectl-foo
sudo mv ./kubectl-foo /usr/local/bin
kubectl foo
这样我们就可以看到 "I am a plugin named kubectl-foo"
这个结果了。
总体上来说还是很简单的,那么Kubernetes是怎么实现的呢,其实也很简单,就是一个查找过程,源码解析如下:
pkg/kubectl/cmd/cmd.go Line 310
func NewDefaultKubectlCommandWithArgs(pluginHandler PluginHandler, args []string, in io.Reader, out, errout io.Writer) *cobra.Command {
cmd := NewKubectlCommand(in, out, errout)
if pluginHandler == nil {
return cmd
}
if len(args) > 1 {
cmdPathPieces := args[1:]
if _, _, err := cmd.Find(cmdPathPieces); err != nil { //如果找到Kubectl子命令,直接退出
if err := HandlePluginCommand(pluginHandler, cmdPathPieces); err != nil { // 查找Plugin命令
fmt.Fprintf(errout, "%vn", err)
os.Exit(1)
}
}
}
return cmd
}
pkg/kubectl/cmd/cmd.go Line 398
func HandlePluginCommand(pluginHandler PluginHandler, cmdArgs []string) error {
remainingArgs := []string{} // all "non-flag" arguments
for idx := range cmdArgs {
if strings.HasPrefix(cmdArgs[idx], "-") { // 跳过flag参数
break
}
remainingArgs = append(remainingArgs, strings.Replace(cmdArgs[idx], "-", "_", -1)) // 替换其中的“-”为_“”
}
foundBinaryPath := ""
// attempt to find binary, starting at longest possible name with given cmdArgs
for len(remainingArgs) > 0 {
path, found := pluginHandler.Lookup(strings.Join(remainingArgs, "-")) // 在Path中寻找可执行文件(用-连接)
if !found {
remainingArgs = remainingArgs[:len(remainingArgs)-1] // 没找到缩短名称
continue
}
foundBinaryPath = path
break
}
if len(foundBinaryPath) == 0 {
return nil
}
// invoke cmd binary relaying the current environment and args given
if err := pluginHandler.Execute(foundBinaryPath, cmdArgs[len(remainingArgs):], os.Environ()); err != nil { // 调用Plugin可执行文件
return err
}
return nil
}
关于上面的内容已经放到Github上了,欢迎Star :)
kuberenetes-learning/kubectl-plugin-demogithub.com![66d650cfc6750880490301a52f52407a.png](https://i-blog.csdnimg.cn/blog_migrate/cdbcab6ee15c19d6094fe44ace12f1d2.png)
也欢迎喜欢Kubernetes的一起加入这个小组 :)