【Kubernetes】Strategic Merge Patchについてざっくり理解する

2023.01.28
2024.03.24
Kubernetes

はじめに

Kubernetesで使われるStrategic Merge Patchについて、ざっくり理解していきます。

また、Strategic Merge Patchで使われる命令文の中からKustomizeでサポートされているものを紹介します。

Strategic Merge Patchとは

Strategic Merge PatchはKubernetesで使われているJSON merege patchをカスタマイズしたパッチ方法です。

JSON Merge Patchの場合、JSON Objectは全てマージされ、リストは全て置換されるようになっています。しかし、Kubernetesだと都合が悪い場合があるので、Strategic Merge Patchでは、Kubernetesのオブジェクトがいい感じにマージされるように制御されています。

このパッチ方法は、kubectl applykubectl editkubectl patchで使われており、専用の命令文(directive)があり、どのようにマージするかを制御することもできます。

community/contributors/devel/sig-api-machinery/strategic-merge-patch.md at main · kubernetes/community

community/contributors/devel/sig-api-machinery/strategic-merge-patch.md at main · kubernetes/community

Kubernetes community content. Contribute to kubernetes/community development by creating an account on GitHub.

また、このパッチ方法はKustomizeでもサポートされており、一部の命令文(パッチフォーマット)はKustomizeのパッチファイルの中でも利用することができます。

patchesStrategicMerge

Patch resources using the strategic merge patch standard.

Server Side Apply

先ほど載せたページに記載されているように、Strategic Merge Patchを使うClient-side Applyに代わって、現在ではServer-side Applyが新しい方法として推奨されています。

また、下記の記事では、"Old patch format"とStrategic Merge Patchが呼ばれており、いくつかバグもあるみたいです。

Server Side Apply Is Great And You Should Be Using It

Server-side apply (SSA) has now been GA for a few releases, and I have found myself in a number of conversations, recommending that people / teams in various situations use it. So I’d like to write down some of those reasons. Obvious (and not-so-obvious) benefits of SSA A list of improvements / niceties you get from switching from various things to Server-side apply! Versus client-side-apply (that is, plain kubectl apply): The system gives you conflicts when you accidentally fight with another actor over the value of a field! When combined with --dry-run, there’s no chance of accidentally running a client-side dry run instead of a server side dry run. Versus hand-rolling patches: The SSA patch format is extremely natural to write, with no weird syntax. It’s just a regular object, but you can (and should) omit any field you don’t care about. The old patch format (“strategic merge patch”) was ad-hoc and still has some bugs; JSON-patch and JSON merge-patch fail to handle some cases that are common in the Kubernetes API, namely lists with items that should be recursively merged based on a “name” or other identifying field. There’s also now great go-language library support for building apply calls programmatically! You can use SSA to explicitly delete fields you don’t “own” by setting them to null, which makes it a feature-complete replacement for all of the old patch formats. Versus shelling out to kubectl: You can use the apply API call from any language without shelling out to kubectl! As stated above, the Go library has dedicated mechanisms to make this easy now. Versus GET-modify-PUT: (This one is more complicated and you can skip it if you've never written a controller!) To use GET-modify-PUT correctly, you have to handle and retry a write failure in the case that someone else has modified the object in any way between your GET and PUT. This is an “optimistic concurrency failure” when it happens. SSA offloads this task to the server– you only have to retry if there’s a conflict, and the conflicts you can get are all meaningful, like when you’re actually trying to take a field away from another actor in the system. To put it another way, if 10 actors do a GET-modify-PUT cycle at the same time, 9 will get an optimistic concurrency failure and have to retry, then 8, etc, for up to 50 total GET-PUT attempts in the worst case (that’s .5N^2 GET and PUT calls for N actors making simultaneous changes). If the actors are using SSA instead, and the changes don’t actually conflict over specific fields, then all the changes can go in in any order. Additionally, SSA changes can often be done without a GET call at all. That’s only N apply requests for N actors, which is a drastic improvement! How can I use SSA? Users Use kubectl apply --server-side! Soon we (SIG API Machinery) hope to make this the default and remove the “client side” apply completely!

Kustomizeが対応しているパッチフォーマット

Server-side Applyが新しい方法として推奨されているので、Kustomizeでサポートされているパッチフォーマットを紹介します。

Kustomizeがサポートしているフォーマットは下記の通りです。

  • replace
  • delete
  • merge

具体的にKustomizeがサポートしているフォーマットが書かれているドキュメントは見つかりませんでしたが、下記のIssueとコードを見た感じだと、replacedeletemergeだと思います。

kyaml is not respecting `$patch replace|retainKeys` directives · Issue #2037 · kubernetes-sigs/kustomize

kyaml is not respecting `$patch replace|retainKeys` directives · Issue #2037 · kubernetes-sigs/kustomize

tree: . ├── base │ ├── kafka.yaml │ └── kustomization.yaml └── overlays ├── kustomization.yaml ├── output.yaml └── patch.yaml base content: # kustomization.yaml resources: - kafka.yaml # kafka.yaml...

kustomize/kyaml/yaml/merge2/smpdirective.go at master · kubernetes-sigs/kustomize

kustomize/kyaml/yaml/merge2/smpdirective.go at master · kubernetes-sigs/kustomize

Customization of kubernetes YAML configurations. Contribute to kubernetes-sigs/kustomize development by creating an account on GitHub.

しかし、merge Directiveに書かれているとおり、mergeに関してはパッチファイルで使われるフォーマットではなさそうです。(実際に試してみましたが、挙動が変わるパターンが見つからなかったので、今回は紹介しないことにします)

replace

replaceは、その名の通り要素をマージする代わりに置き換えます。

1$patch: replace

試してみる

Kustomizeを使って試してみます。

用意するファイル(kustomization.yaml, deployment.yaml, replace.yaml)は下記の通りです。

1apiVersion: kustomize.config.k8s.io/v1beta1
2kind: Kustomization
3
4resources:
5- deployment.yaml
6
7patchesStrategicMerge:
8- replace.yaml
1apiVersion: apps/v1
2kind: Deployment
3metadata:
4  name: myapp
5spec:
6  replicas: 1
7  selector:
8    matchLabels:
9      app: myapp
10  template:
11    metadata:
12      labels:
13        app: myapp
14        ver: 1.0.0
15    spec:
16      containers:
17      - name: nginx
18        image: nginx:latest
19      - name: redis
20        image: redis:latest
1apiVersion: apps/v1
2kind: Deployment
3metadata:
4  name: myapp
5spec:
6  template:
7    metadata:
8      $patch: replace # 下の階層が置換対象
9      labels:
10        app: myapp
11        ver: 2.0.0
12    spec:
13      containers:
14      - name: busybox
15        image: busybox:latest
16      - $patch: replace # リストが置換対象

ビルドしてみます。

1kustomize build
1apiVersion: apps/v1
2kind: Deployment
3metadata:
4  name: myapp
5spec:
6  replicas: 1
7  selector:
8    matchLabels:
9      app: myapp
10  template:
11    metadata:
12      labels: # labelsの中の要素が置換
13        app: myapp
14        ver: 2.0.0
15    spec:
16      containers:
17      - image: busybox:latest # リストが置換
18        name: busybox

delete

deleteは要素の削除をします。

1$patch: delete

試してみる

Kustomizeを使って試してみます。

用意するファイル(kustomization.yaml, deployment.yaml, delete.yaml)は下記の通りです。

1apiVersion: kustomize.config.k8s.io/v1beta1
2kind: Kustomization
3
4resources:
5- deployment.yaml
6
7patchesStrategicMerge:
8- delete.yaml
1apiVersion: apps/v1
2kind: Deployment
3metadata:
4  name: myapp
5spec:
6  strategy:
7    type: Recreat
8  replicas: 1
9  selector:
10    matchLabels:
11      app: myapp
12  template:
13    metadata:
14      labels:
15        app: myapp
16    spec:
17      containers:
18      - name: nginx
19        image: nginx:latest
20      - name: redis
21        image: redis:latest
1apiVersion: apps/v1
2kind: Deployment
3metadata:
4  name: myapp
5spec:
6  strategy:
7    $patch: delete # strategyを削除
8  template:
9    spec:
10      containers:
11      - name: busybox
12        image: busybox:latest
13      - $patch: delete # nginxコンテナを削除
14        name: nginx

ビルドしてみます。

1kustomize build
1apiVersion: apps/v1
2kind: Deployment
3metadata:
4  name: myapp
5spec:
6  # strategyが削除されている
7  replicas: 1
8  selector:
9    matchLabels:
10      app: myapp
11  template:
12    metadata:
13      labels:
14        app: myapp
15    spec:
16      containers:
17      # nginxコンテナが削除され、busyboxコンテナがマージ
18      - image: busybox:latest
19        name: busybox
20      - image: redis:latest
21        name: redis

最後に

Strategic Merge Patchに関しては、ドキュメントがあまり見当たらなかったため、もし謝っている箇所があれば教えていただけるとうれしいです。

参考

Support

\ この記事が役に立ったと思ったら、サポートお願いします! /

buy me a coffee
Share

Profile

author

Masa

都内のIT企業で働くエンジニア
自分が学んだことをブログでわかりやすく発信していきながらスキルアップを目指していきます!

buy me a coffee