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. If you do not already have a cluster, you can create one by using Minikube, or you can use one of these Kubernetes playgrounds:
To check the version, enter kubectl version
.
Here’s the configuration file for a Deployment that has two replicas. Each replica is a Pod that has one container:
deployment-patch-demo.yaml docs/tasks/run-application
|
---|
|
Create the Deployment:
kubectl create -f https://k8s.io/docs/tasks/run-application/deployment-patch-demo.yaml
View the Pods associated with your Deployment:
kubectl get pods
The output shows that the Deployment has two Pods. The 1/1
indicates that
each Pod has one container:
NAME READY STATUS RESTARTS AGE
patch-demo-28633765-670qr 1/1 Running 0 23s
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-containers.yaml
that has this content:
spec:
template:
spec:
containers:
- name: patch-demo-ctr-2
image: redis
Patch your Deployment:
kubectl patch deployment patch-demo --patch "$(cat patch-file-containers.yaml)"
View the patched Deployment:
kubectl get deployment patch-demo --output yaml
The output shows that the PodSpec in the Deployment has two Containers:
containers:
- image: redis
imagePullPolicy: Always
name: patch-demo-ctr-2
...
- image: nginx
imagePullPolicy: Always
name: patch-demo-ctr
...
View the Pods associated with your patched Deployment:
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:
NAME READY STATUS RESTARTS AGE
patch-demo-1081991389-2wrn5 2/2 Running 0 1m
patch-demo-1081991389-jmg7b 2/2 Running 0 1m
Take a closer look at one of the patch-demo Pods:
kubectl get pod <your-pod-name> --output yaml
The output shows that the Pod has two Containers: one running nginx and one running redis:
containers:
- image: redis
...
- image: nginx
...
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
:
type PodSpec struct {
...
Containers []Container `json:"containers" patchStrategy:"merge" patchMergeKey:"name" ...`
You can also see the patch strategy in the OpenApi spec:
"io.k8s.api.core.v1.PodSpec": {
...
"containers": {
"description": "List of containers belonging to the pod. ...
},
"x-kubernetes-patch-merge-key": "name",
"x-kubernetes-patch-strategy": "merge"
},
And you can see the patch strategy in the Kubernetes API documentation.
Create a file named patch-file-tolerations.yaml
that has this content:
spec:
template:
spec:
tolerations:
- effect: NoSchedule
key: disktype
value: ssd
Patch your Deployment:
kubectl patch deployment patch-demo --patch "$(cat patch-file-tolerations.yaml)"
View the patched Deployment:
kubectl get deployment patch-demo --output yaml
The output shows that the PodSpec in the Deployment has only one Toleration:
tolerations:
- effect: NoSchedule
key: disktype
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
.
type PodSpec struct {
...
Tolerations []Toleration `json:"tolerations,omitempty" protobuf:"bytes,22,opt,name=tolerations"`
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:
Parameter value | Merge type |
---|---|
json | JSON Patch, RFC 6902 |
merge | JSON Merge Patch, RFC 7386 |
strategic | Strategic merge patch |
For a comparison of JSON patch and JSON merge patch, see JSON Patch and JSON Merge Patch.
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:
spec:
template:
spec:
containers:
- name: patch-demo-ctr-3
image: gcr.io/google-samples/node-hello:1.0
In your patch command, set type
to merge
:
kubectl patch deployment patch-demo --type merge --patch "$(cat patch-file-2.yaml)"
View the patched Deployment:
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.
spec:
containers:
- image: gcr.io/google-samples/node-hello:1.0
...
name: patch-demo-ctr-3
List the running Pods:
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.
NAME READY STATUS RESTARTS AGE
patch-demo-1307768864-69308 1/1 Running 0 1m
patch-demo-1307768864-c86dc 1/1 Running 0 1m
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:
{
"spec": {
"template": {
"spec": {
"containers": [
{
"name": "patch-demo-ctr-2",
"image": "redis"
}
]
}
}
}
}
The following commands are equivalent:
kubectl patch deployment patch-demo --patch "$(cat patch-file.yaml)"
kubectl patch deployment patch-demo --patch 'spec:\n template:\n spec:\n containers:\n - name: patch-demo-ctr-2\n image: redis'
kubectl patch deployment patch-demo --patch "$(cat patch-file.json)"
kubectl patch deployment patch-demo --patch '{"spec": {"template": {"spec": {"containers": [{"name": "patch-demo-ctr-2","image": "redis"}]}}}}'
In this exercise, you used kubectl patch
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 annotate,
kubectl edit,
kubectl replace,
kubectl scale,
and
kubectl apply.