K8S Patch 命令介绍

2021-02-05 container

通过 patch 命令可以对集群中的资源进行部分更新,也就是以补丁 (Patch) 方式修改、更新某资源的字段,相对于 apply 命令来说,无需提供完整的资源文件,只需要提供更新的内容即可。

简介

支持如下的三种操作类型:

  • Strategic Patch 默认方式,会根据源码中资源对应字段中的 patchMergeKey 标识。
  • JSON Merge Patch 遵循 JSON Merge Patch RFC 7386 规范,根据提供期望更改的字段及其对应的值更新到目标中。
  • JSON Patch 遵循 JSON Patch RFC 6902 规范,通过明确的指令表示具体的操作。

Strategic Patch

如上所述,具体 Patch 的策略由源码中资源对应字段标识,有如下三种策略:

  • replace 默认,可以显示指定,如果 list 类型字段未设置则会替换掉整个列表。
  • merge 将补丁中的中的元素合并到原 list 中。
  • retainKeys 仅保留 object 对象中指定的字段。

例如如下 PodSpec 中的 Containers 字段显式标识了为 merge 策略,也就是合并;而 Tolerations 字段则使用默认的 replace 策略。不同类型的资源可以从 Kubernetes API 或者 Github Swagger.json 中查看,例如 io.k8s.api.core.v1.PodSpec

type PodSpec struct {
  Containers []Container `json:"containers" patchStrategy:"merge" patchMergeKey:"name" ...`
  Tolerations []Toleration `json:"tolerations,omitempty" protobuf:"bytes,22,opt,name=tolerations"`
}

其中 Containers 会采用 merge 策略,而 Key 为 name,也就意味着对应 name 的容器如果不存在则会新增,否则只是更新镜像信息。那么执行如下命令时会看到 Pod 中新增了一个 Container 实例。

----- 新增一个Deployment资源
# cat nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: patch-demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: patch-demo-nginx
        image: nginx
      tolerations:
      - effect: NoSchedule
        key: dedicated
        value: test-team
# kubectl apply -f nginx-deployment.yaml
----- 然后打一个Patch,可以查看输出
# cat patch-container.yaml
spec:
  template:
    spec:
      containers:
      - name: patch-demo
        image: redis
# kubectl patch deployment patch-demo --patch "$(cat patch-containers.yaml)"
# kubectl get deployment patch-demo --output yaml
----- 源码中没有指定,则默认替换
# cat patch-tolerations.yaml
spec:
  template:
    spec:
      tolerations:
      - effect: NoSchedule
        key: disktype
        value: ssd
# kubectl patch deployment patch-demo --patch "$(cat patch-tolerations.yaml)"
# kubectl get deployment patch-demo --output yaml

JSON Merge Patch

也就是遵循 JSON Merge Patch RFC 7386 规范,根据提供期望更改的字段及其对应的值更新到目标中,其规则如下:

  • 提供 Patch 内容中包含目标不存在的字段则添加。
  • 目标包含 Patch 中提供的字段,则替换该字段的值。
  • Patch 中将目标中含有的字段设置为 null 则删除该字段。

如下是一个简单的示例。

{                        |{                         |{
  "title": "Goodbye!",   |   "title": "Hello!",     |  "title": "Hello!",    # 修改
  "author": {            |   "author": {            |  "author": {
    "givenName": "John", |                          |    "givenName": "John"
    "familyName": "Doe"  |      "familyName": null  |                        # 删除
  },                     |   },                     |  },
  "tags": [              |   "tags": [              |  "tags": [             # 修改
    "example",           |      "example"           |      "example"
    "sample"             |                          |
  ],                     |   ],                     |  ],
  "content": "message"   |                          |  "content": "message",
                         |   "phoneNumber": "1234"  |  "phoneNumber": "1234" # 新增
}                        |}                         |}
               ----->>>>> Patch           ----->>>>> Result

使用 kubectl patch 更新时通过 --type merge 指定即可。

# kubectl patch deployment --type merge patch-demo --patch '
{
  "spec": {
    "replicas": 5
  }
}'

JSON Patch

遵循 JSON Patch RFC 6902 规范,通过明确的指令表示具体的操作,在 op 字段中设置具体的操作,包含:

  • add 添加字段。
  • remove 删除字段。
  • replace 替换字段。
  • move 删除指定字段的值,并将其添加到目标字段。
  • copy 将指定字段的值复制到目标字段。
  • test 测试字段的值是否等于给定值。

同样以如上的示例,转换为如下请求。

[  
  {"op": "replace", "path": "/title", "value": "Hello!"},
  {"op": "remove", "path": "/author/familyName"},
  {"op": "replace", "path": "/tags", "value": ["example"]},
  {"op": "add", "path": "/phoneNumber", "value": "1234"}
]

在使用时通过 --type json 指定。