yq は YAML を操作できるコマンドラインツールで、Kubernetes 用のマニフェストの確認やクラスタの状態確認に利用できます。 この記事では yq の基本的な使い方と Kubernetes 環境での応用方法を紹介します。

基本的な使い方

yq eval に続けて評価式を書くことで YAML の一部を表示したり編集したりすることができます。

$ yq eval [expression] [yaml_file] [flags]

eval コマンドは e と書くこともできます。

yq は構文を色付けするので、次のように書くと kubectl の出力を色付けできます。

$ kubectl get pod sample -o yaml | yq e . -

値の表示と配列アクセス

評価式にフィールド名を指定すると、そのフィールドだけを抜き出して表示できます。
Kubernetes リソースの .spec フィールドだけを表示する、といった使い方ができます。

alpine.yaml

apiVersion: v1
kind: Pod
metadata:
  name: alpine
spec:
  containers:
    - command:
        - sleep
        - inf
      image: alpine:3.13.3
      name: alpine
$ yq e .spec alpine.yaml 
containers:
  - command:
      - sleep
      - inf
    image: alpine:3.13.3
    name: alpine

$ yq e .spec.containers[0].name alpine.yaml
alpine

パイプとフィルタ

評価式はパイプ | で連結できます。

$ yq e '.spec.containers | .[0] | .image' alpine.yaml 
alpine:3.13.3

[] を使うと配列の全ての要素に対して後続の処理を実行します。

$ # kind 環境を起動する
$ kind create cluster

$ kubectl get pod -n kube-system -o yaml | yq e '.items[].metadata.name' -
coredns-f9fd979d6-brw2g
coredns-f9fd979d6-mg9vv
etcd-kind-control-plane
kindnet-m4zzj
kube-apiserver-kind-control-plane
kube-controller-manager-kind-control-plane
kube-proxy-bnd47
kube-scheduler-kind-control-plane

select を使うと条件を満たす要素を取り出せます。

$ kubectl get pod -n kube-system -o yaml | yq e '.items[].metadata.name | select(.=="kube*")' -
kube-apiserver-kind-control-plane
kube-controller-manager-kind-control-plane
kube-proxy-bnd47
kube-scheduler-kind-control-plane

便利なコマンド

Kubernetes クラスタの管理に使える便利なコマンドをまとめました。

特定の種類のリソースだけを表示する

複雑な YAML ファイルに含まれる特定の種類のリソースだけを表示できます。

$ yq e 'select(.kind=="Deployment")' manifest.yaml 

一部のフィールドを除いて表示する

CRD を含む大きな YAML ファイルの概略を掴むのに便利です。

$ yq e 'del(.spec)' manifest.yaml

YAML の内容をソートする

YAML の差分を効率的に確認できます。

$ yq e 'sortKeys(..)' manifest.yaml

ラベルやアノテーションのキー一覧を表示する

$ kubectl get pod -n kube-system kube-apiserver-kind-control-plane -o yaml | yq e '.metadata.labels | keys | .[]' -
component
tier

ラベルやアノテーションの値を表示する

$ kubectl get pod -n kube-system kube-apiserver-kind-control-plane -o yaml | yq e '.metadata.labels["component"]' -
kube-apiserver

Pod に付いているラベルをすべて表示する

$ kubectl get pod -A -o yaml | yq e '.items[].metadata | . as $i ireduce({}; . * {$i.namespace: {$i.name: $i.labels}})' -
kube-system:
  coredns-f9fd979d6-brw2g:
    k8s-app: kube-dns
    pod-template-hash: f9fd979d6
  coredns-f9fd979d6-mg9vv:
    k8s-app: kube-dns
    pod-template-hash: f9fd979d6
  etcd-kind-control-plane:
    component: etcd
    tier: control-plane
  kindnet-m4zzj:
    app: kindnet
    controller-revision-hash: 869899dbb6
    k8s-app: kindnet
    pod-template-generation: "1"
    tier: node
  kube-apiserver-kind-control-plane:
    component: kube-apiserver
    tier: control-plane
  kube-controller-manager-kind-control-plane:
    component: kube-controller-manager
    tier: control-plane
  kube-proxy-bnd47:
    controller-revision-hash: 6fbb4864f
    k8s-app: kube-proxy
    pod-template-generation: "1"
  kube-scheduler-kind-control-plane:
    component: kube-scheduler
    tier: control-plane
local-path-storage:
  local-path-provisioner-78776bfc44-bmtw9:
    app: local-path-provisioner
    pod-template-hash: 78776bfc44

ireduce を使うと aggregation が書けます。

$ echo '[1, 2, 3]' | yq e '.[] as $i ireduce(0; . + $i)' -
6

特定の User や ServiceAccount に紐付いた RoleBinding を一覧表示する

$ kubectl get rolebinding -n kube-system -o yaml | yq e '.items[] | select(.subjects[] as $i ireduce(false; . or ($i.kind=="User" and $i.name=="system:kube-controller-manager"))) | .metadata.name' -
system::extension-apiserver-authentication-reader
system::leader-locking-kube-controller-manager

マニアックすぎですがこれは次のコマンドの応用です。

$ echo '[true, false]' | yq e 'select(.[] as $i ireduce(false; . or $i))' -
[true, false]
$ echo '[false, false]' | yq e 'select(.[] as $i ireduce(false; . or $i))' -
$

特定の User や ServiceAccount に紐付いた ClusterRoleBinding を一覧表示する

$ kubectl get clusterrolebinding -o yaml | yq e '.items[] | select(.subjects[] as $i ireduce(false; . or ($i.kind=="User" and $i.name=="system:kube-scheduler"))) | .metadata.name' -
system:kube-scheduler
system:volume-scheduler

roleRef を参照して ClusterRole を直接表示することもできます。

$ kubectl get clusterrolebinding -o yaml | yq e '.items[] | select(.subjects[] as $i ireduce(false; . or ($i.kind=="User" and $i.name=="system:kube-scheduler"))) | .roleRef.name' - | sort | uniq
system:kube-scheduler
system:volume-scheduler

全クラスタリソースと全 namespace リソースを表示する

本番環境でやると大変なことになりそう。 小規模なテスト環境で実行すると色々勉強になります。

$ kubectl get $(kubectl api-resources -o name | paste -sd ,) -A -o yaml 2>/dev/null | yq e '.items[] | . as $i ireduce({}; . *+ {$i.metadata.namespace: {$i.kind: [$i.metadata.name]}})' -

APIGroup/Version 付き

$ kubectl get $(kubectl api-resources -o name | paste -sd ,) -A -o yaml 2>/dev/null | yq e '.items[] | . as $i ireduce({}; . *+ {$i.metadata.namespace: {$i.apiVersion: {$i.kind: [$i.metadata.name]}}})' -

特定の namespace の全リソースを表示する

$ kubectl get $(kubectl api-resources --namespaced -o name | paste -sd ,) -n kube-system -o yaml 2>/dev/null | yq e '.items[] | . as $i ireduce({}; . *+ {$i.kind: [$i.metadata.name]})' -

APIGroup/Version 付き

$ kubectl get $(kubectl api-resources --namespaced -o name | paste -sd ,) -n kube-system -o yaml 2>/dev/null | yq e '.items[] | . as $i ireduce({}; . *+ {$i.apiVersion: {$i.kind: [$i.metadata.name]}})' -

複数ドキュメントの操作

YAML ファイルの複数ドキュメントを配列にする

$ echo -e "dog\n---\ncat" | yq ea '. as $i ireduce ([]; . + $i)' -
- dog
- cat

eaeval-all の略で、ファイルに含まれる YAML ドキュメントをまとめて読み込みます。

YAML ファイルに含まれるドキュメントの数を数える

$ echo -e "dog\n---\ncat" | yq ea '. as $i ireduce ([]; . + $i) | length' -
2

配列を複数のドキュメントに分割する

$ echo '["dog", "cat"]' | yq e '.[] | splitDoc' -
echo '["dog", "cat"]' | yq e '.[] | splitDoc' -
dog
---
cat

jsonnet でリソースの配列を作り、yq でリソースごとのドキュメントに分割して YAML を出力する、というようなこともできます。

YAML と JSON の相互変換

yq コマンドは JSON を直接読み込めます。 -P オプションを付けると YAML に整形して出力します。

$ echo '{"kind": "dog"}' | yq e . - -P
kind: dog

-j オプションを使うと読み込んだ YAML を JSON に変換します。

$ yq e . sample.yaml -j
{
  "animal": {
    "type": "word",
    "members": [
      "dog",
      "cat"
    ]
  }
}

yq でマニフェストを JSON に変換し、jq のコマンドを使う

yq には printf 関数がありませんが、jq と組み合わせて使うことができます。

$ yq e . manifest.yaml -j | jq -r '"\(.kind): \(.metadata.namespace)/\(.metadata.name)"'
Pod: default/sample

jq で処理した結果を YAML に変換する

JSON を jq のフィルタで処理し、結果を YAML で確認できます。

$ kubectl get pod alpine -o json | jq .spec | yq e . - -P

その他のコマンド

yq には他にも色々なコマンドがあります。 詳細は公式マニュアルの Operators をご確認ください。

参考資料