Categories
Best Practices DevOps

Kubernetes Labels Demo

You’ve most likely stumbled on Kubernetes labels while writing deployment manifests. What are they for and how to use them? As always we’ll see a practical demo to answer these questions. Keep reading to find out more.

Introduction

Previously we have seen that Kubernetes Namespaces allow to logically group Kubernetes resources. Today we’ll see another way to organize resources – Kubernetes labels.

In short, Kubernetes labels allow to mark certain API objects. This in turn allows you to search for them easily. Kubernetes internally uses labels as well. For example, Kubernetes controllers manage the desired state of only specific pods, labeled ones. Similarly, Kubernetes Services will forward requests to labeled pods only.

You can even influence Kubernetes scheduling decisions by labeling Kubernetes nodes and instructing pods to run there. 

Let’s see a Kubernetes labels demo in order to better understand what we’ve just discussed.

Demo Prerequisites

I assume you have Kubernetes cluster. If you don’t, install on your machine minikube and kubectl.

Start Kubernetes cluster using minikube start --nodes 2 -p multinode-demo.

If you prefer, you can also repeat this demo on a managed Kubernetes cluster. Check out how easy it is to create Kubernetes Cluster on Linode. Get 100$ credit on Linode using this link. Linode is a cloud service provider recently purchased by Akamai. With this purchase, Akamai became a competitor in the cloud providers market.

Kubernetes labels demo

Let’s create dedicated Kubernetes namespace for our demo and set current context to use it:

kubectl create ns demo
kubectl config set-context  --current --namespace=demo

Unless you had such namespace before, there should be no resources in it:

kubectl get all
No resources found in demo namespace.

Next, create nginx deployment:

$kubectl create deploy nginx --image=nginx:1.13.2 --replicas=3
deployment.apps/nginx created

Where do labels fit it?

$ kubectl get all --show-labels 
NAME                         READY   STATUS    RESTARTS   AGE     LABELS
pod/nginx-6d67674bb5-ks4hp   1/1     Running   0          2m41s   app=nginx,pod-template-hash=6d67674bb5
pod/nginx-6d67674bb5-lql8z   1/1     Running   0          2m41s   app=nginx,pod-template-hash=6d67674bb5
pod/nginx-6d67674bb5-xkxvg   1/1     Running   0          2m41s   app=nginx,pod-template-hash=6d67674bb5

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE     LABELS
deployment.apps/nginx   3/3     3            3           2m41s   app=nginx

NAME                               DESIRED   CURRENT   READY   AGE     LABELS
replicaset.apps/nginx-6d67674bb5   3         3         3       2m41s   app=nginx,pod-template-hash=6d67674bb5

You can see above that after we created a deployment few objects were created. nginx deployment, its corresponding replica set and pods – all have got labels.

Let’s create another nginx deployment:

$ kubectl create deploy nginx2 --image=nginx:1.13.2 --replicas=2
deployment.apps/nginx2 created

Labels allow to filter pods belonging only to specific deployment:

$ kubectl get pods -l app=nginx
NAME                     READY   STATUS    RESTARTS   AGE
nginx-6d67674bb5-ks4hp   1/1     Running   0          16m
nginx-6d67674bb5-lql8z   1/1     Running   0          16m
nginx-6d67674bb5-xkxvg   1/1     Running   0          16m

Note that Kubernetes deployment uses selectors to select its pods.

kubectl get deployments.apps nginx -o jsonpath='{.spec.selector}'
{"matchLabels":{"app":"nginx"}}

Let’s delete the nginx2 deployment in order to avoid confusion using kubectl delete deployments.apps nginx2.

Use Kubernetes labels for debugging

In addition, we can use labels for debugging. Let’s label one of the pods with app=debug label.

kubectl label pod/nginx-557f57675f-d2t8s app=debug --overwrite
pod/nginx-557f57675f-d2t8s labeled

Let’s see now how many pods we have in nginx deployment.

$ kubectl get all --show-labels
NAME                          READY   STATUS    RESTARTS   AGE     LABELS
pod/nginx-6d67674bb5-2mqnc    1/1     Running   0          8m20s   app=debug,pod-template-hash=6d67674bb5
pod/nginx-6d67674bb5-6pnpf    1/1     Running   0          8m19s   app=nginx,pod-template-hash=6d67674bb5
pod/nginx-6d67674bb5-9r5td    1/1     Running   0          5s      app=nginx,pod-template-hash=6d67674bb5
pod/nginx-6d67674bb5-lpgdx    1/1     Running   0          8m20s   app=nginx,pod-template-hash=6d67674bb5

NAME                     READY   UP-TO-DATE   AVAILABLE   AGE   LABELS
deployment.apps/nginx    3/3     3            3           25h   app=nginx

NAME                                DESIRED   CURRENT   READY   AGE   LABELS
replicaset.apps/nginx-6d67674bb5    3         3         3       25h   app=nginx,pod-template-hash=6d67674bb5

Interestingly, we see 4 nginx pods running while expecting only 3. Was our expectation correct? No, because the desired state of nginx deployment is 3 replicas. That’s why, nginx replica set controller has spun up a new nginx pod with label app=nginx instead of the one we labeled for debugging with app=debug.

Let’s now expose the deployment as Kubernetes service.

$kubectl expose deployment/nginx --port 8090 --target-port 80
service/nginx exposed

$kubectl get service nginx --show-labels 
NAME    TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE     LABELS
nginx   ClusterIP   10.97.185.55   <none>        8090/TCP   2m45s   app=nginx

As you can see the service has the same label app=nginx as the pods. Of course, it uses the same selector {"app":"nginx"} as the deployment.

$kubectl get service nginx -o jsonpath='{.spec.selector}'
{"app":"nginx"}

Note, that the pod labeled for debugging won’t get the traffic directed at the service.

Suppose we finished to debug. Let’s now get the pod back into service.

$ kubectl label pod/nginx-6d67674bb5-2mqnc app=nginx --overwrite
pod/nginx-6d67674bb5-2mqnc labeled

We can see now that there are only 3 nginx pods as expected.

$ kubectl get all --show-labels -l app=nginx
NAME                         READY   STATUS    RESTARTS   AGE   LABELS
pod/nginx-6d67674bb5-2mqnc   1/1     Running   0          28m   app=nginx,pod-template-hash=6d67674bb5
pod/nginx-6d67674bb5-9r5td   1/1     Running   0          20m   app=nginx,pod-template-hash=6d67674bb5
pod/nginx-6d67674bb5-lpgdx   1/1     Running   0          28m   app=nginx,pod-template-hash=6d67674bb5

Influence scheduling decisions using Kubernetes labels

Let’s now see another great use of labels – control of scheduling decisions. For that purpose, we’ll label Kubernetes node and force nginx pods to be scheduled to this specific node.

However, first let’s see the nodes the pods run on:

$ kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP            NODE                 NOMINATED NODE   READINESS GATES
nginx-6d67674bb5-2mqnc   1/1     Running   0          47m   10.244.0.8    multinode-demo       <none>           <none>
nginx-6d67674bb5-9r5td   1/1     Running   0          39m   10.244.1.4    multinode-demo-m02   <none>           <none>
nginx-6d67674bb5-lpgdx   1/1     Running   0          47m   10.244.0.11   multinode-demo       <none>           <none>

Next, let’s label one of the nodes where nginx should run:

$ kubectl label node multinode-demo app=nginx
node/multinode-demo labeled

It’s not enough. We should add nodeSelector to nginx deployment pod template spec.

Let’s do that imperatively for demo purposes:

$ kubectl edit deployments.apps nginx

Your system text editor should open. Let’s add the below block to deployment’s pod template spec and save.

      nodeSelector:
        app: nginx

You should see deployment.apps/nginx edited output.

Next, we’ll watch what happens:

$ kubectl get pod -o wide -w

Eventually, all nginx pods should reach their new desired state, e.g. be placed on multinode-demo node:

NAME                     READY   STATUS    RESTARTS   AGE     IP            NODE             NOMINATED NODE   READINESS GATES
nginx-67fc9bd7c9-qctb4   1/1     Running   0          5m4s    10.244.0.13   multinode-demo   <none>           <none>
nginx-67fc9bd7c9-r6kzp   1/1     Running   0          5m2s    10.244.0.14   multinode-demo   <none>           <none>
nginx-67fc9bd7c9-s8ft7   1/1     Running   0          4m59s   10.244.0.15   multinode-demo   <none>           <none>

To abide by configuration as code principles, one should declare Kubernetes Deployments using yaml and put nodeSelector constraint there.

You may rightfully ask, what are pod-template-hash=67fc9bd7c9 labels in replicaSets and pods. Don’t worry, we’ll cover their roles in future posts when we explore Kubernetes controllers.

Finally let’s leave our minikube cluster tidy by simply removing demo namespace. It will remove all the resources we created throughout the demo.

$ kubectl delete ns demo
namespace "demo" deleted

Summary

That’s it about Kubernetes labels. As always, feel free to share and comment.

Watch recommended Kubernetes courses on Pluralsight:

Sign up using this link to get exclusive discounts like 50% off your first month or 15% off an annual subscription)

Read recommended Kubernetes books on Amazon: