Skip to content

Deployments, CoreDNS & Exam Template Workflow

Reference: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/


Exam Priority — The Template Workflow

The core frustration in the raw notes was: "I don't have Google or AI in the exam, I'm not going to memorise these long commands."

Correct. You don't memorise them. You use one of two approaches:

Option 1 — dry-run scaffold (fastest):

kubectl create deployment dns-deploy-cka \
  --image=registry.k8s.io/e2e-test-images/jessie-dnsutils:1.3 \
  --replicas=2 \
  --namespace=dns-ns \
  --dry-run=client -o yaml > deploy.yaml

vim deploy.yaml   # edit container name + add command
kubectl apply -f deploy.yaml

Option 2 — copy from docs:

Go to kubernetes.io/docs/concepts/workloads/controllers/deployment → first example YAML on the page → copy it → edit the fields → apply.

Both are valid. dry-run is faster. Docs are the fallback when you forget the flag syntax.

What you DO memorise: the pattern — create <resource> --dry-run=client -o yaml. The flags for specific resources you look up with --help or the docs.


Deployment vs Pod — The Difference

A Pod is a single instance of your container. If it dies, it's gone.

A Deployment manages pods for you: - Declares desired state: "I want 2 replicas of this pod running at all times" - Creates a ReplicaSet that watches and maintains that count - If a pod dies → Deployment creates a new one automatically - Rolling updates: replace pods one by one, zero downtime - Rollback: go back to a previous version with one command

Deployment
  └── ReplicaSet
        ├── Pod (nginx-abc12)
        ├── Pod (nginx-def34)
        └── Pod (nginx-ghi56)

Rule of thumb: - Use a Pod when you're doing a one-off task, debugging, or a CKA exam question that specifically says "pod" - Use a Deployment for anything that should keep running — it's self-healing


Cluster vs Namespace — The Difference

Cluster Namespace
What it is The entire Kubernetes installation — all nodes, control plane, etcd A logical boundary inside a cluster
Isolation level Physical/VM separation Logical only — same nodes, same etcd
Failure scope One cluster down = everything in it goes down One namespace's resources can be isolated with RBAC/quotas, but same failure domain
Use case Separate prod from dev, compliance isolation Separate teams/apps within the same cluster

Namespace = folders on a hard drive. Cluster = the hard drive itself. If the hard drive fails, all folders go with it.


The Exercise — Full Clean Workflow

Create Deployment dns-deploy-cka, 2 replicas, namespace dns-ns, image registry.k8s.io/e2e-test-images/jessie-dnsutils:1.3, command sleep 3600, container named dns-container. Run nslookup kubernetes.default from a pod, save to dns-output.txt.

# 1. Create namespace
kubectl create namespace dns-ns

# 2. Generate deployment YAML scaffold
kubectl create deployment dns-deploy-cka \
  --image=registry.k8s.io/e2e-test-images/jessie-dnsutils:1.3 \
  --replicas=2 \
  --namespace=dns-ns \
  --dry-run=client -o yaml > deploy.yaml

deploy.yaml will have the container named after the image by default. Edit two things:

vim deploy.yaml

Change:

# BEFORE
containers:
- name: jessie-dnsutils      # ← change this
  image: registry.k8s.io/e2e-test-images/jessie-dnsutils:1.3

# AFTER
containers:
- name: dns-container        # ← to this
  image: registry.k8s.io/e2e-test-images/jessie-dnsutils:1.3
  command: ["sleep", "3600"] # ← add this line

# 3. Apply
kubectl apply -f deploy.yaml

# 4. Wait for pods to be ready
kubectl get pods -n dns-ns -w    # watch until Running
# or
kubectl wait pod -l app=dns-deploy-cka -n dns-ns --for=condition=Ready --timeout=60s

# 5. Run nslookup from a pod and save output
kubectl exec -n dns-ns \
  $(kubectl get pod -n dns-ns -l app=dns-deploy-cka -o jsonpath='{.items[0].metadata.name}') \
  -- nslookup kubernetes.default > dns-output.txt

# 6. Verify
cat dns-output.txt

Breaking Down the exec One-Liner

kubectl exec -n dns-ns \
  $(kubectl get pod -n dns-ns -l app=dns-deploy-cka -o jsonpath='{.items[0].metadata.name}') \
  -- nslookup kubernetes.default > dns-output.txt
Part What it does
kubectl exec Run a command in a running container
-n dns-ns Target pods in the dns-ns namespace
$(...) Command substitution — runs the inner command and uses its output as the pod name
kubectl get pod -n dns-ns -l app=dns-deploy-cka List pods matching label app=dns-deploy-cka
-o jsonpath='{.items[0].metadata.name}' Extract only the name of the first pod in the list
-- Separator — everything after this is the command to run inside the pod
nslookup kubernetes.default DNS lookup for kubernetes.default inside the pod
> dns-output.txt Save output to file locally (on the node running kubectl, not inside the pod)

The $(...) pattern means you never have to manually copy-paste a pod name. It dynamically finds one.


The Typo That Caused NXDOMAIN

In the raw notes:

kubectl exec ... -- nslookup kubernets.default   # NXDOMAIN
kubectl exec ... -- nslookup kubernetes.default  # success

NXDOMAIN = "Non-Existent Domain" — the DNS server received the query but has no record for that name. kubernets is a typo. Always double-check the service name you're looking up.


What's in dns-output.txt

Server:         10.96.0.10
Address:        10.96.0.10#53

Name:   kubernetes.default.svc.cluster.local
Address: 10.96.0.1
Field What it means
Server: 10.96.0.10 The DNS server that answered — this is CoreDNS's ClusterIP
10.96.0.10#53 Port 53 is the standard DNS port
Name: kubernetes.default.svc.cluster.local The FQDN CoreDNS expanded kubernetes.default to
Address: 10.96.0.1 The ClusterIP of the kubernetes Service — the API server endpoint

This confirms: CoreDNS is running, DNS resolution works, the pod can reach DNS.


kubectl create deployment — All Flags

kubectl create deployment NAME \
  --image=IMAGE \           # required — container image
  --replicas=N \            # number of pods (default: 1)
  --namespace=NS \          # namespace (default: default)
  --port=PORT \             # containerPort (informational)
  -- COMMAND [ARGS...]      # override command (after double dash)

Container naming limitation: kubectl create deployment always names the container after the image. If the exam requires a specific container name, you must either: 1. Use --dry-run=client -o yaml, edit the YAML, apply 2. Copy from docs, edit the name, apply

You cannot set the container name via the imperative command.

kubectl create deployment --help shows all flags inline. In the exam, this is faster than going to docs for a single flag.


kubectl wait — Block Until Ready

kubectl wait pod -l app=dns-deploy-cka -n dns-ns --for=condition=Ready --timeout=60s

Blocks until all pods matching the selector have Ready=True, or until 60 seconds pass (then exits with error).

Useful in scripts/exam to avoid running exec before the pod is ready. Without this, kubectl exec on a ContainerCreating pod fails.

Alternatives:

kubectl get pods -n dns-ns -w         # watch mode — stream status updates, Ctrl+C when Running
kubectl rollout status deployment/dns-deploy-cka -n dns-ns   # waits for deployment to complete


Deployment Commands Reference

# Create
kubectl create deployment my-dep --image=nginx --replicas=3
kubectl create deployment my-dep --image=nginx --dry-run=client -o yaml > dep.yaml

# Inspect
kubectl get deployments
kubectl get deploy -n my-ns
kubectl describe deployment my-dep
kubectl get pods -l app=my-dep          # pods owned by deployment

# Scale
kubectl scale deployment my-dep --replicas=5

# Update image (triggers rolling update)
kubectl set image deployment/my-dep nginx=nginx:1.25

# Rollout
kubectl rollout status deployment/my-dep    # watch rollout progress
kubectl rollout history deployment/my-dep   # show revision history
kubectl rollout undo deployment/my-dep      # rollback to previous version

# Delete
kubectl delete deployment my-dep

Docs Bookmark for Deployment Template

URL: kubernetes.io/docs/concepts/workloads/controllers/deployment

Ctrl+F for: replicas: — takes you to the first example YAML. Copy it, edit 5 fields, apply.

# Template from docs — edit these fields:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: CHANGE-ME               # deployment name
  namespace: CHANGE-ME          # namespace
spec:
  replicas: 2                   # replica count
  selector:
    matchLabels:
      app: CHANGE-ME            # must match template labels below
  template:
    metadata:
      labels:
        app: CHANGE-ME          # must match selector above
    spec:
      containers:
      - name: CHANGE-ME         # container name
        image: CHANGE-ME        # image
        command: ["sleep", "3600"]   # add if needed