本文可以学到

  1. .kube/config 文件中有哪些内容
  2. 如何实现 bash 的命令补全功能

起因

在使用 kubectl 命令的过程中,经常需要查看不同 namespace 下的资源,因此命令经常需要带上 -n name

如果不想每次都多打这些字符,也可以设置一个默认的 namespace,

kubectl config set-context --current --namespace=xxxx

这样是方便了不少,但是一旦切换了 namespace 之后,又要重复上面的命令,而且经常还不记得。

有没有更好的办法呢? 有人开发了一个小工具,kubectx 专门用于方便的切换 ctx 和 namespace。 ctx 是什么呢? 其实就是哪个 k8s 集群。 说白了就是让你方便的在多个集群和 namespace 之间切换。

kubectx 有两种实现,一开始用的是最简单的 bash shell 脚本,新的版本开始用 k8s client API 开发。 下文的分析仅仅关注 namespace 的切换。

shell 版本的实现

这个实现非常简单,本质上就是调用几个 kubectl 命令实现 ns 切换。

首先需要知道的是,在 ~/.kube/config 路径下的 config 记录了你配置 kubectl 的信息,比如你用 kubectl 操作过几个 k8s 都会纪录在里面。

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://10.180.117.162
  name: gke_hyrule-dev_us-central1_hyrule-us-central1
contexts:
- context:
    cluster: gke_hyrule_us-central1
    namespace: mi-hyrule
    user: gke_hyrule-dev_us-central1_hyrule-us-central1
  name: gke_hyrule-dev_us-central1_hyrule-us-central1
- context:
    cluster: 
    user: 
  name: 
current-context: gke_hyrule_us-central1
kind: Config
preferences: {}
users:
- name: gke_hyrule-dev_us-central1_hyrule-us-central1
  user:
    auth-provider:
      config:
        access-token: ya29.c.Ko8BCghf9Cp47iz7usZH24k_ask9OD6E4KEh-Z
        cmd-args: config config-helper --format=json
        cmd-path: /usr/lib/google-cloud-sdk/bin/gcloud
      name: gcp

如果是多个 k8s 的话将会有多个 contextsusers 字段。

kubectx 命令主要就是根据这个 config 获得基本信息,再调用 kubectl 切换 ns。

先用这个内置的命令获得是哪个 k8s

$ kubectl config current-context
gke_hyrule_us-central1

然后,用 kubectl config view 显示 config 文件内容,它的输出和 .kube/config 是一样的,

$ kubectl config view -o=jsonpath="{.contexts[?(@.name==\"${cur_ctx}\")].context.namespace}")" 

kubectx 用了一个表达式过滤输出的信息,这个命令获得当前 k8s 默认是哪个ns。

$ kubectl get namespaces -o=jsonpath='{range .items[*].metadata.name}{@}{"\n"}{end}'

这个命令获得所有的 namespace。

所以,切换 ns 就是用上面 3 个 命令实现自动化。

Golang 版本实现

粗略看了一下,感觉没有必要用 go 写,代码晦涩难懂,略过。

命令补全

在阅读 kubectx 和其他几个 krew 安装的 kubectl 插件源代码的过程中,发现他们都提供了 bash/zsh 的命令补全功能,于是学习了一下。

简单来说,就是要问你的 binary 文件提供了一个 bash 脚本,比如 kubectx 的如下

_kube_namespaces()
{
  local curr_arg;
  curr_arg=${COMP_WORDS[COMP_CWORD]}
  COMPREPLY=( $(compgen -W "- $(kubectl get namespaces -o=jsonpath='{range .items[*].metadata.name}{@}{"\n"}{end}')" -- $curr_arg ) );
}

complete -F _kube_namespaces kubens kns

其中几个 bash 内置变量解释如下:

IdNameDescription
1COMP_WORDS类型为数组;存放当前命令行中输入的所有单词
2COMP_CWORD类型为整数;当前光标下输入的单词位于 COMP_WORDS 数组中的索引
3COMP_LINE类型为字符串;表示当前的命令行输入
4COMP_WORDBREAKS类型为字符串;表示单词之间的分隔符
5COMPREPLY类型为数组;候选的补全结果

这样就可以实现在输入 kubectx 命令,按两下 Tab 键后会出现所有的 namespace 候选,并且还能根据你的输入即时过滤候选词。

参考资料

  1. https://www.escapelife.site/posts/22db372f.html