Update API Objects in Place Using kubectl patch

    This task shows how to use kubectl patch to update an API object in place. The exercises in this task demonstrate a strategic merge patch and a JSON merge patch.

    You need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. It is recommended to run this tutorial on a cluster with at least two nodes that are not acting as control plane hosts. If you do not already have a cluster, you can create one by using or you can use one of these Kubernetes playgrounds:

    To check the version, enter kubectl version.

    Use a strategic merge patch to update a Deployment

    Here’s the configuration file for a Deployment that has two replicas. Each replica is a Pod that has one container:

    Create the Deployment:

    1. kubectl apply -f https://k8s.io/examples/application/deployment-patch.yaml

    View the Pods associated with your Deployment:

    1. kubectl get pods

    The output shows that the Deployment has two Pods. The 1/1 indicates that each Pod has one container:

    1. NAME READY STATUS RESTARTS AGE
    2. patch-demo-28633765-670qr 1/1 Running 0 23s
    3. patch-demo-28633765-j5qs3 1/1 Running 0 23s

    Make a note of the names of the running Pods. Later, you will see that these Pods get terminated and replaced by new ones.

    At this point, each Pod has one Container that runs the nginx image. Now suppose you want each Pod to have two containers: one that runs nginx and one that runs redis.

    Create a file named patch-file.yaml that has this content:

    1. spec:
    2. template:
    3. spec:
    4. containers:
    5. - name: patch-demo-ctr-2
    6. image: redis

    Patch your Deployment:

    1. kubectl patch deployment patch-demo --patch-file patch-file.yaml

    View the patched Deployment:

    1. kubectl get deployment patch-demo --output yaml

    The output shows that the PodSpec in the Deployment has two Containers:

    1. containers:
    2. - image: redis
    3. imagePullPolicy: Always
    4. name: patch-demo-ctr-2
    5. ...
    6. - image: nginx
    7. imagePullPolicy: Always
    8. name: patch-demo-ctr
    9. ...

    View the Pods associated with your patched Deployment:

    1. kubectl get pods

    The output shows that the running Pods have different names from the Pods that were running previously. The Deployment terminated the old Pods and created two new Pods that comply with the updated Deployment spec. The 2/2 indicates that each Pod has two Containers:

    1. NAME READY STATUS RESTARTS AGE
    2. patch-demo-1081991389-2wrn5 2/2 Running 0 1m
    3. patch-demo-1081991389-jmg7b 2/2 Running 0 1m

    Take a closer look at one of the patch-demo Pods:

    1. kubectl get pod <your-pod-name> --output yaml

    The output shows that the Pod has two Containers: one running nginx and one running redis:

    1. containers:
    2. - image: redis
    3. ...
    4. - image: nginx
    5. ...

    The patch you did in the preceding exercise is called a strategic merge patch. Notice that the patch did not replace the containers list. Instead it added a new Container to the list. In other words, the list in the patch was merged with the existing list. This is not always what happens when you use a strategic merge patch on a list. In some cases, the list is replaced, not merged.

    With a strategic merge patch, a list is either replaced or merged depending on its patch strategy. The patch strategy is specified by the value of the patchStrategy key in a field tag in the Kubernetes source code. For example, the Containers field of PodSpec struct has a patchStrategy of merge:

    1. type PodSpec struct {
    2. ...
    3. Containers []Container `json:"containers" patchStrategy:"merge" patchMergeKey:"name" ...`
    4. ...
    5. }

    You can also see the patch strategy in the :

    1. "io.k8s.api.core.v1.PodSpec": {
    2. ...,
    3. "containers": {
    4. "description": "List of containers belonging to the pod. ...."
    5. },
    6. "x-kubernetes-patch-merge-key": "name",
    7. "x-kubernetes-patch-strategy": "merge"
    8. }

    And you can see the patch strategy in the Kubernetes API documentation.

    Create a file named patch-file-tolerations.yaml that has this content:

    1. spec:
    2. template:
    3. spec:
    4. tolerations:
    5. - effect: NoSchedule
    6. key: disktype
    7. value: ssd
    1. kubectl patch deployment patch-demo --patch-file patch-file-tolerations.yaml

    View the patched Deployment:

    The output shows that the PodSpec in the Deployment has only one Toleration:

    1. tolerations:
    2. - effect: NoSchedule
    3. key: disktype
    4. value: ssd

    Notice that the tolerations list in the PodSpec was replaced, not merged. This is because the Tolerations field of PodSpec does not have a patchStrategy key in its field tag. So the strategic merge patch uses the default patch strategy, which is replace.

    1. ...
    2. Tolerations []Toleration `json:"tolerations,omitempty" protobuf:"bytes,22,opt,name=tolerations"`
    3. ...
    4. }

    A strategic merge patch is different from a JSON merge patch. With a JSON merge patch, if you want to update a list, you have to specify the entire new list. And the new list completely replaces the existing list.

    The kubectl patch command has a type parameter that you can set to one of these values:

    For a comparison of JSON patch and JSON merge patch, see .

    The default value for the type parameter is strategic. So in the preceding exercise, you did a strategic merge patch.

    Next, do a JSON merge patch on your same Deployment. Create a file named patch-file-2.yaml that has this content:

    1. spec:
    2. spec:
    3. containers:
    4. - name: patch-demo-ctr-3
    5. image: gcr.io/google-samples/node-hello:1.0

    In your patch command, set type to merge:

    1. kubectl patch deployment patch-demo --type merge --patch-file patch-file-2.yaml

    View the patched Deployment:

    1. kubectl get deployment patch-demo --output yaml

    The containers list that you specified in the patch has only one Container. The output shows that your list of one Container replaced the existing containers list.

    1. spec:
    2. containers:
    3. - image: gcr.io/google-samples/node-hello:1.0
    4. ...
    5. name: patch-demo-ctr-3

    List the running Pods:

    1. kubectl get pods

    In the output, you can see that the existing Pods were terminated, and new Pods were created. The 1/1 indicates that each new Pod is running only one Container.

    1. NAME READY STATUS RESTARTS AGE
    2. patch-demo-1307768864-69308 1/1 Running 0 1m
    3. patch-demo-1307768864-c86dc 1/1 Running 0 1m

    Use strategic merge patch to update a Deployment using the retainKeys strategy

    Here’s the configuration file for a Deployment that uses the RollingUpdate strategy:

    Update API Objects in Place Using kubectl patch - 图2

    1. apiVersion: apps/v1
    2. kind: Deployment
    3. metadata:
    4. name: retainkeys-demo
    5. spec:
    6. selector:
    7. matchLabels:
    8. app: nginx
    9. strategy:
    10. rollingUpdate:
    11. maxSurge: 30%
    12. template:
    13. metadata:
    14. labels:
    15. app: nginx
    16. spec:
    17. containers:
    18. - name: retainkeys-demo-ctr
    19. image: nginx

    Create the deployment:

    1. kubectl apply -f https://k8s.io/examples/application/deployment-retainkeys.yaml

    At this point, the deployment is created and is using the RollingUpdate strategy.

    Create a file named patch-file-no-retainkeys.yaml that has this content:

    1. spec:
    2. strategy:
    3. type: Recreate

    Patch your Deployment:

    1. kubectl patch deployment retainkeys-demo --type strategic --patch-file patch-file-no-retainkeys.yaml

    In the output, you can see that it is not possible to set type as Recreate when a value is defined for spec.strategy.rollingUpdate:

    1. The Deployment "retainkeys-demo" is invalid: spec.strategy.rollingUpdate: Forbidden: may not be specified when strategy `type` is 'Recreate'

    The way to remove the value for spec.strategy.rollingUpdate when updating the value for type is to use the retainKeys strategy for the strategic merge.

    Create another file named patch-file-retainkeys.yaml that has this content:

    1. spec:
    2. strategy:
    3. $retainKeys:
    4. - type
    5. type: Recreate

    With this patch, we indicate that we want to retain only the type key of the strategy object. Thus, the rollingUpdate will be removed during the patch operation.

    1. kubectl patch deployment retainkeys-demo --type strategic --patch-file patch-file-retainkeys.yaml

    Examine the content of the Deployment:

    The output shows that the strategy object in the Deployment does not contain the rollingUpdate key anymore:

    1. spec:
    2. strategy:
    3. type: Recreate
    4. template:

    The patch you did in the preceding exercise is called a strategic merge patch with retainKeys strategy. This method introduces a new directive $retainKeys that has the following strategies:

    • It contains a list of strings.
    • All fields needing to be preserved must be present in the $retainKeys list.
    • The fields that are present will be merged with live object.
    • All of the missing fields will be cleared when patching.
    • All fields in the $retainKeys list must be a superset or the same as the fields present in the patch.

    The retainKeys strategy does not work for all objects. It only works when the value of the patchStrategy key in a field tag in the Kubernetes source code contains retainKeys. For example, the Strategy field of the DeploymentSpec struct has a patchStrategy of retainKeys:

    1. type DeploymentSpec struct {
    2. ...
    3. // +patchStrategy=retainKeys
    4. Strategy DeploymentStrategy `json:"strategy,omitempty" patchStrategy:"retainKeys" ...`
    5. ...

    You can also see the retainKeys strategy in the :

    1. "io.k8s.api.apps.v1.DeploymentSpec": {
    2. ...,
    3. "$ref": "#/definitions/io.k8s.api.apps.v1.DeploymentStrategy",
    4. "description": "The deployment strategy to use to replace existing pods with new ones.",
    5. "x-kubernetes-patch-strategy": "retainKeys"
    6. },
    7. ....
    8. }

    And you can see the retainKeys strategy in the Kubernetes API documentation.

    The kubectl patch command takes YAML or JSON. It can take the patch as a file or directly on the command line.

    Create a file named patch-file.json that has this content:

    1. {
    2. "spec": {
    3. "template": {
    4. "spec": {
    5. "containers": [
    6. {
    7. "name": "patch-demo-ctr-2",
    8. "image": "redis"
    9. }
    10. ]
    11. }
    12. }
    13. }
    14. }

    The following commands are equivalent:

    1. kubectl patch deployment patch-demo --patch-file patch-file.yaml
    2. kubectl patch deployment patch-demo --patch 'spec:\n template:\n spec:\n containers:\n - name: patch-demo-ctr-2\n image: redis'
    3. kubectl patch deployment patch-demo --patch-file patch-file.json
    4. kubectl patch deployment patch-demo --patch '{"spec": {"template": {"spec": {"containers": [{"name": "patch-demo-ctr-2","image": "redis"}]}}}}'

    FEATURE STATE: Kubernetes v1.24 [alpha]

    The flag --subresource=[subresource-name] is used with kubectl commands like get, patch, edit and replace to fetch and update status and scale subresources of the resources (applicable for kubectl version v1.24 or more). This flag is used with all the API resources (built-in and CRs) which has status or scale subresource. Deployment is one of the examples which supports these subresources.

    Here’s a manifest for a Deployment that has two replicas:

    1. apiVersion: apps/v1
    2. kind: Deployment
    3. metadata:
    4. name: nginx-deployment
    5. spec:
    6. selector:
    7. matchLabels:
    8. app: nginx
    9. replicas: 2 # tells deployment to run 2 pods matching the template
    10. template:
    11. metadata:
    12. labels:
    13. app: nginx
    14. spec:
    15. containers:
    16. - name: nginx
    17. image: nginx:1.14.2
    18. ports:
    19. - containerPort: 80

    Create the Deployment:

    1. kubectl apply -f https://k8s.io/examples/application/deployment.yaml

    View the Pods associated with your Deployment:

    1. kubectl get pods -l app=nginx

    In the output, you can see that Deployment has two Pods. For example:

    1. NAME READY STATUS RESTARTS AGE
    2. nginx-deployment-7fb96c846b-22567 1/1 Running 0 47s
    3. nginx-deployment-7fb96c846b-mlgns 1/1 Running 0 47s

    Now, patch that Deployment with --subresource=[subresource-name] flag:

    1. kubectl patch deployment nginx-deployment --subresource='scale' --type='merge' -p '{"spec":{"replicas":3}}'

    The output is:

    1. scale.autoscaling/nginx-deployment patched

    View the Pods associated with your patched Deployment:

    1. kubectl get pods -l app=nginx

    In the output, you can see one new pod is created, so now you have 3 running pods.

    1. NAME READY STATUS RESTARTS AGE
    2. nginx-deployment-7fb96c846b-22567 1/1 Running 0 107s
    3. nginx-deployment-7fb96c846b-lxfr2 1/1 Running 0 14s
    4. nginx-deployment-7fb96c846b-mlgns 1/1 Running 0 107s

    View the patched Deployment:

    1. kubectl get deployment nginx-deployment -o yaml
    1. ...
    2. spec:
    3. replicas: 3
    4. ...
    5. status:
    6. ...
    7. availableReplicas: 3
    8. readyReplicas: 3
    9. replicas: 3

    Note: If you run kubectl patch and specify --subresource flag for resource that doesn’t support that particular subresource, the API server returns a 404 Not Found error.

    In this exercise, you used to change the live configuration of a Deployment object. You did not change the configuration file that you originally used to create the Deployment object. Other commands for updating API objects include , kubectl edit, , kubectl scale, and .

    What’s next