All posts
Emire Barış profile photoEmire Barış · Member3 min read

Kubernetes labels and selectors explained (the glue between objects)

Labels and selectors in Kubernetes: how Deployments label Pods, how Services find them, kubectl -l and endpoints checks, common mistakes, and optional kprompt examples.

You already know Pods, Deployments, and Services — see Pods vs Deployments and Services if you need a refresher. Namespaces scope where objects live. Labels and selectors are how Kubernetes connects those objects: which Pods belong to a Deployment, and which Pods a Service sends traffic to.

This guide explains labels on Pods and Deployments, selectors on Services, the kubectl commands that make the link visible, and the mistakes that leave Endpoints empty even when everything looks Running.

The one-sentence version

  • A label is key/value metadata on an object (for example app: api).
  • A selector is a filter: “give me objects with these labels.”
  • Deployment Pod template labels must match the Service selector — or traffic never reaches your Pods.

What is a label?

Labels are arbitrary key/value pairs attached to Kubernetes objects. They do not change how a container runs by themselves — they organize and select objects. Controllers, Services, and kubectl -l all rely on them.

Labels on a Pod (metadata.labels)

apiVersion: v1
kind: Pod
metadata:
  name: api-manual
  labels:
    app: api
    tier: backend
    env: staging
spec:
  containers:
    - name: api
      image: nginx:1.27

On a Deployment, labels appear in two places beginners confuse: metadata.labels on the Deployment object itself (optional, for your own organization) and spec.template.metadata.labels on the Pod template (required for Services to target the Pods the Deployment creates).

What is a selector?

A selector is a label query. A Service uses spec.selector to decide which Pods receive traffic. kubectl uses -l the same way. ReplicaSets (owned by Deployments) also use selectors to know which Pods they own.

Service selector must match Pod labels

apiVersion: v1
kind: Service
metadata:
  name: api
spec:
  selector:
    app: api          # must match Pod template labels
  ports:
    - port: 80
      targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 2
  selector:
    matchLabels:
      app: api        # ReplicaSet watches Pods with this label
  template:
    metadata:
      labels:
        app: api      # Pods get this label — Service must match here
    spec:
      containers:
        - name: api
          image: nginx:1.27
          ports:
            - containerPort: 8080

How Deployment and Service connect

The mental model from Service vs Deployment still applies: the Deployment keeps Pods alive; the Service gives them a stable address. Labels are the wire between them. Scale the Deployment and new Pods inherit template labels — the Service picks them up automatically.

Mental model

Deployment "api"
  └── Pod template labels: app=api
        ├── Pod api-7f8c9d-xk2lm  labels: app=api
        └── Pod api-7f8c9d-mn4pq  labels: app=api

Service "api"  selector: app=api
        │
        └── Endpoints → both Pod IPs

kubectl commands that stick

These four commands are the beginner debugging loop for “Service exists but nothing works.” Run them in order before you change YAML.

See labels, selectors, and Endpoints

# 1) What labels do my Pods have?
kubectl get pods -n staging --show-labels
kubectl get pods -l app=api -n staging

# 2) What does the Service select?
kubectl get svc api -n staging -o yaml | grep -A3 selector

# 3) Which Pod IPs are registered?
kubectl get endpoints api -n staging
kubectl get endpointslices -l kubernetes.io/service.name=api -n staging

# 4) Do Pod labels match the Service selector?
kubectl get pods -n staging -l app=api --show-labels
kubectl describe svc api -n staging

Reading Endpoints output

Endpoints (or EndpointSlices) list the Pod IPs behind a Service. If ADDRESSES is empty or <none>, the Service selector did not match any Pod — even if kubectl get pods shows Running Pods with a similar name.

Healthy vs broken

# Healthy — Pod IPs listed
NAME   ENDPOINTS                     AGE
api    10.244.1.12:8080,10.244.2.8:8080   5m

# Broken — selector mismatch (very common)
NAME   ENDPOINTS   AGE
api    <none>      5m

matchLabels vs matchExpressions (beginner view)

  • matchLabels — equality only (app: api). Enough for most apps.
  • matchExpressions — In, NotIn, Exists, DoesNotExist for advanced filtering.
  • Beginners: make Deployment template labels and Service selector identical with matchLabels first.

matchExpressions example (optional)

selector:
  matchExpressions:
    - key: app
      operator: In
      values:
        - api
        - api-canary

Common beginner mistakes

  • Labels on the Deployment metadata but not on spec.template.metadata.labels — Service cannot see them on Pods
  • Typo: app: api on Pods but app:api or app: Api on the Service selector (labels are case-sensitive)
  • Changing the Service name and assuming DNS follows Pod names — clients dial the Service name; labels do the matching
  • Running Pods from an old ReplicaSet after a label change — Endpoints update only for Pods that still match
  • Using kubectl get pods without -l and missing that the Running Pod has different labels than you think

When labels matter beyond Services

  • kubectl logs and exec with -l app=api — target the right Pod among replicas
  • NetworkPolicy and some Ingress controllers select workloads by labels
  • Prometheus ServiceMonitor and Helm charts often assume standard labels like app.kubernetes.io/name

Same checks in natural language (optional)

kprompt resolves label phrases in read prompts. Mutations still show a plan and ask for approval on a TTY.

Soft kprompt examples

kprompt "list pods with label app=api in staging"
kprompt "describe service api in staging"
kprompt "get endpoints for api in staging"
kprompt "explain why service api has no endpoints in staging"

What to learn next

Labels connect Deployments to Services. Next, configure apps with ConfigMaps and Secrets (env vars and mounted files). For deeper kubectl reading, see kubectl get pods explained and the troubleshooting guides when Pods misbehave.