Table of Contents
Kubernetes provides two basic ways to document your infrastructure—labels and annotations. We have used labels in some of the examples in previous articles, but here I will explain the usage of labels and other related terminologies.
Labels
- Labels give us another level of categorization, which becomes very helpful in terms of everyday operations and management.
- Labels are attached to Kubernetes objects and are simple key: value pairs.
- You will see them on pods, replication controllers, replica sets, services, and so on.
- Labels themselves and the keys/values inside of them are based on a constrained set of variables, so that queries against them can be evaluated efficiently using optimized algorithms and data structures.
- Labels are used for organization and selection of subsets of objects, and can be added to objects at creation time and/or modified at any time during cluster operations.
Let’s use an easy example to demonstrate. Suppose you wanted to identify a pod as being part of the front-end tier of your application. You might create a label named tier and assign it a value of frontend—like so:
“labels”: { “tier”: “frontend” }
The text “tier
” is the key, and the text “frontend
” is the value.
Selectors
Labels are queryable — which makes them especially useful in organizing things. The mechanism for this query is a label selector. A label selector is a string that identifies which labels you are trying to match. There are currently two types of selectors: equality-based and set-based selectors.
Equality-based selector
An equality-based test is just a “IS/IS NOT” test. For example:
tier = frontend
will return all pods that have a label with the key “tier” and the value “frontend”. On the other hand, if we wanted to get all the pods that were not in the frontend tier, we would say:
tier != frontend
You can also combine requirements with commas like so:
tier != frontend, game = super-shooter-2
This would return all pods that were part of the game named super-shooter-2
but were not in its frontend
tier.
Set-based selectors
Set-based tests, on the other hand, are of the “IN/NOT IN” variety. For example:
environment in (production, qa) tier notin (frontend, backend) partition
The first test returns pods that have the environment
label and a value of either production
or qa
. The next test returns all the pods not in the frontend
or backend
tiers. Finally, the third test will return all pods that have the partition
label—no matter what value it contains.
Like equality-based tests, these can also be combined with commas to perform an AND operation like so:
environment in (production, qa), tier notin (frontend, backend), partition
This test returns all pods that are in either the production
or qa
environment, also not in either the frontend
or backend
tiers, and have a partition
label of some kind.
Annotations
Annotations are bits of useful information you might want to store about a pod (or cluster, node, etc.) that you will not have to query against. They are also key/value pairs and have the same rules as labels.
Examples of things you might put there are the pager contact, the build date, or a pointer to more information someplace else—like a URL.
Labels are used to store identifying information about a thing that you might need to query against. Annotations are used to store other arbitrary information that would be handy to have close but won’t need to be filtered or searched.
Assigning a label to a Deployment
Method-1: Assign labels while creating a new object
It is always a good idea to use YAML template from any of the existing resource object. Since we plan to create a deployment, I can use a YAML template from any of the existing template but if you don't have any existing template then you can create one using --dry-run
and export the template into another YAML file:
[root@controller ~]# kubectl create deployment label-nginx-example --image=nginx --dry-run=client -o yaml > label-nginx-example.yml
So we now have a template file for a new deployment with following content:
[root@controller ~]# cat label-nginx-example.yml apiVersion: apps/v1 kind: Deployment metadata: creationTimestamp: null labels: app: label-nginx-example name: label-nginx-example spec: replicas: 1 selector: matchLabels: app: label-nginx-example strategy: {} template: metadata: creationTimestamp: null labels: app: label-nginx-example spec: containers: - image: nginx name: nginx resources: {} status: {}
We can perform clean up in this file and remove some unwanted content. You can see that by default kubectl
has created and assigned a label app: label-nginx-example
, I will replace that and assign a new label to our deployment as app: prod
.
[root@controller ~]# cat label-nginx-example.yml apiVersion: apps/v1 kind: Deployment metadata: labels: app: prod name: label-nginx-example spec: replicas: 2 selector: matchLabels: app: prod template: metadata: labels: app: prod spec: containers: - image: nginx name: nginx
Next let us create a new deployment:
[root@controller ~]# kubectl create -f label-nginx-example.yml
deployment.apps/label-nginx-example created
List the available deployments with their labels:
[root@controller ~]# kubectl get deployments --show-labels NAME READY UP-TO-DATE AVAILABLE AGE LABELS label-nginx-example 2/2 2 2 3m12s app=prod nginx-deploy 2/2 2 2 22h type=dev
List the available pods with their labels:
[root@controller ~]# kubectl get pods --show-labels NAME READY STATUS RESTARTS AGE LABELS label-nginx-example-5c57d87787-qjmhw 1/1 Running 0 4m36s app=prod,pod-template-hash=5c57d87787 label-nginx-example-5c57d87787-vsjv5 1/1 Running 0 4m36s app=prod,pod-template-hash=5c57d87787 nginx-deploy-d98cc8bdb-48ppw 1/1 Running 1 22h pod-template-hash=d98cc8bdb,type=dev nginx-deploy-d98cc8bdb-nvcb5 1/1 Running 1 22h pod-template-hash=d98cc8bdb,type=dev
Method-2: Assign a new label to existing pod runtime as a patch
In this example we will assign new label "tier: frontend" to our existing Pods from the deployment label-nginx-example
which we created in the previous example. To achieve this we need to create a spec file with the required properties:
[root@controller ~]# cat update-label.yml
spec:
template:
metadata:
labels:
tier: frontend
Next patch the deployment with this YAML file:
[root@controller ~]# kubectl patch deployment label-nginx-example --patch "$(cat update-label.yml)"
deployment.apps/label-nginx-example patched
Now you can use kubectl describe
to check if our label was applied to the deployment:
[root@controller ~]# kubectl describe deployment label-nginx-example
Name: label-nginx-example
Namespace: default
CreationTimestamp: Thu, 03 Dec 2020 11:35:15 +0530
Labels: app=prod
Annotations: deployment.kubernetes.io/revision: 2
Selector: app=prod
Replicas: 2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=prod
tier=frontend
...
This would apply the label to the Pod:
[root@controller ~]# kubectl get pods --show-labels NAME READY STATUS RESTARTS AGE LABELS label-nginx-example-79fdbb7d49-sd82d 1/1 Running 0 8m26s app=prod,pod-template-hash=79fdbb7d49,tier=frontend label-nginx-example-79fdbb7d49-wf2c4 1/1 Running 0 8m18s app=prod,pod-template-hash=79fdbb7d49,tier=frontend nginx-deploy-d98cc8bdb-48ppw 1/1 Running 1 22h pod-template-hash=d98cc8bdb,type=dev nginx-deploy-d98cc8bdb-nvcb5 1/1 Running 1 22h pod-template-hash=d98cc8bdb,type=dev
Method-3: Assign a new label to existing deployments runtime using kubectl
In this example we can assign a new label runtime using kubectl
command to our deployment. I have another deployment nginx-deploy
on my cluster, so I will assign label tier: backend
to this deployment:
[root@controller ~]# kubectl label deployment nginx-deploy tier=backend deployment.apps/nginx-deploy labeled
Verify if the label was applied successfully:
[root@controller ~]# kubectl get deployments --show-labels
NAME READY UP-TO-DATE AVAILABLE AGE LABELS
label-nginx-example 2/2 2 2 14m app=prod
nginx-deploy 2/2 2 2 22h tier=backend,type=dev
Using labels to list resource objects
Now I have already used some of these commands in previous example but let me summarise all here again for your reference.
To list all the pods with their label details:
[root@controller ~]# kubectl get pods --show-labels NAME READY STATUS RESTARTS AGE LABELS label-nginx-example-79fdbb7d49-sd82d 1/1 Running 0 8m26s app=prod,pod-template-hash=79fdbb7d49,tier=frontend label-nginx-example-79fdbb7d49-wf2c4 1/1 Running 0 8m18s app=prod,pod-template-hash=79fdbb7d49,tier=frontend nginx-deploy-d98cc8bdb-48ppw 1/1 Running 1 22h pod-template-hash=d98cc8bdb,type=dev nginx-deploy-d98cc8bdb-nvcb5 1/1 Running 1 22h pod-template-hash=d98cc8bdb,type=dev
To list all the deployments with their label details:
[root@controller ~]# kubectl get deployments --show-labels NAME READY UP-TO-DATE AVAILABLE AGE LABELS label-nginx-example 2/2 2 2 19m app=prod nginx-deploy 2/2 2 2 22h tier=backend,type=dev
To list all resources with assigned labels:
[root@controller ~]# kubectl get all --show-labels NAME READY STATUS RESTARTS AGE LABELS pod/label-nginx-example-79fdbb7d49-sd82d 1/1 Running 0 9m8s app=prod,pod-template-hash=79fdbb7d49,tier=frontend pod/label-nginx-example-79fdbb7d49-wf2c4 1/1 Running 0 9m app=prod,pod-template-hash=79fdbb7d49,tier=frontend pod/nginx-deploy-d98cc8bdb-48ppw 1/1 Running 1 22h pod-template-hash=d98cc8bdb,type=dev pod/nginx-deploy-d98cc8bdb-nvcb5 1/1 Running 1 22h pod-template-hash=d98cc8bdb,type=dev NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE LABELS service/kubernetes ClusterIP 10.96.0.1 443/TCP 5d12h component=apiserver,provider=kubernetes NAME READY UP-TO-DATE AVAILABLE AGE LABELS deployment.apps/label-nginx-example 2/2 2 2 19m app=prod deployment.apps/nginx-deploy 2/2 2 2 22h tier=backend,type=dev NAME DESIRED CURRENT READY AGE LABELS replicaset.apps/label-nginx-example-5c57d87787 0 0 0 19m app=prod,pod-template-hash=5c57d87787 replicaset.apps/label-nginx-example-79fdbb7d49 2 2 2 9m8s app=prod,pod-template-hash=79fdbb7d49,tier=frontend replicaset.apps/nginx-deploy-d98cc8bdb 2 2 2 22h pod-template-hash=d98cc8bdb,type=dev
To list all the deployments using type: dev
label:
[root@controller ~]# kubectl get deployments -l type=dev
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deploy 2/2 2 2 22h
To list all the pods using app: prod
label:
[root@controller ~]# kubectl get pods -l app=prod
NAME READY STATUS RESTARTS AGE
label-nginx-example-79fdbb7d49-sd82d 1/1 Running 0 12m
label-nginx-example-79fdbb7d49-wf2c4 1/1 Running 0 12m
Using selector to list resource objects
In this section we will use selectors to list the deployments and pods. The pod's selector determines where the ReplicaSet
is running, so in our examples we have defined selector when creating a deployment.
But to demonstrate, I will create another deployment here with two labels and use one of the label as selector:
[root@controller ~]# cat lab-nginx.yml apiVersion: apps/v1 kind: Deployment metadata: labels: app: dev tier: backend name: lab-nginx spec: replicas: 2 selector: matchLabels: app: dev template: metadata: labels: app: dev spec: containers: - image: nginx name: nginx
Now we will create this deployment:
[root@controller ~]# kubectl create -f lab-nginx.yml
deployment.apps/lab-nginx created
List the applied labels to the newly created pods and deployment:
[root@controller ~]# kubectl get pods --show-labels NAME READY STATUS RESTARTS AGE LABELS lab-nginx-58f9bf94f7-df24l 0/1 ContainerCreating 0 34s app=dev,pod-template-hash=58f9bf94f7 lab-nginx-58f9bf94f7-pc8zf 1/1 Running 0 34s app=dev,pod-template-hash=58f9bf94f7 label-nginx-example-79fdbb7d49-sd82d 1/1 Running 0 52m app=prod,pod-template-hash=79fdbb7d49,tier=frontend label-nginx-example-79fdbb7d49-wf2c4 1/1 Running 0 52m app=prod,pod-template-hash=79fdbb7d49,tier=frontend nginx-deploy-d98cc8bdb-48ppw 1/1 Running 1 23h pod-template-hash=d98cc8bdb,type=dev nginx-deploy-d98cc8bdb-nvcb5 1/1 Running 1 23h pod-template-hash=d98cc8bdb,type=dev [root@controller ~]# kubectl get deployments --show-labels NAME READY UP-TO-DATE AVAILABLE AGE LABELS lab-nginx 0/2 2 0 15s app=dev,tier=backend label-nginx-example 2/2 2 2 62m app=prod nginx-deploy 2/2 2 2 23h tier=backend,type=dev
So, all the pods from our lab-nginx
deployment has two labels but is using app=dev
as the selector so we can use this to filter the list of pods:
[root@controller ~]# kubectl get pods --selector "app=dev"
NAME READY STATUS RESTARTS AGE
lab-nginx-58f9bf94f7-df24l 1/1 Running 0 18m
lab-nginx-58f9bf94f7-pc8zf 1/1 Running 0 18m
But will we get any output if we use tier: backend as the selector:
[root@controller ~]# kubectl get pods --selector "tier=backend"
No resources found in default namespace.
No resources found as we are using app=dev as our selector for the pods part of lab-nginx
deployment.
To list all the deployments with selector app: prod
[root@controller ~]# kubectl get deployments --selector "app=prod"
NAME READY UP-TO-DATE AVAILABLE AGE
label-nginx-example 2/2 2 2 32m
In the last example we used equality-based
selector to filter the available deployments, now we will use set-based
selector:
[root@controller ~]# kubectl get deployments --selector "app in (prod, dev)"
NAME READY UP-TO-DATE AVAILABLE AGE
lab-nginx 2/2 2 2 21m
label-nginx-example 2/2 2 2 83m
Removing labels
We can also remove a label from a resource object using following syntax:
]# kubectl label <resource-type> <resource> <label-key>-
For example to remove label app: dev from pods created by lab-nginx
deployment:
[root@controller ~]# kubectl label pod lab-nginx-58f9bf94f7-pc8zf app-
pod/lab-nginx-58f9bf94f7-pc8zf labeled
As soon as we remove the selector label from the Pod, replicaset will create another Pod to fulfil the replica requirement of the deployment. Since lab-nginx
expects two replica pods with label app=dev
, another one will be created as soon as we remove label from existing Pod:
[root@controller ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
lab-nginx-58f9bf94f7-df24l 1/1 Running 0 106m app=dev,pod-template-hash=58f9bf94f7
lab-nginx-58f9bf94f7-fbkc2 0/1 ContainerCreating 0 3s app=dev,pod-template-hash=58f9bf94f7
lab-nginx-58f9bf94f7-pc8zf 1/1 Running 0 106m pod-template-hash=58f9bf94f7
...
So as expected, you can see that as soon as I removed the app label from exiting lab-nginx
Pod, a new one is getting created.
Similarly, we can also remove label from a deployment:
[root@controller ~]# kubectl get deployments --show-labels
NAME READY UP-TO-DATE AVAILABLE AGE LABELS
lab-nginx 2/2 2 2 107m app=dev,tier=backend
label-nginx-example 2/2 2 2 169m app=prod
nginx-deploy 2/2 2 2 25h tier=backend,type=dev
Now we remove app label from this deployment:
[root@controller ~]# kubectl label deployment lab-nginx app-
deployment.apps/lab-nginx labeled
Verify the available set of label of your deployment:
[root@controller ~]# kubectl get deployments --show-labels
NAME READY UP-TO-DATE AVAILABLE AGE LABELS
lab-nginx 2/2 2 2 107m tier=backend
label-nginx-example 2/2 2 2 170m app=prod
nginx-deploy 2/2 2 2 25h tier=backend,type=dev
Conclusion
In this Kubernetes Tutorial we learned about the usage of labels, selector and annotation using different examples. To summarise, labels and annotation help you organize the Pods once your cluster size grows in size and scope. These are mostly used with replication controllers and replica sets in a deployment. You also learned that we can assign/modify/remove labels from different Kubernetes resource runtime.