Skip to main content
mastering ckad certified kubernetes application developer

Namespaces, Labels, Selectors, and kubectl explain

10 min read Chapter 12 of 87
Summary

Covers Kubernetes namespaces for logical isolation, labels and...

Covers Kubernetes namespaces for logical isolation, labels and annotations for metadata, equality-based and set-based selectors for filtering, and kubectl explain as the built-in manifest reference for the exam.

Namespaces, Labels, Selectors, and kubectl explain

Kubernetes gives you four organizational tools that appear in nearly every exam task: namespaces partition a cluster into logical segments, labels tag resources with queryable key-value pairs, selectors filter resources by those labels, and kubectl explain provides built-in documentation for every field in every manifest. Mastering these primitives is not optional — they are the grammar of Kubernetes resource management.

Namespaces: Logical Isolation

A namespace is a virtual partition within a Kubernetes cluster. Resources in one namespace are invisible to queries against another namespace (unless you explicitly ask for all namespaces). Namespaces provide:

  • Scope isolation — two Pods in different namespaces can have the same name without conflict.
  • Access control boundaries — RBAC policies can restrict users to specific namespaces.
  • Resource quota boundaries — you can cap CPU, memory, and object counts per namespace.

Every cluster starts with four namespaces:

NamespacePurpose
defaultWhere resources land if you do not specify a namespace
kube-systemControl plane components (API server, scheduler, CoreDNS)
kube-publicPublicly readable data (rarely used directly)
kube-node-leaseNode heartbeat leases for failure detection

The Default Namespace Pitfall

When a task does not specify a namespace, kubectl targets default. When a task does specify a namespace (and exam tasks almost always do), you must include -n <namespace> in every command — or set the namespace context before starting the task.

This is the most common mistake on the CKAD: creating the right resource in the wrong namespace. The scoring is binary — if the grader checks namespace finance and your Pod is in default, you get zero points.

Creating and Managing Namespaces

# Create a namespace imperatively
kubectl create ns dev

# Create a namespace from YAML
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
  name: staging
EOF

# List all namespaces
kubectl get ns

# Delete a namespace (deletes ALL resources inside it)
kubectl delete ns dev

Warning: Deleting a namespace is a cascading operation. Every Pod, Service, ConfigMap, and Secret inside that namespace is destroyed. There is no undo.

Setting Your Default Namespace

Instead of typing -n dev on every command, set the namespace for your current context:

kubectl config set-context --current --namespace=dev

Now every kubectl command targets the dev namespace unless you override with -n. On the exam, run this immediately when a task specifies a namespace. It prevents the “right resource, wrong namespace” failure mode.

Verify your current context:

kubectl config get-contexts

The NAMESPACE column shows your active default. If it is blank, you are targeting default.

Labels: Queryable Metadata

Labels are key-value pairs attached to resources. They serve one critical purpose: identification for selection. Services route traffic to Pods based on labels. Deployments manage Pods based on labels. NetworkPolicies target Pods based on labels. Without labels, Kubernetes has no way to express “this group of resources belongs together.”

Label Syntax Rules

  • Keys can include an optional prefix and a required name: app.kubernetes.io/name or app.
  • Prefixes must be DNS subdomains (e.g., company.com/). The kubernetes.io/ and k8s.io/ prefixes are reserved.
  • Names must be 63 characters or fewer, start and end with alphanumeric characters, and can include -, _, and . internally.
  • Values follow the same 63-character alphanumeric rules.

Adding Labels

Labels can be set in the manifest or added after creation:

# In a manifest
apiVersion: v1
kind: Pod
metadata:
  name: web-server
  labels:
    app: nginx
    env: prod
    tier: frontend
spec:
  containers:
    - name: nginx
      image: nginx:1.25
# Add a label to a running Pod
kubectl label pod web-server version=v2

# Overwrite an existing label
kubectl label pod web-server env=staging --overwrite

# Remove a label (note the trailing minus sign)
kubectl label pod web-server version-

Common Label Conventions

Kubernetes recommends a standard set of labels for application identification:

LabelExample ValuePurpose
app.kubernetes.io/namenginxApplication name
app.kubernetes.io/version1.25.0Application version
app.kubernetes.io/componentwebserverRole within the architecture
app.kubernetes.io/part-ofecommerceHigher-level application

On the exam, you will typically use short-form labels (app, env, tier) for speed. In production, the prefixed form provides structure across teams.

Annotations: Metadata for Tools

Annotations look like labels — key-value pairs in metadata — but they serve a different purpose. Annotations store non-identifying metadata: build timestamps, git commit hashes, configuration for ingress controllers, tool-specific directives.

metadata:
  name: web-server
  annotations:
    build.company.com/commit: "a1b2c3d"
    build.company.com/timestamp: "2025-01-15T10:30:00Z"
    nginx.ingress.kubernetes.io/rewrite-target: /

The key difference: labels are for selectors, annotations are not. You cannot query resources by annotation value with kubectl get -l. Annotations have no length limit on values (labels are capped at 63 characters), which makes them suitable for structured data like JSON configuration blobs.

# Add an annotation
kubectl annotate pod web-server description="Primary frontend server"

# Remove an annotation
kubectl annotate pod web-server description-

Exam relevance: The CKAD occasionally requires setting annotations, particularly for Ingress resources. Know how to add them imperatively and in YAML.

Selectors: Filtering by Labels

Selectors are the query language for labels. Every time Kubernetes needs to find “which Pods does this Service target?” or “which Pods does this NetworkPolicy apply to?”, it uses a selector.

Equality-Based Selectors

Match labels using =, == (identical to =), or !=:

# Get all Pods where app equals nginx
kubectl get pods -l app=nginx

# Get all Pods where env does NOT equal prod
kubectl get pods -l env!=prod

# Combine multiple conditions (AND logic)
kubectl get pods -l app=nginx,env=prod

Multiple selectors separated by commas are combined with AND logic — the resource must match all conditions.

Set-Based Selectors

Match labels using in, notin, and exists:

# Get Pods where env is dev OR staging
kubectl get pods -l 'env in (dev,staging)'

# Get Pods where env is NOT prod and NOT staging
kubectl get pods -l 'env notin (prod,staging)'

# Get Pods that HAVE the label "tier" (any value)
kubectl get pods -l 'tier'

# Get Pods that do NOT have the label "tier"
kubectl get pods -l '!tier'

Note: Set-based selectors require single quotes around the expression to prevent shell interpretation of parentheses and exclamation marks.

Selectors in Manifests

Services and Deployments use selectors in their specs to target Pods:

# Service selector — routes traffic to Pods with matching labels
apiVersion: v1
kind: Service
metadata:
  name: web-service
spec:
  selector:
    app: nginx
    tier: frontend
  ports:
    - port: 80
      targetPort: 80
# Deployment selector — manages Pods with matching labels
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:1.25

The Deployment’s spec.selector.matchLabels must match spec.template.metadata.labels. If they do not match, the Deployment cannot find the Pods it creates, and you get a validation error. This is a common manifest mistake and a frequent exam pitfall.

kubectl explain: The Exam Documentation Tool

The CKAD exam allows access to the official Kubernetes documentation at kubernetes.io/docs, but navigating a browser is slow. kubectl explain provides the same information directly in the terminal — field names, types, descriptions, and nesting — without leaving your workflow.

Basic Usage

# Top-level fields of a Pod
kubectl explain pod

Output:

KIND:       Pod
VERSION:    v1

DESCRIPTION:
    Pod is a collection of containers that can run on a host...

FIELDS:
    apiVersion   <string>
    kind         <string>
    metadata     <ObjectMeta>
    spec         <PodSpec>
    status       <PodStatus>

Drilling Into Nested Fields

Use dot notation to navigate deeper:

# Container fields within a Pod spec
kubectl explain pod.spec.containers

# Resource limits within a container
kubectl explain pod.spec.containers.resources

# Specific field: memory limits
kubectl explain pod.spec.containers.resources.limits

Each level shows the field’s type, whether it is required, and a description. This is your substitute for memorizing every field name in every resource.

Recursive Output

To see the full tree structure at once:

kubectl explain pod.spec --recursive

This dumps every field under pod.spec with its type, but without descriptions. It is useful when you know the field name exists somewhere and need to find its exact path.

# Find where readinessProbe lives
kubectl explain pod.spec --recursive | grep -i readiness

Output:

      readinessProbe       <Probe>

Now you know it is at pod.spec.containers.readinessProbe. Drill in for details:

kubectl explain pod.spec.containers.readinessProbe

Why This Matters on the Exam

During the exam, you will need to write fields you have not memorized. Instead of switching to a browser, searching documentation, and finding the right page:

  1. Use kubectl explain <resource> to find the top-level structure.
  2. Drill into the section you need with dot notation.
  3. Read the field description and type.
  4. Write the YAML.

This workflow keeps you in the terminal and saves minutes per task. Over a 2-hour exam with 15-20 tasks, those minutes compound into the difference between passing and failing.

Exercises

Work through these exercises in your Kind cluster. Solutions are provided in the next chapter.

Exercise 1: Create a Pod Imperatively and Declaratively

  1. Generate a Pod manifest using the dry-run technique:
    kubectl run nginx --image=nginx:1.25 --dry-run=client -o yaml > pod.yaml
  2. Open pod.yaml and add a label env: dev under metadata.labels.
  3. Apply the manifest: kubectl apply -f pod.yaml.
  4. Verify the Pod is running: kubectl get pods.
  5. Verify the label is present: kubectl get pod nginx --show-labels.

Exercise 2: Add Labels to a Running Pod

  1. Add two labels to the running nginx Pod:
    kubectl label pod nginx tier=frontend version=v1
  2. Verify the labels: kubectl get pod nginx --show-labels.
  3. Overwrite the env label from dev to staging:
    kubectl label pod nginx env=staging --overwrite
  4. Remove the version label:
    kubectl label pod nginx version-
  5. Confirm the final label set with --show-labels.

Exercise 3: Filter Resources with Label Selectors

  1. Create three additional Pods with different labels:
    kubectl run web1 --image=nginx:1.25 -l app=web,env=dev,tier=frontend
    kubectl run web2 --image=nginx:1.25 -l app=web,env=prod,tier=frontend
    kubectl run api1 --image=nginx:1.25 -l app=api,env=dev,tier=backend
  2. List all Pods where env=dev.
  3. List all Pods where env is dev or staging.
  4. List all Pods where app=web AND tier=frontend.
  5. List all Pods that have the label tier (any value).
  6. List all Pods across all namespaces that have the label app.

Exercise 4: Use kubectl explain to Find Resource Limit Fields

  1. Run kubectl explain pod.spec.containers.resources and identify the fields for setting CPU and memory limits.
  2. Run kubectl explain pod.spec.containers.resources.limits to see what resource types are available.
  3. Use kubectl explain pod.spec --recursive | grep -i restart to find the exact path for restartPolicy.
  4. Based on what you find, add a resource limit of 128Mi memory and 250m CPU to your nginx Pod manifest, then re-apply.