PUT/Patch 都能够对资源进行操作。
PUT 对资源进行残缺内容的批改,Patch 能够对资源进行局部批改。
1.Patch 类型
- JSONPatchType
- MergePatchType
- StrategicMergePatch
2. 测试对象
创立 deploy,上面的 Patch 操作以此为例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
tolerations:
- effect: NoSchedule
key: abc
value: xyz
deloy 蕴含:
- 2 个 pod;
- 每个 pod 含 1 个 container:nginx;
- 带 1 个 toleration;
# kubectl get deploy,pod
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/demo 2/2 2 2 11s
NAME READY STATUS RESTARTS AGE
pod/demo-7ff49f4cdb-d9jpc 1/1 Running 0 11s
pod/demo-7ff49f4cdb-t6lsl 1/1 Running 0 11s
3.JSONPatch:
通过 client.Patch() 进行 JSONPatch,批改 deploy 的 replicas=3:
var replicaPatchData = `[{"op": "replace", "path": "/spec/replicas", "value": 3}]`
ctx := context.Background()
result, err := client.AppsV1().Deployments("default").
Patch(ctx, "demo", types.JSONPatchType, []byte(replicaPatchData), metav1.PatchOptions{})
能够看到,JSONPatch 的 body 中须要指明:
- op: 操作,比方 replace/add/copy 等等;
- path: 操作的指标,这里是 json 的门路节点;
- value: 新值;
JSONPatch 因为要具体指明门路和操作符,应用较为繁琐。
4.MergePatch
通过 client.Patch() 进行 MergePatch,批改 deploy 的 containers:
var containerPatchData = `{"spec": {"template": {"spec": {"containers": [{"name": "redis", "image": "redis"}]}}}}`
ctx := context.Background()
result, err := client.AppsV1().Deployments("default").
Patch(ctx, "demo", types.MergePatchType, []byte(containerPatchData), metav1.PatchOptions{})
批改完结后,pod 中依然仅有 1 个 container,但其镜像由 nginx 被更新为 redis;
能够看到,对于 MergePath 中的 body 中指明要批改的字段,其内容被残缺替换。
MergePatch 的特点:
- 无奈追加数组,因为它会间接替换掉原数组内容;
- 若将 value=nil,则其语义 = 将该项删除;
5.StrategicMergePatch
这是最易于 client 应用的 Patch 类型。
1) 更新 containers
通过 client.Patch() 进行 StrategicMergePatch,批改 deloy 的 containers:
var containerPatchData = `{"spec": {"template": {"spec": {"containers": [{"name": "redis", "image": "redis"}]}}}}`
ctx := context.Background()
result, err := client.AppsV1().Deployments("default").
Patch(ctx, "demo", types.StrategicMergePatchType, []byte(containerPatchData), metav1.PatchOptions{})
批改完结后,pod 中有 2 个 container,新增了一个 redis 的 container。
2) 更新 tolerations
通过 client.Patch() 进行 StrategicMergePatch,批改 deploy 的 tolerations:
var tolerationPathData = `{"spec": {"template": {"spec": {"tolerations": [{"effect": "NoSchedule", "key": "hij", "value": "opr"}]}}}}`
ctx := context.Background()
result, err := client.AppsV1().Deployments("default").
Patch(ctx, "demo", types.StrategicMergePatchType, []byte(tolerationPathData), metav1.PatchOptions{})
批改完结后,deploy 中仅有 1 个 tolerations,源 toleration 被替换为新的 toleration;
3) 更新原理
从下面能够看到,对于 delopy 中的 containers 和 tolerations,尽管都是 slice,然而:
- containers 的 StrategicMergePatch 进行了 slice 元素的新增;
- tolerations 的 StrategicMergePatch 进行了 slice 的整个替换;
StragegicMergePatch 对字段的内容,是 Merge 还是 replace,取决于字段的定义:
// PodSpec is a description of a pod.
type PodSpec struct {
....
Containers []Container `json:"containers" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,2,rep,name=containers"`
...
Tolerations []Toleration `json:"tolerations,omitempty" protobuf:"bytes,22,opt,name=tolerations"`}
- Containers 字段,patchStrategy=merge,即进行元素的新增;
- Tolerations 字段,未指定 patchStragegy 字段,默认 patchStrategy=replace,即进行元素的替换;
5.CRD 类型的 Patch
对于 CRD 类型,不反对 StrategicMergePatch,即只能应用 JSONPatch 或 MergePatch。
参考
1.https://kubernetes.io/zh/docs/tasks/manage-kubernetes-objects…
2.https://erosb.github.io/post/json-patch-vs-merge-patch/
3.https://datatracker.ietf.org/doc/html/rfc7386#section-1
4. 更新的语义:https://www.cnblogs.com/FengZeng666/p/15128060.html