Declarative vs. Imperative object management

Kubernetes provides two ways to manage objects: declarative and imperative.

Imperative object management

In imperative object management, you tell Kubernetes exactly what to do. You provide the command and Kubernetes executes it.

Declarative object management

In declarative object management, you tell Kubernetes what you want to achieve. You provide a configuration file and Kubernetes makes sure that the cluster matches the desired state.

The difference

The difference between the two is subtle. Let's understand this with examples.

Imperative pod creation

Let's understand imperative object management with an example.

Run the following command to create a pod named simple-pod:

cd bootstrapping-with-kubernetes-examples/deploy/simple-pod
kubectl create -f pod.yaml

It should give the following output:

$ kubectl create -f pod.yaml
pod/simple-pod created

In this command, you're telling Kubernetes to exactly perform the create operation on the pod.yaml file. This will create a pod named simple-pod with no labels, as shown below:

$ kubectl get pods --show-labels
NAME         READY   STATUS    RESTARTS   AGE   LABELS
simple-pod   1/1     Running   0          25m   <none>

Now, say you want to add a label app=simple-pod to the pod. You can do this by running the following command:

kubectl label pod simple-pod app=simple-pod

This will add the label app=simple-pod to the pod.

$ kubectl get pods --show-labels
NAME         READY   STATUS    RESTARTS   AGE   LABELS
simple-pod   1/1     Running   0          27m   app=simple-pod

In this command, you're telling Kubernetes to exactly perform the label operation on the simple-pod pod.

Another way to add label would be edit the metadata field in the pod.yaml file and add the label there, as shown below:

metadata:
  name: simple-pod
  labels:
    app: simple-pod

Now, if you run create on the updated configuration again, kubectl will give the following output:

$ kubectl create -f pod.yaml
Error from server (AlreadyExists): error when creating "pod.yaml": pods "simple-pod" already exists

This happens because the create operation is idempotent. It will only create the object if it doesn't exist. It won't update the object if it already exists. This creates issues when you are working with existing objects and want to update them using imperative object management. To perform such updates, the imperative way, you will need to keep using commands like kubectl label pod simple-pod app=simple-pod, kubectl edit pod simple-pod, etc.

This behavior is not ideal when you want to manage objects in a more reliable and consistent way. This is where declarative object management helps.

Before going into declarative object management, let's delete the simple-pod pod:

kubectl delete -f pod.yaml

Declarative pod creation

Using declarative object management, you provide a configuration file that describes the desired state of the object. Kubernetes will make sure that the cluster matches the desired state.

Let's understand this with an example.

kubectl apply -f pod.yaml

This will again create a pod named simple-pod with no labels.

$ kubectl get pods --show-labels
NAME         READY   STATUS    RESTARTS   AGE   LABELS
simple-pod   1/1     Running   0          48s   <none>

Now, to add a label app=simple-pod to the pod, you can edit the pod.yaml file and add the label there, as shown below:

metadata:
  name: simple-pod
  labels:
    app: simple-pod

Now, if you run apply on the updated configuration again, kubectl will update the pod with the new label:

$ kubectl apply -f pod.yaml
pod/simple-pod configured
$ kubectl get pods --show-labels
NAME         READY   STATUS    RESTARTS   AGE     LABELS
simple-pod   1/1     Running   0          2m42s   app=simple-pod

The benefit here is that you don't have to worry about the current state of the object. You just provide the desired state and Kubernetes will make sure that the cluster matches the desired state. This is more reliable and easier to manage.

Also, if you run apply command again, without making any changes, the command will still run successfully.

Delete the simple-pod pod:

kubectl delete -f pod.yaml

Which one to use?

Declarative object management is the recommended way to manage objects in Kubernetes. This way, you don't have to consistently keep track of the current state of the object, Kubernetes will do that for you. All you need to do is to specify the desired state.