Using Diff in Kubernetes

2 minute read

Diff

As you might probably know one of the most important concepts in Kubernetes is its Objects model. The Kubernetes objects are persistent entities in the K8S system. Kubernetes uses these entities to represent the state of your cluster. They can describe what containerized applications are running, on which nodes, the resources available to those applications, the policies around, etc.

A Kubernetes object is a “record of intent”, which means that once you create the object, the K8S will constantly work to ensure that object exists. By creating an object you tell the system the desired state. To work with Kubernetes objects, which are stored in its database, the user uses the Kubernetes API, for example, by using the kubectl command-line interface which makes the necessary Kubernetes API calls for you.

Understanding the differences between the current state and the desired state, it is important to highlight one of the most useful, and sometimes ignored, commands: kubectl diff. Let’s see an example, we are going to create a simple deployment like the following:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nginx
  replicas: 1 
  template: 
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
kubectl apply -f deployment.nginx.yaml

Now let’s change the deployment parameters to deploy an additional replica (replicas: 2) and, since we want to check the difference between the current deployment and the new one, we check it by executing:

kubectl diff -f deployment.nginx.yaml

And this is the output:

diff -u -N /tmp/LIVE-417333416/apps.v1.Deployment.language.nginx /tmp/MERGED-411218407/apps.v1.Deployment.language.nginx
--- /tmp/LIVE-417333416/apps.v1.Deployment.language.nginx	2021-03-14 16:47:47.205057892 +0200
+++ /tmp/MERGED-411218407/apps.v1.Deployment.language.nginx	2021-03-14 16:47:47.229058257 +0200
@@ -6,7 +6,7 @@
     kubectl.kubernetes.io/last-applied-configuration: |
       {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"nginx","namespace":"language"},"spec":{"replicas":2,"selector":{"matchLabels":{"app":"nginx"}},"strategy":{"type":"Recreate"},"template":{"metadata":{"labels":{"app":"nginx"}},"spec":{"containers":[{"image":"nginx","name":"nginx","ports":[{"containerPort":80}]}]}}}}
   creationTimestamp: "2021-03-14T14:39:46Z"
-  generation: 1
+  generation: 2
   managedFields:
   - apiVersion: apps/v1
     fieldsType: FieldsV1
@@ -17,7 +17,6 @@
           f:kubectl.kubernetes.io/last-applied-configuration: {}
       f:spec:
         f:progressDeadlineSeconds: {}
-        f:replicas: {}
         f:revisionHistoryLimit: {}
         f:selector: {}
         f:strategy:
@@ -84,13 +83,21 @@
     manager: k3s
     operation: Update
     time: "2021-03-14T14:39:49Z"
+  - apiVersion: apps/v1
+    fieldsType: FieldsV1
+    fieldsV1:
+      f:spec:
+        f:replicas: {}
+    manager: kubectl-client-side-apply
+    operation: Update
+    time: "2021-03-14T14:47:47Z"
   name: nginx
   namespace: language
   resourceVersion: "743562"
   uid: f58929e1-1a69-4f4b-9bee-d6ef6fb4e556
 spec:
   progressDeadlineSeconds: 600
-  replicas: 2
+  replicas: 1
   revisionHistoryLimit: 10
   selector:
     matchLabels:

You can see the additions and removals.

As described in [1], you can even set your favorite external diff tool by setting the KUBECTL_EXTERNAL_DIFF environment variable, for example:

KUBECTL_EXTERNAL_DIFF=meld kubectl diff -f some-resources.yaml

I find really useful this diff tool called Dyff to highlight the changes using different colors and summarizing what is important:

KUBECTL_EXTERNAL_DIFF="dyff between --omit-header --set-exit-code"
$ kubectl diff -f deployments/deployment.nginx.yaml

metadata.generation
  ± value change
    - 1
    + 2

metadata.managedFields
  + one list entry added:
    - apiVersion: apps/v1
    │ fieldsType: FieldsV1
    │ fieldsV1:
    │ │ f:spec:
    │ │ │ f:replicas: {}
    │ manager: kubectl-client-side-apply
    │ operation: Update
    │ time: "2021-03-14T15:36:27Z"

metadata.managedFields.kubectl-create.fieldsV1.f:spec
  - one map entry removed:
    f:replicas: {}

spec.replicas
  ± value change
    - 2
    + 1