$ cheat sheet
CKAD
Imperative
Every kubectl command worth memorizing. Generate, verify, ship.
$
Setup & Context
1 snippetalias & completion
alias k=kubectl export do="--dry-run=client -o yaml" kubectl config set-context --current --namespace=<namespace-name>
Drop these in your shell rc. The exam terminal already has kubectl completion sourced for bash.
--
Dry-run & Generate
2 snippetsthe core pattern
# Generate YAML without creating the resource kubectl run nginx --image=nginx --dry-run=client -o yaml > pod.yaml # Shortcut with the alias k run nginx --image=nginx $do > pod.yaml # Then edit and apply vim pod.yaml k apply -f pod.yaml
This is the single most important CKAD trick. Generate a manifest, edit it, then apply.
what supports --dry-run
kubectl run # Pod
kubectl create # Deployment, Job, CronJob, ConfigMap,
# Secret, Service, Role, RoleBinding,
# ServiceAccount, Namespace, Quota, Ingress
kubectl expose # Service from existing workload
kubectl set image # Image update previewOnly kubectl run, create, expose, set, and a few others. kubectl edit, scale, label do not.
po
Pods
6 snippetsbasic pod
# Simplest form kubectl run nginx --image=nginx # With port and labels kubectl run nginx --image=nginx \ --port=80 \ --labels="app=web,tier=front"
pod with env vars
kubectl run nginx --image=nginx \ --env="DB_HOST=db" \ --env="DB_PORT=5432"
pod with command & args
# Override args only kubectl run busybox --image=busybox -- sleep 3600 # Override entrypoint and args kubectl run busybox --image=busybox \ --command -- /bin/sh -c "echo hello; sleep 3600"
Everything after -- becomes the container args. Use --command to override the entrypoint.
pod with resources
kubectl run nginx --image=nginx \ --requests='cpu=100m,memory=128Mi' \ --limits='cpu=200m,memory=256Mi'
ephemeral debug pod
kubectl run tmp --rm -it \ --image=busybox \ --restart=Never -- sh # Inside the pod: # nslookup my-svc # wget -O- http://my-svc:80
Auto-deletes when you exit. Lifesaver for testing connectivity or DNS from inside the cluster.
expose pod as service
kubectl run nginx --image=nginx \ --port=80 --expose
Creates the pod AND a matching ClusterIP service in one shot.
deploy
Deployments
5 snippetscreate deployment
# Basic kubectl create deployment web --image=nginx # With replicas and port kubectl create deployment web \ --image=nginx --replicas=3 --port=80
scale
kubectl scale deployment web --replicas=5 # Conditional scale kubectl scale deployment web \ --current-replicas=3 --replicas=5
update image (rolling)
kubectl set image deployment/web \ nginx=nginx:1.25 # Multi-container kubectl set image deployment/web \ nginx=nginx:1.25 sidecar=fluentd:1.16
Triggers a rolling update. Verify with rollout status before moving on.
rollout commands
kubectl rollout status deployment/web kubectl rollout history deployment/web kubectl rollout history deployment/web --revision=2 kubectl rollout undo deployment/web kubectl rollout undo deployment/web --to-revision=2 kubectl rollout restart deployment/web kubectl rollout pause deployment/web kubectl rollout resume deployment/web
Always verify after deploying. The exam wants to see you check status, not just apply.
canary pattern
# Stable: 4 replicas with version=stable kubectl create deployment web-stable \ --image=nginx:1.24 --replicas=4 # Canary: 1 replica with version=canary kubectl create deployment web-canary \ --image=nginx:1.25 --replicas=1 # Service selects on shared label only (app=web) # Add: kubectl label deployment web-* app=web
Two deployments + one service with a shared label selector. Adjust replica ratios to shift traffic.
svc
Services
3 snippetsexpose existing workload
kubectl expose deployment web \ --port=80 --target-port=8080 # NodePort kubectl expose deployment web \ --port=80 --type=NodePort # LoadBalancer kubectl expose deployment web \ --port=80 --type=LoadBalancer
Reuses the pod/deployment's labels as the service selector. Almost always the right call.
create service directly
kubectl create service clusterip my-svc \ --tcp=80:8080 kubectl create service nodeport my-svc \ --tcp=80:8080 --node-port=30080 kubectl create service externalname my-svc \ --external-name=example.com
Use this when there's no workload yet to expose, or when the selector needs to be custom.
test a service
kubectl run curl --rm -it \ --image=curlimages/curl \ --restart=Never -- \ curl http://my-svc:80
Spin up a throwaway pod in the same namespace, then curl/wget the service name.
cm
ConfigMaps
3 snippetsfrom literal values
kubectl create configmap app-config \ --from-literal=DB_HOST=db \ --from-literal=DB_PORT=5432
from a file
# File name as key kubectl create configmap app-config \ --from-file=nginx.conf # Custom key kubectl create configmap app-config \ --from-file=config=nginx.conf # Multiple files kubectl create configmap app-config \ --from-file=./config-dir/
The filename becomes the key by default. Use key=path to rename.
from an env file
# app.env contains: # DB_HOST=db # DB_PORT=5432 kubectl create configmap app-config \ --from-env-file=app.env
Each line becomes a key=value entry. Useful for porting .env files.
sec
Secrets
5 snippetsgeneric secret
kubectl create secret generic db-creds \ --from-literal=username=admin \ --from-literal=password='S!B\\*d$zDsb='
from file
kubectl create secret generic ssh-key \ --from-file=ssh-privatekey=~/.ssh/id_rsa
docker registry
kubectl create secret docker-registry regcred \ --docker-server=registry.example.com \ --docker-username=user \ --docker-password=pass \ --docker-email=user@example.com
Used as imagePullSecrets on the pod spec to pull from a private registry.
tls secret
kubectl create secret tls my-tls \ --cert=path/to/tls.crt \ --key=path/to/tls.key
decode a secret
kubectl get secret db-creds \
-o jsonpath='{.data.password}' | base64 -dSecrets are base64, not encrypted. -d decodes the value back to plaintext.
ns
Namespaces
2 snippetscreate and switch
kubectl create namespace dev # Set as default for current context kubectl config set-context --current \ --namespace=dev
list across namespaces
kubectl get pods -A kubectl get all -n dev kubectl get all --all-namespaces
sa
Service Accounts
2 snippetscreate
kubectl create serviceaccount app-sa # Attach to a pod (in spec) # spec: # serviceAccountName: app-sa
issue a token
kubectl create token app-sa kubectl create token app-sa --duration=24h
1.24+ doesn't auto-mount long-lived tokens. Use this to mint one when you need it.
rbac
RBAC
5 snippetscreate a role
kubectl create role pod-reader \ --verb=get,list,watch \ --resource=pods # Multiple resources and verbs kubectl create role pod-rw \ --verb=* \ --resource=pods,deployments,services
cluster role
kubectl create clusterrole node-reader \ --verb=get,list,watch --resource=nodes # Non-resource URL kubectl create clusterrole metrics-reader \ --verb=get --non-resource-url=/metrics
Same as Role but cluster-scoped. Also supports non-resource URLs like /healthz.
role binding
# To a user kubectl create rolebinding alice-reader \ --role=pod-reader --user=alice # To a service account kubectl create rolebinding app-reader \ --role=pod-reader \ --serviceaccount=dev:app-sa
Bind a Role to a user, group, or service account in the same namespace.
cluster role binding
kubectl create clusterrolebinding admin-bind \ --clusterrole=cluster-admin \ --user=alice
test permissions
# As yourself kubectl auth can-i create pods # As another user kubectl auth can-i list secrets \ --as=alice -n dev # As a service account kubectl auth can-i get pods \ --as=system:serviceaccount:dev:app-sa \ -n dev
The fastest way to verify RBAC works. Use --as to impersonate a user or SA.
cj
Jobs & CronJobs
3 snippetsone-off job
kubectl create job hello \ --image=busybox \ -- /bin/sh -c "echo hello world"
cronjob
kubectl create cronjob backup \ --image=busybox \ --schedule="*/5 * * * *" \ -- /bin/sh -c "echo backup"
trigger cronjob now
kubectl create job manual-run \ --from=cronjob/backup
Manually kick off a one-time run from an existing cronjob. Handy for verification.
ing
Ingress
4 snippetssingle rule
kubectl create ingress web \ --rule="example.com/*=web-svc:80"
Format is host/path=service:port. The * matches any path under that host.
multiple rules
kubectl create ingress multi \ --rule="foo.com/=svc1:80" \ --rule="bar.com/=svc2:80"
path-based routing
kubectl create ingress api \ --rule="example.com/api/*=api-svc:8080" \ --rule="example.com/web/*=web-svc:80"
with TLS and class
kubectl create ingress secure \ --class=nginx \ --rule="example.com/*=svc:80,tls=tls-secret"
quota
Quotas & Limits
2 snippetsresource quota
kubectl create quota team-quota \ --hard=cpu=4,memory=4Gi,pods=10
Caps total resource use across a namespace. Applies to all new objects.
limitrange — YAML only
apiVersion: v1
kind: LimitRange
metadata:
name: defaults
spec:
limits:
- default:
cpu: 200m
memory: 256Mi
defaultRequest:
cpu: 100m
memory: 128Mi
type: ContainerNo imperative create flag exists. Generate a Pod manifest and adapt, or write from scratch.
-l
Labels & Selectors
3 snippetslabel & annotate
kubectl label pod nginx env=prod kubectl label pod nginx env=dev --overwrite kubectl label pod nginx env- # remove kubectl annotate pod nginx \ description="frontend tier"
selector queries
kubectl get pods -l env=prod kubectl get pods -l 'env in (prod,stage)' kubectl get pods -l env!=prod kubectl get pods -l env=prod,tier=front
bulk operations by label
kubectl delete pods -l app=web kubectl get all -l app=web -o wide
?
Debugging
5 snippetsdescribe & events
kubectl describe pod nginx kubectl describe deployment web kubectl get events --sort-by=.lastTimestamp kubectl get events --field-selector type=Warning
describe is your first stop. The Events at the bottom usually tell you what's wrong.
logs
kubectl logs nginx kubectl logs nginx -c container-name kubectl logs nginx --previous # last crashed container kubectl logs nginx -f # follow kubectl logs -l app=nginx --tail=20
exec
kubectl exec nginx -- ls / kubectl exec -it nginx -- sh kubectl exec -it nginx -c sidecar -- bash
port forward
kubectl port-forward pod/nginx 8080:80 kubectl port-forward svc/web 8080:80 kubectl port-forward deploy/web 8080:80
Bypasses the service. Useful when you suspect the service selector is wrong.
top — metrics-server
kubectl top pod kubectl top pod --containers kubectl top pod -l app=web --sort-by=cpu kubectl top node
-o
Output & Explain
4 snippetsexplain — your offline docs
kubectl explain pod kubectl explain pod.spec.containers kubectl explain pod --recursive kubectl explain deploy.spec.strategy
kubectl ships with the entire API schema. Use it instead of opening kubernetes.io tabs.
jsonpath
# All pod names
kubectl get pods \
-o jsonpath='{.items[*].metadata.name}'
# Images across all pods
kubectl get pods \
-o jsonpath='{.items[*].spec.containers[*].image}'custom columns
kubectl get pods -o custom-columns=\ NAME:.metadata.name,\ STATUS:.status.phase,\ NODE:.spec.nodeName
sort
kubectl get pods \ --sort-by=.metadata.creationTimestamp kubectl get pods \ --sort-by=.status.containerStatuses[0].restartCount
~
Edit & Patch
4 snippetsedit live
kubectl edit deployment web kubectl edit svc/web # Use nano instead KUBE_EDITOR=nano kubectl edit deploy web
Opens vim with the live object. Not all fields are mutable — image, replicas, env yes; selector no.
patch (strategic merge)
kubectl patch deployment web \
-p '{"spec":{"replicas":5}}'patch (json)
kubectl patch deployment web --type=json \
-p='[{"op":"replace","path":"/spec/replicas","value":5}]'Use when you need to remove a field or modify a list element by index.
force replace
kubectl replace --force -f pod.yaml
Equivalent to delete + create. Use when a field can't be edited in place.
+/-
Apply & Delete
3 snippetsapply
kubectl apply -f pod.yaml kubectl apply -f ./manifests/ kubectl apply -f https://example.com/manifest.yaml
delete
kubectl delete pod nginx kubectl delete -f pod.yaml kubectl delete pods -l app=web kubectl delete all -l app=web
force delete (stuck pod)
kubectl delete pod nginx \ --force --grace-period=0 # With the alias k delete pod nginx $now
Use only when a pod is stuck Terminating. Skips graceful shutdown.
y
YAML-only Resources
2 snippetsno imperative form
# NetworkPolicy # PersistentVolume / PersistentVolumeClaim # LimitRange # HorizontalPodAutoscaler (use 'kubectl autoscale' instead) # Pod with readinessProbe / livenessProbe # Pod with securityContext / capabilities # Pod with volumes / volumeMounts # Pod with initContainers / sidecars
These need raw YAML. Memorize the minimum required spec — they show up often.
shortcut — generate and edit
# Generate a pod skeleton k run nginx --image=nginx $do > pod.yaml # Add probes, security context, volumes in vim vim pod.yaml k apply -f pod.yaml
Start from a kubectl-generated manifest, then add the YAML-only fields manually.