Kekeの日記

エンジニア、読書なんでも

JsonPathを変幻自在に操るKubernetes使いになろう

JSONPathとは

何かしらCLIツールでコマンドを実行した時にフォーマットをするようなものである。

たとえば以下のように実行する

kubectl get pods -o json

すると生のJSONが返ってくるので、このjsonにpathを指定することになる。

これに対してjsonpathを指定することによって効率のよく必要な情報が集められたりする。

以下のようにすると、キレイに取得をすることができます。

kubectl get pods hogehoge pod -o json | jq .

JSONPathの使い方

注意点

全体は''で囲んで、中では""を使うことに注意をしてください。

使える項目

1. Child Operator

子要素を取得するものである

以下のように直接指定する。

kubectl get nodes -o=jsonpath="{.kind}"

=> List

kubectl get nodes -o=jsonpath="{.metadata}"

=> map[selfLink: resourceVersion:]

2. Recursive descent

再帰的に合致するものも抽出するものである。

kubectl get nodes -o=jsonpath="{..name}"

=> gke-locust-cluster-default-pool-8eb6b5df-9hjh gke-locust-cluster-default-pool-8eb6b5df-ctb5

この場合だと

{
     name: hoge
     kind: {
          name: piyo
      }
}

の場合は

hoge piyo

と返ってきます。

3. Wild card

すべてのオブジェクトを取得するものです。

kubectl get nodes -o=jsonpath="{.items[*].name}"

これをしない場合、つまり以下のように*を取り除くと

kubectl get nodes -o=jsonpath="{.items[].name}"

最初の一つだけマッチして終了してしまうので注意が必要です。

4. Current Object

以下のFilterのSectionでもあるが、@でそのレベルでのオブジェクトを取得できます。

kubectl get nodes -o=jsonpath="{@}"

ここでは@に対応するのはルートオブジェクトです。

5. Filter

条件にかけて抽出するものです。

[]で挟んで?を前において()の中に条件を入れます。。Go templateで構成されているので、わからなければGo templateを参照するのがいいでしょう。

kubectl get nodes -o=jsonpath="{.users[?(@.name==“e2e”)].user.password}"

条件が真となるときのみ、ここでいう.usersは取得されます。

6. Range

以下のように特定のArrayを持つようなオブジェクトに対してfor文を行います。{end}も忘れないでください。

kubectl get nodes -o=jsonpath="{range .items[*]}[{.metadata.name}, {.status.capacity}] {end}"

7. Union

,で配列などを定義できます。もちろんオブジェクトも可能です。

kubectl get nodes -o=jsonpath="{range .items[*]}[{.metadata.name}, {.status.capacity}] {end}"

ユースケース

特定のNodeをDrainする

公式ページにもあった使い道です。

一般的には

  1. Node名を確認する
kubectl get nodes
  1. ひとつひとつDrainする
kubectl drain --force --ignore-daemonsets --delete-local-data --grace-period=10 [NODE1]
kubectl drain --force --ignore-daemonsets --delete-local-data --grace-period=10 [NODE2]
kubectl drain --force --ignore-daemonsets --delete-local-data --grace-period=10 [NODE3]
....

これをjsonpathを使うと

for node in $(kubectl get nodes -l cloud.google.com/gke-nodepool=default-pool -o=name); do
  kubectl drain --force --ignore-daemonsets --delete-local-data --grace-period=10 "$node";
done

このようにすることでNode名を知らなくても一気にdrainすることができます。ここで-lを指定しているのはラベルを使うためです。

Evictedになったものだけ消す

以下のようにEvictedしていた結果、悲惨なことになっている状況を考えましょう。

spin-front50-8659899b76-v44rv        0/1     Evicted     0          3h42m
spin-front50-8659899b76-v4ssm        0/1     Evicted     0          4h8m
spin-front50-8659899b76-v4vpc        0/1     Evicted     0          154m
spin-front50-8659899b76-vbhss        0/1     Evicted     0          141m
spin-front50-8659899b76-vbr4l        0/1     Evicted     0          3h14m
spin-front50-8659899b76-vpq62        0/1     Evicted     0          3h55m
spin-front50-8659899b76-w5w2c        0/1     Evicted     0          4h8m
...
spin-front50-8659899b76-w94rm        1/1     Running     1          20m
spin-front50-8659899b76-z8lht        0/1     Evicted     0          19m
spin-front50-8659899b76-zbv64        0/1     Evicted     0          166m
spin-front50-8659899b76-zcfpz        0/1     Evicted     0          43m
spin-front50-8659899b76-zffwd        0/1     Evicted     0          3h55m
spin-front50-8659899b76-zgtj9        0/1     Evicted     0          117m
spin-front50-8659899b76-zqsrc        0/1     Evicted     0          19m

一つだけRunningになったので他が必要ないです。

以下のコマンドで消します。

for evictedPod in (kubectl get pods -l cluster=spin-front50 -o=jsonpath="{.items[?(@.status.reason=='Evicted')].metadata.name}" | tr " " "\n")
    kubectl delete pods $evictedPod
end

付録

1. get podsは一つのオブジェクトである

以下のようにitemsにPodが入るため、すべてを取り出すにはrangeを使うべきです。

{
   "items": {
       Pod情報
    }
}

参考文献

kubernetes.io