kubectl技巧之通過jsonpath擷取屬性

周國通發表於2019-06-19

系列目錄

前面一節我們介紹了使用go-template擷取屬性,go-template功能非常強大,可以定義變數,使用流程控制等,這是jsonpath所不具備的.然而,jsonpth使用的時候更為靈活.通過上一節我們發現,我們想要找到某個具體屬性,必須從最外層一層層向內找到具體屬性,這對於巢狀層次非常深的yaml物件來說操作是非常繁瑣的.而使用jsonpath只需要知道頂層物件,然後可以省略中間的物件,遞迴查詢直接找到我們想要的屬性,這在很多時候對我們在不清楚物件的層次但是清楚知道某個屬性名稱的時候獲取這個屬性的值是非常有幫助的.並且jsonpath可以使用下標索引陣列物件,這在實際工作中也是非常有幫助的(比如雖然pod裡可以包含多個containers,但是很多時候一個pod裡只有一個container,使用go-template我們為了找到這個物件需要寫一個遍歷表示式,而使用jsonpath可以直接取第0個物件,省去了寫迴圈的麻煩),還有一點很重要的是jsonpath是一個標準,這對於熟悉jsonpath的開發者來說使用起來方便很多.

jsonpath模板使用一對花括號({})把jsonpath表示式包含在裡面(go-template是雙花括號).除了標準jsonpath語法外,kubernetes jsonpath模板還額外支援以下語法:

  • 用""雙引號來引用JSONPath表示式中的文字

  • 使用rangeend來遍歷集合(這點和go-template類似)

  • 使用負數來從尾部索引集合

$操作符是可選的因為表示式預設總是從根節點開始選擇
物件通過它的String()函式列印輸出出來

假如有以下JSON字串

{
  "kind": "List",
  "items":[
    {
      "kind":"None",
      "metadata":{"name":"127.0.0.1"},
      "status":{
        "capacity":{"cpu":"4"},
        "addresses":[{"type": "LegacyHostIP", "address":"127.0.0.1"}]
      }
    },
    {
      "kind":"None",
      "metadata":{"name":"127.0.0.2"},
      "status":{
        "capacity":{"cpu":"8"},
        "addresses":[
          {"type": "LegacyHostIP", "address":"127.0.0.2"},
          {"type": "another", "address":"127.0.0.3"}
        ]
      }
    }
  ],
  "users":[
    {
      "name": "myself",
      "user": {}
    },
    {
      "name": "e2e",
      "user": {"username": "admin", "password": "secret"}
    }
  ]
}
Function Description Example Result
text the plain text kind is {.kind} kind is List
@ the current object {@} the same as input
. or [] child operator {.kind} or {[‘kind’]} List
.. recursive descent {..name} 127.0.0.1 127.0.0.2 myself e2e
* wildcard. Get all objects {.items[*].metadata.name} [127.0.0.1 127.0.0.2]
[start:end :step] subscript operator {.users[0].name} myself
[,] union operator {.items[*][‘metadata.name’, ‘status.capacity’]} 127.0.0.1 127.0.0.2 map[cpu:4] map[cpu:8]
?() filter {.users[?(@.name==“e2e”)].user.password} secret
range, end iterate list {range .items[*]}[{.metadata.name}, {.status.capacity}] {end} [127.0.0.1, map[cpu:4]] [127.0.0.2, map[cpu:8]]
quote interpreted string {range .items[*]}{.metadata.name}{’\t’}{end} 127.0.0.1 127.0.0.2

使用jsonpath示例

kubectl get pods -o json
kubectl get pods -o=jsonpath='{@}'
kubectl get pods -o=jsonpath='{.items[0]}'
kubectl get pods -o=jsonpath='{.items[0].metadata.name}'
kubectl get pods -o=jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.startTime}{"\n"}{end}'

如果物件是集合型別,需要使用range關鍵字開始,以end關鍵字結果,同前面一節go-template類似.

我們通過以下示例來看如何通過jsonpath簡單地獲取到容器所在節點名稱

[centos@k8s-master ~]$ kubectl get po consul-0 -ojsonpath='{..nodeName}'
k8s-node1
[centos@k8s-master ~]$

當然以上也可以通過grep來獲取到同樣的資訊,並且對於很多熟悉linux命令的童鞋來說更為方便,如果僅僅是檢視.grep確實更為方便,但是通過jsonpath是準確地獲取到了一個屬性的值,而grep則是擷取的包含這個關鍵字的一行,如果我們要把獲取的值作為下一個命令的的輸入值時,通過grep獲取的結果往往是需要處理的.例如通過grep獲取到的結果如下

"k8s-node1",[centos@k8s-master ~]$ kubectl get po consul-0 -ojson|grep nodeName
        "nodeName": "k8s-node1",

這裡想要準備的獲取結果,產生要擷取第二列值,然後再去掉引號,操作起來不如jsonpath方便.尤其在不同環境如果輸出的格式不一樣的話,通過字串擷取得到的結果可能是錯誤的.

相關文章