Understanding the Kubectl Apply Command

In this post, we'll explore how the kubectl apply command works internally. Which will give you a better understanding of how kubernetes works under the hood and make you stand out as a DevOps Engineer.

Introduction

Usually, the kubectl apply command is used to create and update objects in a declarative way.

For instance, to update/create an object defined in nginx.yaml:

kubectl apply -f nginx.yaml

As a reminder, the previous command shows how the apply command is used to create and update kubernetes objects in a declarative fashion.


---

In order to understand the internals of the apply command, let's first take a step back and understand how objects are created within kubernetes:

Take as an example the following POD object defined in a YAML file:

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
    type: front-end-service
spec:
  containers:
    - name: nginx-container
      image: nginx:1.18

Now create the object:

kubectl create -f nginx.yaml

Important: In the background, a live configuration file is additionally generated within kubernetes. This new file is similar to the one we created locally. However, it contains further information regarding the status of the object:

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
    type: front-end-service
spec:
  containers:
    - name: nginx-container
      image: nginx:1.18
# New
status:
  conditions:
    - lastProbeTime: null
      status: "True"
      type: Initialized

The above file is the live configuration of the object on the kubernetes cluster.

As depicted above, kubernetes appends the status field to the configuration file in order to track information about the object.

This is how kubernetes internally stores information about an object, regardless of the way it was created (declarative or imperative).

Back to the Apply command

The apply command, when executed, takes into consideration the following 3 files in for book-keeping.

  • A local configuration file (defined by the developer)
  • A live object definition on kubernetes (The Additional YAML file created by kubernetes)
  • The last applied configuration. (New)

As you may have noticed, the first two listed files are the ones we have previously discussed, the third is unique to the apply command.

Whenever we run the apply command All of the three files are compared to identify what changes are to be made on the live object

More on the applied configuration file

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

Following our previous examples:

{
  "apiVersion": "v1",
  "kind": "Pod",
  "metadata": {
    "annotations": {},
    "labels": {
      "run": "myapp-pod",
      "type": "front-end-service"
    },
    "name": "myapp-pod"
  },
  "spec": {
    "containers": [
      {
        "image": "nginx:1.18",
        "name": "nginx-container"
      }
    ]
  }
}

How does kubernetes utilize theseĀ files?

For example: say we update the image field from 1.18 to 1.19 in our local configuration file, and we then run the apply command as before.

This changed image field is compared with the value in the live configuration and if there is a difference, the live configuration is updated with the new value.

After any change, the last applied JSON file is always updated.

At this point you will probably be asking yourself: What is the purpose of the JSON applied configuration file?

This is best illustrated with an example:

Let's imagine that a field was deleted, say, the type field in label was deleted in our local configuration file. When we run the kubectl apply command, we see that 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 (The YAML file generated by kubernetes).

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

But if a field is missing from the local file and it is present in the last applied configuration, that means that in the previous step the field was removed.

So in summary: the newly added applied configuration file helps kubernetes figure out the fields that have been removed from the local file.




What we just discussed is available for your reference in detail in the kubernetes is documentation pages.




Wrapping Up

  • We learned about the three sets of files used by the kubectl apply command
  • The local file is what's stored on our local system.
  • The live object configuration is in the kubernetes memory.

But where is this JSON file that has the last applied configuration stored?

It's stored on the live object configuration on the kubernetes cluster itself as an annotation named: last applied configuration.

So remember that this is only done when you use the apply command, the kubectl create or replace command do not store the last applied configuration like explained.

Once you use the apply command going forward, whenever a change is made, the apply command compares all three sections.

  1. The local definition file.
  2. The live object configuration file.
  3. The last applied configuration stored