kustomize JSON Patch(JSON 补丁)完全指南:用 RFC 6902 精准改造 Ingress 等任意资源
2026/9/23 12:43:55 网站建设 项目流程

kustomize JSON Patch(JSON 补丁)完全指南:用 RFC 6902 精准改造 Ingress 等任意资源

【免费下载链接】kustomizeCustomization of kubernetes YAML configurations项目地址: https://gitcode.com/gh_mirrors/ku/kustomize

JSON Patch(RFC 6902 的完整演示为主线,结合仓库源码讲解 patch 的语法、target 定位机制、JSON/YAML 两种写法,以及它与其他 patch 方式的取舍,读完你可以立刻在自己的 kustomization 项目中落地这套打补丁方案。

一、JSON Patch 是什么,kustomize 为什么要支持它

kustomize 的职责是「Customization of kubernetes YAML configurations」——在不改原始资源的前提下,通过叠加规则生成最终 YAML。修改资源的方式有很多种,JSON Patch 是其中语法最精确、最贴近标准的一种:

  • Strategic Merge Patch(SMP):把想修改的字段局部重写一份,kustomize 按 Kubernetes 特有规则与原资源合并(详见 patchstrategicmerge 过滤器)。它擅长「改字段」,但在「往列表中间插一项」「按精确路径改一个值」等场景下不够直观。
  • JSON Patch:由一组显式的操作指令组成,每条指令形如{"op": "replace", "path": "/spec/rules/0/host", "value": "foo.bar.io"},操作对象、路径、新值一目了然,完全遵循 RFC 6902 标准。

kustomize 的 JSON Patch 支持体现在两个层面:

  1. 字段层面kustomization.yaml中声明patches(新推荐)或patchesJson6902(已弃用,见 kustomization.go),每个 patch 带一个target选择器;
  2. 实现层面:内置插件 PatchJson6902Transformer 与底层过滤器 patchjson6902.Filter 负责解析和应用。

二、完整演示:用 JSON Patch 改造一个 Ingress

下面完整复现 examples/jsonpatch.md 的官方演示:先造一个包含三个路由路径的 Ingress,再用一个 JSON Patch 文件同时完成「改值 × 2 + 指定位置插入 × 1」。

2.1 准备资源文件

建一个临时工作目录,写入 Ingress:

DEMO_HOME=$(mktemp -d)
cat <<EOF >$DEMO_HOME/ingress.yaml apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: my-ingress spec: rules: - host: foo.bar.com http: paths: - path: / backend: serviceName: homepage servicePort: 8888 - path: /api backend: serviceName: my-api servicePort: 7701 - path: /test backend: serviceName: hello servicePort: 7702 EOF

注意:示例资源使用的是networking.k8s.io/v1beta1版本的 Ingress,这是该演示文档编写时的 API 版本,当前 Kubernetes 已演进到networking.k8s.io/v1,实际使用时请把apiVersiontarget中的version同步替换为你集群支持的版本。

2.2 定义三项目标修改

我们要做的修改是:

  1. host的值从foo.bar.com改为foo.bar.io
  2. '/'路径的servicePort8888改为80
  3. paths列表的指定位置/test之前)插入一条全新的/healthz服务路径,而不是追加到列表末尾或开头。

第三条正是 JSON Patch 相对普通字段覆盖的差异化优势:路径定位用数组下标(/paths/1)精确控制插入点。

2.3 编写 JSON Patch 文件

cat <<EOF >$DEMO_HOME/ingress_patch.json [ {"op": "replace", "path": "/spec/rules/0/host", "value": "foo.bar.io"}, {"op": "replace", "path": "/spec/rules/0/http/paths/0/backend/servicePort", "value": 80}, {"op": "add", "path": "/spec/rules/0/http/paths/1", "value": { "path": "/healthz", "backend": {"servicePort":7700} }} ] EOF

该文件是一个 JSON 数组,数组中每个元素是一条 RFC 6902 操作指令:

字段含义本例取值
op操作类型:add/remove/replace/move/copy/testreplaceadd
path用 JSON Pointer 语法(/分隔,数组用数字下标)定位目标字段/spec/rules/0/host
value操作涉及的数值/对象"foo.bar.io"80{...}

add在数组路径上的语义是「在指定下标处插入」,因此"/spec/rules/0/http/paths/1"会把新路径插到原下标 1(即/api路径)之前,其余元素自动后移。关于 add 在对象、数组及-通配下标上的行为,见 RFC 6902 第 4.1 节。

2.4 编写 kustomization 并挂接 patch

先声明引用 Ingress:

cat <<EOF >$DEMO_HOME/kustomization.yaml resources: - ingress.yaml EOF

再追加patches字段,用target把 patch 指向 Ingress 对象:

cat <<EOF >>$DEMO_HOME/kustomization.yaml patches: - path: ingress_patch.json target: group: networking.k8s.io version: v1beta1 kind: Ingress name: my-ingress EOF

2.5 运行并校验输出

预期输出($DEMO_HOME/out_expected.yaml):

apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: my-ingress spec: rules: - host: foo.bar.io http: paths: - backend: serviceName: homepage servicePort: 80 path: / - backend: servicePort: 7700 path: /healthz - backend: serviceName: my-api servicePort: 7701 path: /api - backend: serviceName: hello servicePort: 7702 path: /test

运行构建并与预期比对:

kustomize build $DEMO_HOME >$DEMO_HOME/out_actual.yaml diff $DEMO_HOME/out_actual.yaml $DEMO_HOME/out_expected.yaml

diff无输出即说明补丁生效,三处修改全部命中:host 变为foo.bar.io/端口变为 80、/healthz被插到/api之前。同时可以看到 patch 后的字段排序(如backendpath的顺序)可能相对原文件发生变化,这与底层实现有关(见第四节)。

三、同样一套补丁,也可以写成 YAML

JSON Patch 的规则不变,但文件本身可以用 YAML 语法书写(YAML 是 JSON 的超集,写起来更省标点)。追加一条「add」操作到列表末尾(/spec/rules/0/http/paths/-中的-表示列表末尾,是 RFC 6902 规定的特殊下标):

cat <<EOF >$DEMO_HOME/ingress_patch.yaml - op: add path: /spec/rules/0/http/paths/- value: path: '/canada' backend: serviceName: hoser servicePort: 7703 EOF

把它加进 kustomization 的 patch 列表:

cat <<EOF >>$DEMO_HOME/kustomization.yaml - path: ingress_patch.yaml target: group: networking.k8s.io version: v1beta1 kind: Ingress name: my-ingress EOF

预期输出末尾追加了/canada路径:

- backend: serviceName: hello servicePort: 7702 path: /test - backend: serviceName: hoser servicePort: 7703 path: /canada

验证:

kustomize build $DEMO_HOME | tail -n 8 |\ diff $DEMO_HOME/out_expected.yaml -

tail -n 8截取输出末尾 8 行再与期望片段比对,同样无输出即通过。

3.1 中文版演示的另一种写法

仓库还提供了一份更精简的中文演示 examples/zh/jsonpatch.md,它演示的是:

  • patchesJson6902(旧字段)写法,patch 中targetpath的顺序可以交换;
  • replace+add两种操作组合,把 host 改为foo.bar.io、把 servicePort 改为8080、追加/test路径;
  • grep验证输出,例如kustomize build $DEMO_HOME | grep "host: foo.bar.io"

两份演示互相印证:同一个功能既可以写在新字段patches下,也可以写在旧字段patchesJson6902下。

四、底层原理:patch 是如何被解析和应用的

4.1 字段定义:Patch 与 Selector

kustomization.yaml中的patches字段类型定义在 api/types/kustomization.go:每个元素都是types.Patch,其结构见 api/types/patch.go:

  • path:patch 文件的相对路径;
  • patch:直接内联的 patch 内容(二选一,与path互斥);
  • target:指向要应用 patch 的资源选择器;
  • options:可选,allowNameChange/allowKindChange两个开关,定义见 api/types/patchargs.go。

targettypes.Selector,定义在 api/types/selector.go,支持以下条件,多个条件取交集(AND 关系):

字段说明
groupAPI 组
versionAPI 版本
kind资源类型
name资源名,支持正则
namespace命名空间
labelSelector标签选择器表达式
annotationSelector注解选择器表达式

从源码可以推断:name等字段会被编译为正则表达式(见 selector.go 的NewSelectorRegexanchorRegex),非空字段以^(?:pattern)$锚定匹配。这意味着name: my-ingress精确匹配,而name: foo.*可以一次命中多个资源。

4.2 解析流程:从文件到 jsonpatch.Patch

内置插件 PatchJson6902Transformer 的Config方法负责解析,核心逻辑:

  1. 校验target.name不能为空、path与内联jsonOp不能同时为空;
  2. 若给了path,用 Loader 读取文件内容;
  3. 若内容不是以[开头,说明是 YAML 格式,先yaml.YAMLToJSON转成 JSON——这就是为什么 patch 文件可以用 YAML 书写;
  4. 交给jsonpatch.DecodePatch解码为操作列表;
  5. 空 patch(解码后长度为 0)直接报错。

4.3 应用流程:目标选择与逐资源打补丁

Transform方法(PatchJson6902Transformer.go)先按target从资源映射中选出所有匹配资源,再对每个资源调用过滤器。最底层的过滤器在 api/filters/patchjson6902/patchjson6902.go:

  1. 把目标资源的 YAML 序列化为 JSON;
  2. 调用jsonpatch库的Apply应用全部操作;
  3. 再把结果反序列化回 YAML。

该文件源码注释也坦诚指出一个重要事实:这种「YAML → JSON → patch → YAML」的往返方式不保证字段顺序完全保持,这正是 2.5 节输出中字段顺序可能重排的根本原因。若对字段顺序敏感,应优先考虑 Strategic Merge Patch 或直接检查生成结果。

过滤器的行为有完整单测覆盖:api/filters/patchjson6902/patchjson6902_test.go 用 4 个用例验证了 JSON/YAML 两种格式下单操作与多操作(replace + 多个 add)的等效性;example_test.go 还展示了对多个资源(FooBar)同时应用同一个 YAML patch 的管道式用法(kio.Pipeline),与 kustomize 的批处理机制同源。

五、一次 patch 打多个资源:target 选择器进阶

patches字段天然支持「一个 patch 作用于多个资源」,因为target是一个选择器而非单一路径。完整演示见 examples/patchMultipleObjects.md,核心要点:

  • name支持正则,name: foo.*可命中多个同类型资源;
  • kind: Deployment只按类型筛;
  • 组合条件更精确,例如同时要求kind: DeploymentlabelSelector: app=hello
  • 该演示还展示了用 labelSelector 只 patch 其中一个 Deployment(labelSelector: key=value时仅 deploy2 被修改)。

需要注意:示例中的patches条目既可以放 Strategic Merge Patch 文件,也可以放 JSON Patch 文件(kustomization.go 注明每个 patch 可以是两者之一),kustomize 依据内容自动识别。若想严格指定 JSON Patch 语义,可使用旧字段patchesJson6902

六、新旧字段迁移:patchesJson6902 已弃用

从 kustomization.go 可以看到patchesJson6902已被标记为Deprecated,注释明确指出:使用patches字段即可,它是 JSON Patch 功能的超集。运行时若检测到旧字段,kustomize 会给出警告(kustomization.go),并在内部把patchesJson6902条目合并进patches(kustomization.go)。

迁移方法很简单,把:

patchesJson6902: - target: group: networking.k8s.io version: v1beta1 kind: Ingress name: my-ingress path: ingress_patch.json

改成:

patches: - path: ingress_patch.json target: group: networking.k8s.io version: v1beta1 kind: Ingress name: my-ingress

七、JSON Patch vs Strategic Merge Patch:如何选择

维度JSON Patch(本文)Strategic Merge Patch
语法RFC 6902 操作数组,精确到路径部分重写目标对象,按 Kubernetes 合并规则
列表操作支持按下标/-精确插入、删除、移动主要靠合并策略,行为受 openapi schema 影响
适用场景改某个精确字段、列表指定位置插入、跨多个同型资源批量修改覆盖字段、注入 sidecar 等常规合并
字段顺序经 JSON 往返,不保证完全保持一般保持结构顺序
声明位置patches(或旧patchesJson6902patches(或旧patchesStrategicMerge

实际项目中二者可混用(都挂在patches下),按「精确路径 vs 局部重写」的诉求灵活选择。

八、快速上手小结

  1. 准备要修改的资源(本文为ingress.yaml),resources引用它;
  2. 写 patch 文件(.json.yaml均可),内容为 RFC 6902 操作数组;
  3. kustomization.yamlpatches下挂接path+target
  4. kustomize build生成结果,用diffgrep验证;
  5. 需要批量时把target.name写成正则,或叠加labelSelector/annotationSelector

更完整的配套示例可继续阅读 examples/jsonpatch.md(英文原版)、examples/zh/jsonpatch.md(中文精简版)与 examples/patchMultipleObjects.md(多资源补丁)。

【免费下载链接】kustomizeCustomization of kubernetes YAML configurations项目地址: https://gitcode.com/gh_mirrors/ku/kustomize

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询