一些快捷方式让 kubectl 更好用

本文为同一作者原博客的中文翻译。

分享一些使用 kubectl 时的命令行小工具、技巧。

oh-my-zsh 的 kubectl 插件:

如果你使用 Zsh 和 oh-my-zsh, 这个插件 将会非常有帮助.

在 rc 文件 ~/.zshrc 的这一行 plugins= 处加上 kubectl 即可使用。即使你不用 Zsh,也许也可以找到你的 shell 的对应插件,或者直接把这里的一些 alias 和 functions 定义 加入到你自己的 rc 文件中去。

该插件最有用的部分就是 alias k=kubectl,只需要输入一个字母就可以使用 kubectl 命令。另一个比较有用的是 kca,它会把后面的命令应用到 all-namespaces

% kca get svc
NAMESPACE     NAME    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE
analytics     pod0    ClusterIP   172.20.xxx.xx    <none>        80/TCP              262d
analytics     pod1    ClusterIP   172.20.xxx.xx    <none>        80/TCP              4y190d
cache         pod2    ClusterIP   172.20.xxx.xx    <none>        6379/TCP            2y333d
cache         pod3    ClusterIP   None             <none>        6379/TCP,16379/TCP  2y333d

如果你本地安装了一些格式着色工具,比如 jq, fx, yh , 就可以使用快捷命令 kj, ky 来执行原本的 kuebctl 命令,输出内容会自动变成对应格式并用相应的工具高亮。

这个 oh-my-zsh 插件提供了大量 kubectl 命令(和子命令)的快捷方式。如果你是位全职运维工程师并且每天要使用大量不同的 kubectl 命令,这个插件提供的快捷方式将非常有用。但对我来说,我只会选取一个比较有限的集合只包括我非常高频使用并且可以灵活扩展的快捷方式。

精选 aliases:

我个人不喜欢诸如 kgp=kubectl get pods 这样的别名,太具体从而失去了灵活性。导致我要记大量不同别名。这是我自己使用的几个别名:

  • kg="k get"

  • kd="k describe"

  • kgy="k get -o yaml"

  • kgw="k get -o wide"

    我倾向于把别名设置到 kubectl 命令(getdescribe)这一级别,这样我可以只打两个字母就能用,还能跟剩余部分做各种结合。

    使用 kg 来获取某个类型的资源;使用 kgw 来展示更丰富的信息;使用 kgykd 来获得某个资源的细节。

    % kgw -n kube-system pod
    NAME          READY   STATUS    RESTARTS AGE   IP          NODE                        NOMINATED NODE   READINE
    SS GATES
    aws-node-xxx  1/1     Running   0        33d   10.0.xx.xx  ip-10-0-xx-xx.ec2.internal  <none>           <none>
    aws-node-ooo  1/1     Running   0        2d7h  10.0.xx.xx  ip-10-0-xx-xx.ec2.internal  <none>           <none>
    aws-node-yyy  1/1     Running   0        33d   10.0.xx.xx  ip-10-0-xx-xx.ec2.internal  <none>           <none>
    
    % kgy -n glow pod/my-pod-aaaaaaa-66666
    apiVersion: v1
    kind: Pod
    metadata:
      annotations:
        cliRestartAt: "1565324980"
        cluster-autoscaler.kubernetes.io/safe-to-evict: "true"
        fluentbit.io/exclude: "true"
        kubectl.kubernetes.io/restartedAt: "2023-10-10T21:51:25+08:00"
        kubernetes.io/psp: eks.privileged
      creationTimestamp: "2023-11-11T02:35:30Z"
      generateName: zoe-www-aaaaaaa-
      labels:
        app.kubernetes.io/instance: my-pod
        app.kubernetes.io/name: my-pod
    ... ...
    
  • kt="k taint node"
    在做 k8s 集群升级的过程当中我要经常使用 taint,所以加入这个别名。

  • ktop="k top"
    也经常使用 k top 来查看节点或 pods 的资源使用情况。

  • kl="k logs"
    这个别名是上文中 oh-my-zsh 插件提供的,同时还提供了其他几个相关的别名,也挺有用的,比如 klf(k logs -f), kl1m(k logs --since 1m)。

根据(部分) pod 名字来查找:

function kfindpod {
    name=$1
    shift
    kg --all-namespaces pod $@ | grep $name
}

偶尔会发生忘了名字空间但隐约记得 pod 名字的情况,我用这个方法把带某些关键词的 pod 都列出来。有一次我就是忘了 ingress 这个名字空间,就只能用这个方法把 aws load balancer controller 所在的 pod 和名字空间给找到:

aws:(prod-eks) k8s:(prod-eks)  % kfindpod lb
ingress  aws-lb-controller-xxx-yyy  1/1  Running     0  34d
ingress  aws-lb-controller-xxx-yyy  1/1  Running     0  34d

给节点添加 No-Schedule 污点:

function ktnos {
    for n in $*
    do
        k taint node $n eks-node-rolling:NoSchedule
    done
}
function ktnos- {
    for n in $*
    do
        k taint node $n eks-node-rolling:NoSchedule-
    done
}

在升级 k8s 集群的工作中,我需要经常给多个节点添加和去除污点,所以我写了这两个方法。如果读者自己使用的话,要根据你的 k8s 集群作相应调整,比如污点的键值对名称。

列出 pods 和它们所在的节点:

function kpodnode {
    ns=$1
    shift
    if [[ $ns =~ "allns" || $ns =~ "all"  ]]; then
      kg --all-namespaces pod -o=custom-columns=NAME:.metadata.name,NODE:.spec.nodeName,NS:.metadata.namespace,STATUS:.status.phase $@
    else
      kg -n $ns pod -o=custom-columns=NAME:.metadata.name,NODE:.spec.nodeName,STATUS:.status.phase $@
    fi
}
alias knodepod="kpodnode"

这个方法会选出某个名字空间下(或所有)的 pod,并显示对应的节点的名字。在升级工作节点使经常会用到。我最常把这两个方法搭配 -w 选项使用(可以持续监控 pod 的转移情况):

aws:(prod-eks) k8s:(prod-eks)  % kpodnode analytics -w
NAME                NODE                          STATUS
metabase2023-xxxx   ip-10-0-xx-oo.ec2.internal    Running
superset-yyy        ip-10-0-xx-oo.ec2.internal    Running

Node group 相关:

如果你使用 node group(节点组) 标签来组织 k8s 集群中的节点,你可能经常需要列出节点的 node group 信息,或要找到某个 node group 标签下的节点:

function kgnode {
    kubectl get node -o=custom-columns=NAME:.metadata.name,NODEGROUP:.metadata.labels.node-group,VERSION:.status.nodeInfo.kubeletVersion $@
}

function knodegroup {
    kubectl get node -l node-group=$@
}

⚠️注意:这个具体的标签名(node-group)可能不同,根据实际情况改写这些方法。

sops 更好用:

如果你使用 sops 来加解密 helm 变量,让相关指令变短是很有必要的。此外,我自己有两个 k8s 环境(对应两个 kube config)所以每次要根据环境指定不同的 kms 和加密变量文件挺麻烦的。所以我用下面这两个方法来“偷懒”:

function sopsd {
  if [[ $KUBECONFIG =~ "prod-eks$" ]]; then
    sops -d -i helm_vars/prod/secrets.yaml
  elif [[ $KUBECONFIG =~ "sandbox-eks$" ]]; then
    sops -d -i helm_vars/sandbox/secrets.yaml
  fi
}
function sopse {
  if [[ $KUBECONFIG =~ "prod-eks$" ]]; then
    sops -e -k arn:aws:kms:us-east-1:xxxx:key/ooo -i helm_vars/prod/secrets.yaml
  elif [[ $KUBECONFIG =~ "sandbox-eks$" ]]; then
    sops -e -k arn:aws:kms:us-east-1:yyyy:key/iii -i helm_vars/sandbox/secrets.yaml
  fi
}

读者如果要在自己的场景里使用,记得也要有指明 k8s 环境的环境变量(如果没有多个 k8s 环境可以直接去掉 if..elif分支判断)。同时 sops -e -k 里使用的秘钥(这里是一个 aws arn)和加密变量文件的路径也各不相同,请根据实际情况更改定制。