【Kustomize】patchesJson6902の使い方と利用シーン

Kustomizeを使うとき、 patches でファイルを指定してbaseファイルを部分的に変更することが多いと思う。しかし先日、 patches ではなく patchesJson6902 という指定をしているファイルを見かけたので、どう使うのか調べてみた。

patchesJson6902とは

patchesJson6902は、名前の通りRFC6902に沿った方法でPatch処理を行うことができる。RFC6902ではJSON Patchについて定義されている。

tools.ietf.org

Kustomizeは公式ドキュメントをたどりづらいが、Kubernetesのドキュメントの中に詳しい使い方が記載されている。 kubernetes.io

patchesStrategicMergepatchesJson6902 の違い

Kustomizeでは、patchを行う際に patchesStrategicMergepatchesJson6902 の2つの方式に対応している。 patch フィールドは渡したファイルまたはPatchをもとに、どちらの方式かを自動で判定して適用してくれる。
この2つの方式がどう違うのかというと、 patchesStrategicMerge はマージの挙動をKubernetesの設定ファイルに最適化されるように変更している。例えば、以下のようなdeployment.yamlがあるとする。

# base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.1
        ports:
        - containerPort: 80
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80
      - name: nginx
        image: nginx:1.14.3
        ports:
        - containerPort: 80

# base/kustomization.yaml
resources:
  - deployment.yaml

overlaysを以下のようにする。

# overlays/test/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  template:
    spec:
      containers:
        - name: busybox
          image: busybox:1.33
          ports:
            - containerPort: 80

# overlays/test/kustomization.yaml
bases:
  - ../../base

patchesStrategicMerge:
  - deployment.yaml

このとき、buildした結果は以下のようになる。overlaysで指定したコンテナが、 containers に追加されていることがわかる。

$ kustomize build . 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: busybox:1.33
        name: busybox
        ports:
        - containerPort: 80
      - image: nginx:1.14.1
        name: nginx
        ports:
        - containerPort: 80
      - image: nginx:1.14.2
        name: nginx
        ports:
        - containerPort: 80
      - image: nginx:1.14.3
        name: nginx
        ports:
        - containerPort: 80

一方で、これと同じことを patchesJson6902 で行おうとすると、overlaysを以下のようにしなければならない。

# overlays/test/kustomization.yaml
bases:
  - ../../base

patchesJson6902:
  - target:
      group: apps
      version: v1
      kind: Deployment
      name: nginx-deployment
    patch: |- # patchの内容は別ファイルに指定しても良い
      - op: add
        path: /spec/template/spec/containers/0
        value: {"image": "busibox:1.33", "name": "busybox", "ports": [{"containerPort": 80}]}

patch 内の pathJSON pathを指定する必要があり、ここで配列のインデックス番号を指定したうえで、配列に入れる新たな要素を定義する必要がある。 patchesStrategicMerge の場合と同じようにしてしまうと、 containers が丸々入れ替わって busybox のみになってしまう。

patchesJson6902 を使うべきシーン

逆に「配列の中の特定の一要素を入れ替えたい場合」は patchesJson6902 の方を使うべき。

# overlays/test/kustomization.yaml
bases:
  - ../../base

patchesJson6902:
  - target:
      group: apps
      version: v1
      kind: Deployment
      name: nginx-deployment
    patch: |-
      - op: replace
        path: /spec/template/spec/containers/0
        value: {"image": "busibox:1.33", "name": "busybox", "ports": [{"containerPort": 80}]}

opreplace に変更したことで、 containers 配列の0番目の要素のみを入れ替えることができる。結果は以下の通り。

$ kustomize build .  
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: busibox:1.33
        name: busybox
        ports:
        - containerPort: 80
      - image: nginx:1.14.2
        name: nginx
        ports:
        - containerPort: 80
      - image: nginx:1.14.3
        name: nginx
        ports:
        - containerPort: 80

これに対して patchesStrategicMerge の場合、 $patch: replace を指定することで containers 配列全体を入れ替えることはできるが、特定の要素を指定してそこだけ入れ替える機能はない。baseの containers 配列全体をoverlaysに書いてそこに新しい要素を加えるという方法はあるが、配列の要素が多い場合は非効率である。

各Patch方式の詳細な挙動は、以下が参考になる。

community/strategic-merge-patch.md at master · kubernetes/community · GitHub kustomize/inlinePatch.md at master · kubernetes-sigs/kustomize · GitHub