How kubectl apply command works?

Shubham Agarwal
4 min readDec 18, 2021

--

Kubectl apply command is used for creating, updating or deleting an object in a declarative way.

  • The “kubectl apply” command is intelligent enough to create an object if it doesn’t already exist.
  • It will look at the existing configuration and figure out what changes need to be made to the existing objects or applications.

And when we need to make any changes in our application, let’s say need to update the image version, we simply update the object configuration file and run the “kubectl apply -f object-definition.yaml” and this time the apply command knows that the object exists, so it only updates the object with the new changes.

So how the kubectl apply command exactly works?

The kubectl apply takes the local configuration file, a live object definition on Kubernetes and the last applied configuration into consideration before making a decision on what changes are to be made.

local-object-definition.yml

apiVersion: v1
kind: Pod
metadata:
name: httpd
labels:
type : web-server
app: my-app
spec:
containers:
- name: nginx-web-server
image: nginx:1.17

So when you run the kubectl apply -f local-object-definition.yml command, if the object does not already exist, the object is created.

When the Object is created, a “live object configuration” similar to what we created locally is also got created but with additional fields to store the status of the object.

live-object-configuration:

apiVersion: v1
kind: Pod
metadata:
name: httpd
labels:
type : web-server
app: my-app
spec:
containers:
- name: nginx-web-server
image: nginx:1.17
status:
conditions:
- lastProbeTime: null
status: "True"
type: Initialized

This is how Kubernetes internally stores information about an object, no matter what approach you used (kubectl create or kubectl apply) to create the object.

But when we used the “kubectl apply” command to create an object, it does something a bit more.

The yml version of the “local object configuration” file is converted to a JSON format and it is then stored as the “last applied configuration”.

last applied configuration

{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "httpd",
"labels": {
"type": "web-server",
"app": "my-app"
}
},
"spec": {
"containers": [
{
"name": "nginx-web-server",
"image": "nginx:1.17"
}
]
}
}

Going forward for any updates to the object, All the three (local-object-configuration, last-applied-configuration & live-object-configuration) are compared to identify what changes are to be made on live object on Kubernetes cluster.

For example, when the Nginx images is updated to 1.18 in our local file and we run the “kubectl apply” command this value is compared with the value in live configuration and if there is a difference, the live configuration is updated with the new value.

And after any change, the last applied JSON format is always updated to the latest so that it’s always up-to-date.

So why do we really need the last applied configuration?

Let’s say a field was deleted, say for example, the type label was deleted, and now when we run the “kubectl apply” command, we see the last applied configuration had a label, but it’s not present in the local configuration.

This means that the field needs to be removed from the live configuration.

So if a field is present in the live configuration and not present in the local or the last applied configuration, then it will be left as it is.

But if a field is missing from the local field and it is present in the last applied configuration, so that means that in the previous step or wherever the last time we ran the program in that particular field was there and it is now being removed.

So the last applied configuration helps us to figure out, what fields have been removed from the local file, so that field is then removed from the live configuration.

So we saw the three sets of files and we know that the local file is stored in our local system. The live object configuration is stored in the Kubernetes memory, but where is the JSON file that has the last applied configuration stored?

It’s stored in the live object configuration on the Kubernetes cluster itself as an annotation, named last applied configuration:

apiVersion: v1
kind: Pod
metadata:
name: httpd
labels:
type : web-server
app: my-app
annotations:
kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion": "v1","kind": "Pod","metadata": {"name": "httpd", "labels": {"type": "web-server","app": "my-app"}},"spec": {"containers": [{"name": "nginx-web-server","image": "nginx:1.17"
}]}}
spec:
containers:
- name: nginx-web-server
image: nginx:1.17
status:
conditions:
- lastProbeTime: null
status: "True"
type: Initialized

So that is the only applied when we use the kubectl apply command, the kubectl create or replace command does not store the last applied configuration like this.

Thanks for reading!!! :)

Refer Other useful Kubernetes Articles:

Declarative Management of Kubernetes Objects Using Configuration Files

Kubernetes Services for Absolute Beginners — NodePort

Kubernetes Services for Absolute Beginners — ClusterIP

Kubernetes Services for Absolute Beginners — LoadBalancer

labels-and-selectors-in-kubernetes

Kubernetes workflow for Absolute Beginners

--

--

Shubham Agarwal
Shubham Agarwal

Written by Shubham Agarwal

Site Reliability Engineer, have 5 years of experience in IT support and Operations

Responses (3)