🗂

単一ファイルにある複数YAMLドキュメントのうち、1つをyqで抽出する

2022/12/10に公開約3,600字

概要

kustomize buildの出力など、単一ファイルに複数のYAMLドキュメントが記述されていることがあります。そのYAMLドキュメントの1つを抽出したい場合、yqを利用できます。

以下のexample.yamlを例として、コマンドと実行結果を紹介します。

example.yaml
foo: bar
---
hoge: fuga
$ yq '(select(documentIndex == 0) | .)' example.yaml
foo: bar

$ yq '(select(documentIndex == 1) | .)' example.yaml
hoge: fuga

環境

筆者は macOS Monterey 12.6.1(Apple M1)を使用しています。
yqのバージョンはこちらです。

$ yq --version
yq (https://github.com/mikefarah/yq/) version v4.30.5

目的

@hhiroshellさんに語り尽くされていました。
KustomizeのHash Suffixがあってもいい感じにdiffが見られるkubectlプラグインを作った話

筆者はkubectlを素のまま使わない環境を利用しています。kubectl diff相当のコマンドを利用できない、また、kubectl pluginで解決できないため、別のアプローチを取りました[1]

まず、変更前のマニフェストを適用します。

https://github.com/oke-py/zenn-sample-dd1cd79fb94965/blob/804e9b7e99bba31903b7142b3668185da45a7a9f/before/app.yaml

kubectl apply -f before/app.yaml

ConfigMapGeneratorに指定する値を編集し、kustomize buildします。ここでは、サンプルリポジトリのわかりやすさを考慮し、ファイル一式をbeforeafterディレクトリに配置しています。

after/app.yamlを適用する前に、差分を確認します。

diff -upN <(kubectl apply -f after/app.yaml view-last-applied) after/app.yaml

出力結果は以下のとおりです。1行目はstderrに出力されます。
ConfigMapの名前が変更されており、期待した結果を得られません。

Error from server (NotFound): configmaps "example-configmap-1-286h7kfc5k" not found
--- /dev/fd/11  2022-12-10 12:13:10.000000000 +0900
+++ after/app.yaml      2022-12-10 11:51:08.000000000 +0900
@@ -0,0 +1,27 @@
+apiVersion: v1
+data:
+  FOO: baz
+kind: ConfigMap
+metadata:
+  annotations:
+    app: example
+  name: example-configmap-1-286h7kfc5k
+  namespace: default
+---
+apiVersion: v1
+kind: Pod
+metadata:
+  annotations:
+    app: example
+  name: example
+  namespace: default
+spec:
+  containers:
+  - env:
+    - name: FOO
+      valueFrom:
+        configMapKeyRef:
+          key: FOO
+          name: example-configmap-1-286h7kfc5k
+    image: nginx
+    name: nginx

解決策として1つずつ比較することを思いつきました。ここで、概要で紹介したコマンドを利用します。

Podの差分を確認する

コマンド
diff -upN \
  <(kubectl get pod example -o yaml | yq '.metadata.annotations.["kubectl.kubernetes.io/last-applied-configuration"]' | jq | yq -P .) \
  <(yq '(select(documentIndex == 1) | .)' after/app.yaml)
実行結果
--- /dev/fd/11  2022-12-10 12:04:25.000000000 +0900
+++ /dev/fd/14  2022-12-10 12:04:25.000000000 +0900
@@ -12,6 +12,6 @@ spec:
           valueFrom:
             configMapKeyRef:
               key: FOO
-              name: example-configmap-1-59m54fbgh2
+              name: example-configmap-1-286h7kfc5k
       image: nginx
       name: nginx

ConfigMapの差分を確認する

コマンド
CONFIGMAP=$(kubectl get pod example -o jsonpath='{.spec.containers[?(@.name=="nginx")].env[0].valueFrom.configMapKeyRef.name}')
diff -upN \
  <(kubectl get cm $CONFIGMAP -o yaml | yq '.metadata.annotations.["kubectl.kubernetes.io/last-applied-configuration"]' | jq | yq -P .) \
  <(yq '(select(documentIndex == 0) | .)' after/app.yaml)
実行結果
--- /dev/fd/11  2022-12-10 12:10:14.000000000 +0900
+++ /dev/fd/14  2022-12-10 12:10:14.000000000 +0900
@@ -1,9 +1,9 @@
 apiVersion: v1
 data:
-  FOO: bar
+  FOO: baz
 kind: ConfigMap
 metadata:
   annotations:
     app: example
-  name: example-configmap-1-59m54fbgh2
+  name: example-configmap-1-286h7kfc5k
   namespace: default

おわりに

yqを利用してkustomize buildの出力から得たい情報を抽出できました。考案したdiffコマンドは柔軟性に欠けますが、私のユースケースでは十分なものとなりました。

参考

本記事で紹介したコマンドは、こちらのIssueに記載されています。
https://github.com/mikefarah/yq/issues/9

脚注
  1. 正確には、紹介したアプローチを試した後で@hhiroshellさんの発表、プラグインを知りました。 ↩︎

GitHubで編集を提案

Discussion

ログインするとコメントできます