【 K8S, Bash 】K8s-快速刪除全部特定資源指令-jsonpath-&-xargs

最近在公司因為在開發 K8s Operator 的緣故,因此常常需要使用 `Kubectl` 跟 K8s 這個魔王打交道,開心的是,也因此學會了很多 Bash 相關的快速指令,這一篇快速分享一下,我是如何使用 `JsonPath` 的語法以及 `xargs` 快速的操作 k8s 上面的資源的!本篇重點: `Kubectl` & `JsonPath` 概念、`xargs` 拆解字串並傳入指令中`

最近在公司因為在開發 K8s Operator 的緣故,因此常常需要使用 Kubectl 跟 K8s 這個魔王打交道,開心的是,也因此學會了很多 Bash 相關的快速指令,這一篇快速分享一下,我是如何使用 JsonPath 的語法以及 xargs 快速的操作 k8s 上面的資源的!

本篇重點:

  1. Kubectl & JsonPath 概念
  2. xargs 拆解字串並傳入指令中

Kubectl

kubectl 是與 k8s 互動的 CLI 工具,通常會搭配 get <resource> / delete <resource> 的方式去操作 K8s 中的資源。

當我們要取得 K8s 資源的詳細資料的時候通常會用以下的幾種方式去做取得

  1. kubectl get pod nginx
1NAME    READY   STATUS    RESTARTS      AGE
2nginx   1/1     Running   1 (24m ago)   22d
  1. kubectl get pod nginx -o yaml 以 YAML 的方式回傳資訊
 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  annotations:
 5    kubectl.kubernetes.io/last-applied-configuration: |
 6      {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"labels":{"aaa-aaa":"bbb-bbb","abc/def":"omg","hello":"hi"},"name":"nginx","namespace":"default"},"spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx","ports":[{"containerPort":80}]}]}}      
 7  creationTimestamp: "2024-06-18T02:51:33Z"
 8  labels:
 9    aaa-aaa: bbb-bbb
10    abc/def: omg
11    hello: hi
12  name: nginx
13  namespace: default
14  resourceVersion: "28520675"
15  uid: bd165233-da63-41fb-94ec-64d0ee87f512
16spec:
17  containers:
18  - image: nginx:1.14.2
19    imagePullPolicy: IfNotPresent
20    name: nginx
21    ports:
22    - containerPort: 80
23      protocol: TCP
24    resources: {}
25    terminationMessagePath: /dev/termination-log
26    terminationMessagePolicy: File
27    volumeMounts:
28    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
29      name: kube-api-access-vb2dh
30      readOnly: true
31... 以下省略
  1. kubectl get pod nginx -o json
 1{
 2    "apiVersion": "v1",
 3    "kind": "Pod",
 4    "metadata": {
 5        "annotations": {
 6            "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"labels\":{\"aaa-aaa\":\"bbb-bbb\",\"abc/def\":\"omg\",\"hello\":\"hi\"},\"name\":\"nginx\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"image\":\"nginx:1.14.2\",\"name\":\"nginx\",\"ports\":[{\"containerPort\":80}]}]}}\n"
 7        },
 8        "creationTimestamp": "2024-06-18T02:51:33Z",
 9        "labels": {
10            "aaa-aaa": "bbb-bbb",
11            "abc/def": "omg",
12            "hello": "hi"
13        },
14        "name": "nginx",
15        "namespace": "default",
16        "resourceVersion": "28520675",
17        "uid": "bd165233-da63-41fb-94ec-64d0ee87f512"
18    },
19    "spec": {
20        "containers": [
21            {
22                "image": "nginx:1.14.2",
23                "imagePullPolicy": "IfNotPresent",
24                "name": "nginx",
25                "ports": [
26                    {
27                        "containerPort": 80,
28                        "protocol": "TCP"
29                    }
30                ],
31                "resources": {},
32                "terminationMessagePath": "/dev/termination-log",
33                "terminationMessagePolicy": "File",
34                "volumeMounts": [
35                    {
36... 以下省略
  1. kubectl describe pod nginx 以 describe 的方式取得詳細的條列式資料 這種做法可以很漂亮的取得重要的 k8s 物件資訊
 1Name:             nginx
 2Namespace:        default
 3Priority:         0
 4Service Account:  default
 5Node:             henry-rapd-po-develop/192.168.89.96
 6Start Time:       Tue, 18 Jun 2024 10:51:33 +0800
 7Labels:           aaa-aaa=bbb-bbb
 8                  abc/def=omg
 9                  hello=hi
10Annotations:      <none>
11Status:           Running
12IP:               10.42.0.51
13IPs:
14  IP:  10.42.0.51
15Containers:
16  nginx:
17    Container ID:   containerd://6fd82893641cd7389395c62d0aa4168e599fb511b7ad63408dddb00cd0542b4f
18    Image:          nginx:1.14.2
19    Image ID:       docker.io/library/nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d
20    Port:           80/TCP
21    Host Port:      0/TCP
22    State:          Running
23      Started:      Wed, 10 Jul 2024 10:41:49 +0800
24    Last State:     Terminated
25      Reason:       Unknown
26      Exit Code:    255
27      Started:      Tue, 18 Jun 2024 10:51:40 +0800
28      Finished:     Wed, 10 Jul 2024 10:41:39 +0800
29    Ready:          True
30    Restart Count:  1
31    Environment:    <none>
32    Mounts:
33      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-vb2dh (ro)
34Conditions:
35  Type              Status
36  Initialized       True
37  Ready             True
38  ContainersReady   True
39  PodScheduled      True
40Volumes:
41  kube-api-access-vb2dh:
42    Type:                    Projected (a volume that contains injected data from multiple sources)
43    TokenExpirationSeconds:  3607
44    ConfigMapName:           kube-root-ca.crt
45    ConfigMapOptional:       <nil>
46    DownwardAPI:             true
47QoS Class:                   BestEffort
48Node-Selectors:              <none>
49Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
50                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
51Events:
52  Type    Reason          Age   From     Message
53  ----    ------          ----  ----     -------
54  Normal  SandboxChanged  26m   kubelet  Pod sandbox changed, it will be killed and re-created.
55  Normal  Pulled          26m   kubelet  Container image "nginx:1.14.2" already present on machine
56  Normal  Created         26m   kubelet  Created container nginx
57  Normal  Started         26m   kubelet  Started container nginx

Kubectl && JsonPath

上一節中提到我們取得資訊的格式可以是 json,也就代表我們可以用工具去分析這個JSON結構化資料,並且取得內容,這種作法已經內建在 kubectl 中了,也就是今天鼎鼎大名的主角 – JsonPath

先來一個簡單的指令

1kubectl get pod nginx -o jsonpath="{.metadata.name}"

我們得到的回應會是

1nginx

沒錯!我們簡化了輸出只取得重要的且我們關注的資訊! 這樣就可以在做 devops 的時候很方便地處理資料了!

.metadata.name 就是取得 剛剛範例中的 json 的資料,從 root key metadata 開始解析,取得 metadata 下的 name key 的資料!

接著,我們來處理一個複雜一點的狀況

1> kubectl get pod
2NAME                                   READY   STATUS    RESTARTS        AGE
3example-deployment1-7c68fc9d7f-hp9dw   1/1     Running   1 (35m ago)     27d
4example-deployment1-7c68fc9d7f-rncg6   1/1     Running   1 (35m ago)     27d
5example-deployment2-56bffc5686-bzvkk   1/1     Running   1 (35m ago)     27d
6example-deployment2-56bffc5686-vjw7p   1/1     Running   1 (35m ago)     27d
7example-pod                            1/1     Running   662 (35m ago)   27d
8nginx                                  1/1     Running   1 (35m ago)     22d

這次我們使用迴圈的方式去取得每一個 Pod 的 name,因此我們要使用 [*] 去針對每一個物件做處理

1> kubectl get pod -o jsonpath="{.items[*].metadata.name}"
2example-deployment1-7c68fc9d7f-hp9dw example-deployment1-7c68fc9d7f-rncg6 example-deployment2-56bffc5686-bzvkk example-deployment2-56bffc5686-vjw7p example-pod nginx

有發現這次開頭不一樣了嗎? 這是因為當我們取得多個物件的時候,k8s 會使用一個 items 的 key 去包裝這個陣列得值,也因此我們需要先取得 items 的陣列後 再使用 [*] 去針對陣列中所有的物件一一作分析 後面的 .metadata.name 就跟剛剛一樣,唯一不同的是這段是針對陣列裡的每一個物件去做處理!

xargs 整合

現在,我們已經使用 kubectl + jsonpath 取得了很多字串由空白分隔開來了

現在我們要把這些字串當作一個一個的參數傳進指令中

1kubectl get pod -o jsonpath="{.items[*].metadata.name}" | xargs -n 1 echo

xargs -n 1 echo 這邊的 -n 1 代表每一個字串都去執行一次 echo 指令

所以我們有10個pod 就會執行10次,echo 出 10 行

結果:

1example-deployment1-7c68fc9d7f-hp9dw
2example-deployment1-7c68fc9d7f-rncg6
3example-deployment2-56bffc5686-bzvkk
4example-deployment2-56bffc5686-vjw7p
5example-pod
6nginx

xargs 變化題 – 當作指令放進 bash 中

1kubectl get pod -o jsonpath="{.items[*].metadata.name}" | xargs -n 1 bash -c 'echo aaaa-$0-xdd'

我們可以用 bash -c 的方式當作參數傳入指令中,取得參數的方式就是用位置參數的取法就可以了 $0 $1 這種寫法

結果:

1aaaa-example-deployment1-7c68fc9d7f-hp9dw-xdd
2aaaa-example-deployment1-7c68fc9d7f-rncg6-xdd
3aaaa-example-deployment2-56bffc5686-bzvkk-xdd
4aaaa-example-deployment2-56bffc5686-vjw7p-xdd
5aaaa-example-pod-xdd
6aaaa-nginx-xdd

JsonPath + xargs 變化題 – 多參數 Xargs & 複雜結合字串處理的 JsonPath

這邊用了一些技巧去做出 第一個: 使用 range + {end} 的方式作迴圈,這樣就可以在每一次迴圈結束的時候加入換行符號了 第二個: 使用 {' '} 的方式串接字串

xargs 中的 -n 2 代表每兩個字串一組 -l 當作一行傳入 bash -c

1kubectl get pod --all-namespaces -o=jsonpath="{range .items[*]}{.metadata.name}{' '}{.metadata.namespace}{'\n'}{end}" | xargs -n 2 -l bash -c 'echo name: $0 ,namespace: $1'

結果:

1name: example-deployment1-7c68fc9d7f-hp9dw ,namespace: default
2name: example-deployment1-7c68fc9d7f-rncg6 ,namespace: default
3name: example-deployment2-56bffc5686-bzvkk ,namespace: default
4name: example-deployment2-56bffc5686-vjw7p ,namespace: default
5name: example-pod ,namespace: default
6name: nginx ,namespace: default

結語

這些 bash 指令真的很方便! 跟 SRE 合作以後,真的學到了很多很厲害的 bash 技巧,以後繼續更新文章記錄一下我的 Bash 技巧進步之路!

All rights reserved,未經允許不得隨意轉載
使用 Hugo 建立
主題 StackJimmy 設計