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
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, namespacedns-ns, imageregistry.k8s.io/e2e-test-images/jessie-dnsutils:1.3, commandsleep 3600, container nameddns-container. Runnslookup kubernetes.defaultfrom a pod, save todns-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:
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¶
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