In this episode, we'll discuss another important concept in Kubernetes called Annotations. We'll learn how to use Annotations to attach arbitrary metadata to Kubernetes objects.

Note
If you want to read the previous episode, you can click the Episode 6 thumbnail below
In the previous episode, we learned deeply about the Label object in Kubernetes. In episode 7, we'll discuss another important concept that complements Labels: Annotations.
Note: Here I'll be using a Kubernetes Cluster installed through K3s.
While Labels are used for identification and selection of objects, Annotations serve a different purpose. They're designed to attach arbitrary non-identifying metadata to objects. This metadata can be used by tools, libraries, or humans to store additional information about resources without affecting how Kubernetes selects or manages them.
An Annotation is a key-value pair that you attach to Kubernetes objects to store arbitrary metadata. Unlike Labels, Annotations are not used to identify and select objects. Instead, they're used to attach non-identifying information that can be useful for tools, automation, documentation, or operational purposes.
Think of Annotations as sticky notes you attach to objects. These notes contain information that's useful for reference but doesn't affect how the object is selected or grouped. For example, you might add an annotation to record who created a resource, when it was last updated, or what tool was used to deploy it.
Annotations are metadata that help you:
An Annotation consists of two parts:
description, build-version, contact)For example:
description: "Production web server for customer portal"
build-version: "v1.2.3-abc123"
contact: "platform-team@company.com"Annotations follow similar naming rules to Labels, but with some differences:
/)-), underscores (_), and dots (.)Valid examples:
description: "Web application server"
kubernetes.io/change-cause: "Update to version 2.0"
company.com/team: "platform-engineering"
build-info: '{"version":"1.0","commit":"abc123"}'Invalid examples:
-description: "Invalid" # Key starts with hyphen
description-: "Invalid" # Key ends with hyphen
kubernetes.io/-change: "Invalid" # Name part starts with hyphenYou might wonder why we need both Labels and Annotations. The key difference is their purpose:
Consider this scenario: You want to store information about who deployed a Pod, what Git commit it came from, and what Jira ticket authorized the deployment. This information is useful for auditing and troubleshooting, but you don't need to select Pods based on it. This is perfect for Annotations.
Another important distinction is that Labels have strict size limits (63 characters for values), while Annotations can store much larger amounts of data. This makes Annotations suitable for storing structured data like JSON configurations or longer descriptions.
To help you understand when to use Labels vs Annotations, here's a comparison:
| Aspect | Labels | Annotations |
|---|---|---|
| Purpose | Identification and selection | Metadata storage |
| Used by Kubernetes | Yes (for selectors) | No |
| Value size limit | 63 characters | No practical limit |
| Can contain spaces | No | Yes |
| Can contain special chars | Limited | Yes |
| Used for grouping | Yes | No |
| Used for querying | Yes | No |
| Used by tools | Sometimes | Often |
In production Kubernetes environments, there are common annotation patterns that teams use:
These annotations track build and deployment details:
build-version: "v1.2.3"
git-commit: "abc123def456"
git-branch: "main"
build-date: "2026-03-01T10:30:00Z"
deployed-by: "john.doe@company.com"
deployment-tool: "ArgoCD"These annotations provide documentation and contact details:
description: "Production API server for customer portal"
documentation: "https://docs.company.com/api-server"
contact: "platform-team@company.com"
oncall: "https://oncall.company.com/platform"
runbook: "https://runbook.company.com/api-server"These annotations track change management information:
jira-ticket: "PROJ-1234"
change-request: "CHG0012345"
approved-by: "jane.smith@company.com"
kubernetes.io/change-cause: "Update to version 2.0 for security patch"Many Kubernetes tools use annotations for configuration:
# Ingress controller annotations
nginx.ingress.kubernetes.io/rewrite-target: "/"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
# Prometheus monitoring annotations
prometheus.io/scrape: "true"
prometheus.io/port: "9090"
prometheus.io/path: "/metrics"
# Service mesh annotations
sidecar.istio.io/inject: "true"Annotations can store structured configuration data:
config: '{"timeout":30,"retries":3,"backoff":"exponential"}'
feature-flags: '{"new-ui":true,"beta-api":false}'Now let's learn how to add Annotations to Kubernetes objects. There are two main ways to add Annotations:
The most common way is to add Annotations directly in the YAML configuration file under the metadata section:
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
annotations:
description: "Production web server"
build-version: "v1.2.3"
git-commit: "abc123"
contact: "platform-team@company.com"
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80In this example, we've added four annotations to the Pod:
description - A human-readable description of the Podbuild-version - The version of the applicationgit-commit - The Git commit hash used to build the imagecontact - Contact information for the team responsibleYou can also add Annotations to existing objects using the kubectl annotate command:
sudo kubectl annotate pod <pod_name> <key>=<value>For example, to add an annotation to an existing Pod:
sudo kubectl annotate pod nginx-pod description="Production web server"To add multiple annotations at once:
sudo kubectl annotate pod nginx-pod build-version=v1.2.3 git-commit=abc123To overwrite an existing annotation, use the --overwrite flag:
sudo kubectl annotate pod nginx-pod description="Updated description" --overwriteAfter adding Annotations to objects, you can view them using various kubectl commands:
The most common way to view annotations is using the kubectl describe command:
sudo kubectl describe pod nginx-podThe output will include the annotations section:
You can also view annotations in YAML or JSON format:
sudo kubectl get pod nginx-pod -o yamlThe output will show the annotations in the metadata section:
Let's create a practical example where we create Pods with various annotations:
Create a file named annotated-pod.yml:
apiVersion: v1
kind: Pod
metadata:
name: web-app
labels:
app: web
environment: production
annotations:
description: "Production web application server"
version: "2.1.0"
build-date: "2026-03-01T10:00:00Z"
git-commit: "a1b2c3d4e5f6"
git-branch: "main"
deployed-by: "john.doe@company.com"
jira-ticket: "PROJ-1234"
contact: "platform-team@company.com"
documentation: "https://docs.company.com/web-app"
kubernetes.io/change-cause: "Deploy version 2.1.0 with security fixes"
spec:
containers:
- name: web
image: nginx:1.25
ports:
- containerPort: 80sudo kubectl apply -f annotated-pod.ymlsudo kubectl describe pod web-appYou'll see all the annotations we added:
Let's update the version annotation:
sudo kubectl annotate pod web-app version=2.1.1 --overwriteTo remove an annotation, add a minus sign (-) after the key:
sudo kubectl annotate pod web-app jira-ticket-Tip
Don't forget to clean up resources like Pods that are no longer in use so your computer can run other Pods without obstacles. To delete it, you can run the following command
sudo kubectl delete -f annotated-pod.ymlAnnotations are not just used for Pods. You can add Annotations to any Kubernetes object. Here are some common use cases:
Deployments often use annotations to track rollout history:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deployment
annotations:
description: "Web application deployment"
version: "2.0.0"
kubernetes.io/change-cause: "Update to version 2.0"
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
prometheus.io/path: "/metrics"
spec:
containers:
- name: web
image: nginx:1.25
ports:
- containerPort: 80Services use annotations for load balancer configuration:
apiVersion: v1
kind: Service
metadata:
name: web-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
service.beta.kubernetes.io/aws-load-balancer-internal: "true"
description: "Internal load balancer for web application"
spec:
selector:
app: web
ports:
- protocol: TCP
port: 80
targetPort: 80
type: LoadBalancerIngress resources heavily rely on annotations for configuration:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: "/"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
description: "Ingress for web application"
spec:
ingressClassName: nginx
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80One common mistake is trying to use annotations to select objects. Annotations cannot be used with selectors.
Wrong approach:
# This will NOT work
sudo kubectl get pod -l description="Production web server"Correct approach: Use labels for selection, annotations for metadata.
Never store sensitive information like passwords or API keys in annotations. They're visible to anyone who can view the resource.
Solution: Use Kubernetes Secrets for sensitive data.
While annotations can store large amounts of data, don't abuse this capability. Storing too much data in annotations can make resources difficult to manage.
Solution: Keep annotations concise and relevant. Use ConfigMaps or external storage for large configuration data.
Many tools expect specific annotation keys. Using non-standard keys can break tool integrations.
Solution: Follow Kubernetes conventions and tool documentation for annotation keys.
When creating custom annotations, use a domain prefix to avoid conflicts:
apiVersion: v1
kind: Pod
metadata:
name: app-pod
annotations:
company.com/team: "platform"
company.com/cost-center: "engineering"
company.com/project: "web-app"
spec:
containers:
- name: app
image: nginxCreate documentation for your team about what annotations to use and when. This ensures consistency across your cluster.
Track changes and deployments using annotations:
apiVersion: v1
kind: Pod
metadata:
name: app-pod
annotations:
deployed-at: "2026-03-01T10:30:00Z"
deployed-by: "john.doe@company.com"
deployment-tool: "kubectl"
change-ticket: "CHG0012345"
approved-by: "jane.smith@company.com"
spec:
containers:
- name: app
image: nginxFor complex configuration, use JSON or YAML in annotation values:
apiVersion: v1
kind: Pod
metadata:
name: app-pod
annotations:
config: '{"timeout":30,"retries":3,"backoff":"exponential"}'
feature-flags: '{"new-ui":true,"beta-api":false,"dark-mode":true}'
spec:
containers:
- name: app
image: nginxUse labels for identification and selection, annotations for metadata:
apiVersion: v1
kind: Pod
metadata:
name: app-pod
labels:
app: web
environment: production
tier: frontend
annotations:
description: "Production web server"
version: "2.1.0"
contact: "platform-team@company.com"
spec:
containers:
- name: app
image: nginxWhile annotations are useful, there are cases where you shouldn't use them:
In episode 7, we've explored the Annotation concept in Kubernetes in depth. We've learned what annotations are, how they differ from labels, how to add them to objects, and best practices for using them effectively.
Annotations are a powerful feature that allows you to attach arbitrary metadata to Kubernetes objects. They're essential for storing build information, documentation, tool configuration, and audit trails. By understanding the difference between labels and annotations, you can use each feature appropriately to make your Kubernetes cluster more manageable and well-documented.
While labels help Kubernetes identify and select objects, annotations help humans and tools understand and manage those objects. Together, they provide a complete metadata system for your cluster resources.
Are you getting a clearer understanding of Annotations in Kubernetes? In the next episode 8, we'll discuss another important Kubernetes concept: Namespace. Namespaces provide a way to divide cluster resources between multiple users or teams. Keep your learning momentum going and look forward to the next episode!