CKA Study

Command cheat sheet

Everything here is imperative. If a task can be done without opening an editor, do it without opening an editor.


Setup — the first 60 seconds of the exam

alias k=kubectl
source <(kubectl completion bash)
complete -o default -F __start_kubectl k
export do='--dry-run=client -o yaml'
export now='--force --grace-period=0'
export ns='-n '        # then:  k get po $ns dev

cat >> ~/.vimrc <<'EOF'
set expandtab tabstop=2 shiftwidth=2 number
EOF

Why: $do turns every create/run into a manifest generator; set expandtab prevents literal tabs, which YAML rejects outright. Community write-ups put the saving at 20–30 minutes across the exam.

Per-task, before anything else:

kubectl config use-context <given-in-the-task>
kubectl config current-context

Discovery — instead of the docs tab

kubectl api-resources                       # every kind, its group, short name, namespaced?
kubectl api-resources --namespaced=false    # cluster-scoped kinds (PV, node, CRD, ClusterRole)
kubectl explain deploy.spec.template.spec.containers --recursive
kubectl explain networkpolicy.spec --recursive | head -40
kubectl <verb> --help | grep -A2 example    # every kubectl subcommand ships examples

Why: explain --recursive prints the schema from the API server you’re connected to — always the right version, always faster than a browser tab.


Generate, don’t author

kubectl run web --image=nginx $do > pod.yaml
kubectl run web --image=nginx --restart=Never --rm -it -- sh      # throwaway debug Pod
kubectl create deploy web --image=nginx --replicas=3 $do > deploy.yaml
kubectl create job pi --image=perl $do -- perl -Mbignum=bpi -wle 'print bpi(200)'
kubectl create cronjob rep --image=busybox --schedule="*/5 * * * *" $do -- /bin/sh -c date
kubectl expose deploy web --port=80 --target-port=8080 $do > svc.yaml
kubectl create ingress web --rule="host/path*=svc:80" --class=nginx $do
kubectl create configmap cfg --from-literal=k=v $do
kubectl create secret generic s --from-literal=p=x $do
kubectl create role r --verb=get,list --resource=pods $do
kubectl create rolebinding rb --role=r --serviceaccount=ns:sa $do
kubectl create quota q --hard=cpu=2,memory=4Gi $do
kubectl create poddisruptionbudget pdb --selector=app=web --min-available=2 $do

There is no imperative generator for: PersistentVolume, PersistentVolumeClaim, StorageClass, NetworkPolicy, DaemonSet, StatefulSet, Gateway, HTTPRoute, or tolerations/affinity stanzas. That list is your memorisation set — everything else on this page you can generate.


Inspect

kubectl get po -A -o wide
kubectl get po --show-labels
kubectl get po -l app=web,tier!=cache
kubectl get po --field-selector status.phase=Running
kubectl get po --sort-by=.status.startTime
kubectl get events -A --sort-by=.lastTimestamp | tail -20
kubectl get po -o custom-columns=NAME:.metadata.name,NODE:.spec.nodeName,IMG:.spec.containers[*].image
kubectl get po <p> -o jsonpath='{.spec.containers[*].image}{"\n"}'
kubectl get no -o json | jq '.items[].status.capacity'
kubectl describe po <p> | sed -n '/Events/,$p'
kubectl top no ; kubectl top po -A --sort-by=memory

Modify without an editor

kubectl set image deploy/web nginx=nginx:1.27
kubectl set resources deploy/web --requests=cpu=100m --limits=memory=256Mi
kubectl set env deploy/web --from=configmap/cfg
kubectl set serviceaccount deploy/web app-sa
kubectl label node w1 disktype=ssd
kubectl annotate deploy web owner=team-a
kubectl scale deploy/web --replicas=5
kubectl patch deploy web -p '{"spec":{"replicas":4}}'
kubectl patch pv pv1 -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'
kubectl patch deploy web --type=json -p='[{"op":"replace","path":"/spec/replicas","value":4}]'

Why two patch types: a strategic-merge -p '{...}' handles most fields; --type=json is for list surgery (add/remove an element at an index) where merge semantics are ambiguous.

Delete

kubectl delete po web $now
kubectl delete po -l app=web
kubectl delete all -l app=web -n dev          # NB: "all" ≠ everything; no PVC, no Secret, no CM
kubectl delete -k ./overlays/prod

Logs and exec

kubectl logs <p> -f
kubectl logs <p> --previous
kubectl logs <p> -c <container> --tail=50 --since=10m
kubectl logs -l app=web --all-containers --prefix
kubectl logs <p> | grep ERROR > /opt/answer.txt && cat /opt/answer.txt
kubectl exec -it <p> -- sh
kubectl exec <p> -c <c> -- env
kubectl cp <ns>/<p>:/etc/config/app.conf ./app.conf
kubectl port-forward svc/web 8080:80
kubectl debug -it <p> --image=busybox:1.36 --target=<container>   # ephemeral container

Node and cluster lifecycle

kubectl cordon w1 ; kubectl uncordon w1
kubectl drain w1 --ignore-daemonsets --delete-emptydir-data --force
kubectl get no -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints
kubectl taint no w1 key=val:NoSchedule
kubectl taint no w1 key=val:NoSchedule-
kubeadm token create --print-join-command
kubeadm certs check-expiration
kubeadm upgrade plan
kubeadm upgrade apply v1.35.0      # first control-plane node
kubeadm upgrade node               # every other node

On the node, when kubectl is gone

systemctl status kubelet
journalctl -u kubelet --no-pager -n 50
sudo crictl ps -a
sudo crictl logs <id>
sudo crictl pods
ls /etc/kubernetes/manifests/
sudo ss -lntp | grep 6443

etcd

export ETCDCTL_API=3
E="--cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key --endpoints=https://127.0.0.1:2379"
etcdctl $E snapshot save /opt/snap.db
etcdctl --write-out=table snapshot status /opt/snap.db
etcdctl $E endpoint health
etcdctl $E member list --write-out=table
etcdctl snapshot restore /opt/snap.db --data-dir=/var/lib/etcd-restore
# then edit /etc/kubernetes/manifests/etcd.yaml: --data-dir AND the hostPath volume

Helm and Kustomize

helm repo add x <url> && helm repo update
helm search repo x --versions
helm show values x/chart > values.yaml
helm install rel x/chart -n ns --create-namespace --version 1.2.3 -f values.yaml
helm upgrade --install rel x/chart -n ns --set replicaCount=3
helm list -A ; helm history rel -n ns ; helm rollback rel 1 -n ns
helm uninstall rel -n ns
kubectl kustomize ./overlays/prod
kubectl apply -k ./overlays/prod

RBAC checks

kubectl auth can-i list pods -n dev --as=system:serviceaccount:dev:app-sa
kubectl auth can-i --list --as=jane
kubectl auth whoami

Flags worth memorising

FlagWhereDoes
--dry-run=client -o yamlcreate/run/exposegenerate a manifest, don’t send it
-o widegetnode and Pod IP columns
-o jsonpath='{...}'getpull one field for a scripted answer
--sort-by=get.lastTimestamp, .status.startTime, memory
--show-labelsgetthe labels a selector has to match
-l k=v / --field-selectorget/deletelabel vs. server-side field filtering
--previouslogsthe container instance that died
--all-containerslogsevery container in the Pod
--ignore-daemonsetsdrainalmost always required
--delete-emptydir-datadrainrequired if any Pod has an emptyDir
--force --grace-period=0deleteimmediate; only when you mean it
--recordremoveddon’t reach for it; it’s gone
-kapply/deleterun kustomize first
--asanyimpersonate, for RBAC verification
-A / --all-namespacesgetcluster-wide