The exam-day cheat sheet

Every command and minimal manifest this course used, grouped by domain, plus the kubernetes.io search phrase that lands on the right page for each topic.

Exam prep30 min0 tasks

After this lesson

  • 01You can reproduce any manifest skeleton in this sheet from memory or from one kubectl explain.
  • 02You can find the right documentation page for any domain topic with a single search phrase.
  • 03You can run the node-level and cluster-level diagnostics in order without looking anything up.

This is a reference, not a lesson: keep it open while you do the mocks, then stop needing it. Everything here runs on the lab as written (node commands run after docker exec -it cka-control-plane bash, or ssh <node> then sudo -i on the exam). The YAML blocks are deliberately minimal; kubectl explain <kind>.<path> fills in anything you need beyond them. The domain headings carry their exam weight so you know where a minute is worth most. Nothing on this page may come into the exam with you, but all of it is one search away on kubernetes.io; the table at the end lists the phrases.

kubectl: setup, generators, reading and changing objectsbash
alias k=kubectl
export do="--dry-run=client -o yaml"
export now="--force --grace-period=0"
source <(kubectl completion bash); complete -o default -F __start_kubectl k
printf 'set ts=2 sw=2 et nu\n' > ~/.vimrc

k run web --image=nginx:1.27 --port=80 --labels=app=web $do > pod.yaml
k run tmp --image=busybox:1.36 --restart=Never -it --rm -- sh          # throwaway shell
k create deploy web --image=nginx:1.27 --replicas=3 --port=80 $do > deploy.yaml
k expose deploy web --name=web-svc --port=80 --target-port=8080 --type=ClusterIP
k create svc nodeport web --tcp=80:8080 --node-port=30080
k create cm app-cfg --from-literal=KEY=value --from-file=app.properties --from-env-file=.env
k create secret generic db --from-literal=password=s3cret
k create secret tls web-tls --cert=tls.crt --key=tls.key
k create job once --image=busybox:1.36 -- sh -c 'date'
k create job manual --from=cronjob/nightly
k create cj nightly --image=busybox:1.36 --schedule='0 2 * * *' -- sh -c 'date'
k create ingress web --class=nginx --rule='shop.example.com/*=web-svc:80'
k create ns team-a; k create quota q --hard=pods=10,requests.cpu=2 -n team-a
k create pdb web-pdb --selector=app=web --min-available=1
k create priorityclass high --value=100000
k autoscale deploy web --min=2 --max=6 --cpu-percent=70
k scale deploy web --replicas=5
k set image deploy/web nginx=nginx:1.26
k set env deploy/web LOG_LEVEL=debug; k set env deploy/web --from=configmap/app-cfg
k set resources deploy/web -c nginx --requests=cpu=100m,memory=64Mi --limits=cpu=200m,memory=128Mi
k set sa deploy/web app
k label pod web tier=frontend --overwrite; k label pod web tier-
k annotate deploy web kubernetes.io/change-cause="image 1.26" --overwrite
k explain deploy.spec.strategy; k explain pod.spec.containers.livenessProbe --recursive
k api-resources | grep -i <word>; k api-versions

# --- Reading the cluster: formats, selectors, jsonpath, config
k get pods -o wide -A; k get pods -o name; k get pods --show-labels
k get pods -l app=web,tier!=cache; k get pods -l 'env in (prod,staging)'
k get pods -A --field-selector=status.phase!=Running
k get pods --sort-by=.metadata.creationTimestamp; k get events --sort-by=.lastTimestamp
k get pods -o custom-columns=NAME:.metadata.name,NODE:.spec.nodeName,IP:.status.podIP
k get deploy web -o jsonpath='{.spec.template.spec.containers[*].image}'
k get pods -o jsonpath='{.items[*].metadata.name}'
k get nodes -o jsonpath='{range .items[*]}{.metadata.name}{" "}{.status.addresses[?(@.type=="InternalIP")].address}{"\n"}{end}'
k get pods -A -o jsonpath='{range .items[?(@.spec.nodeName=="cka-worker")]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}'
k get nodes -o jsonpath='{range .items[*]}{.metadata.name}{": "}{.spec.taints[*].key}{"\n"}{end}'
k get deploy web -o yaml | yq '.spec.template.spec.containers[].image'
k get pods -w                                     # Ctrl+C to stop

k config get-contexts; k config use-context <ctx>; k config current-context
k config set-context --current --namespace=<ns>; k config view --minify
k --kubeconfig=/path/kubeconfig get nodes

k edit deploy web                                 # mutable fields
k apply -f file.yaml                              # from a file
k get pod web -o yaml > p.yaml; k replace --force -f p.yaml   # immutable Pod fields
k delete pod web $now                             # stuck Terminating
Architecture (25%): RBAC, service accounts, certificates, kubeconfigbash
k create role dev --verb=get,list,watch --resource=pods,deployments -n team-a
k create role dev-pod --verb=get --resource=pods --resource-name=web -n team-a
k create rolebinding dev-rb --role=dev --user=jane -n team-a
k create clusterrole nodes-ro --verb=get,list,watch --resource=nodes
k create clusterrole health --verb=get --non-resource-url=/healthz
k create clusterrolebinding nodes-ro-rb --clusterrole=nodes-ro --group=ops
k create rolebinding sa-rb --clusterrole=view --serviceaccount=team-a:app -n team-a   # ClusterRole bound in one namespace
k auth can-i list pods --as=jane -n team-a
k auth can-i get nodes --as=system:serviceaccount:team-a:app
k auth can-i --list --as=jane -n team-a

k create sa app -n team-a
k create token app -n team-a --duration=1h
# Pod: spec.serviceAccountName: app   spec.automountServiceAccountToken: false

# Client certificate for a user via the CSR API
openssl genrsa -out jane.key 2048
openssl req -new -key jane.key -subj "/CN=jane/O=devs" -out jane.csr
base64 -w0 jane.csr    # goes into spec.request below
k certificate approve jane; k certificate deny jane
k get csr jane -o jsonpath='{.status.certificate}' | base64 -d > jane.crt
k config set-credentials jane --client-key=jane.key --client-certificate=jane.crt --embed-certs
k config set-context jane --cluster=kubernetes --user=jane --namespace=team-a

# kubeadm-managed certificates (on the control plane)
kubeadm certs check-expiration
kubeadm certs renew apiserver; kubeadm certs renew all
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -dates -subject -ext subjectAltName
Architecture: kubeadm upgrade sequence, drain, etcd backup and restorebash
# --- Upgrade one minor (example 1.36 -> 1.37). On the node, as root. Control plane first, then each worker.
sed -i 's|v1\.36|v1.37|' /etc/apt/sources.list.d/kubernetes.list && apt-get update
apt-cache madison kubeadm | head -3
apt-mark unhold kubeadm && apt-get install -y kubeadm='1.37.0-*' && apt-mark hold kubeadm
kubeadm version
kubeadm upgrade plan
kubeadm upgrade apply v1.37.0                 # first control plane only
kubeadm upgrade node                          # other control planes and every worker
# From a machine with kubectl, before touching kubelet on that node:
kubectl drain <node> --ignore-daemonsets --delete-emptydir-data
# Back on the node:
apt-mark unhold kubelet kubectl && apt-get install -y kubelet='1.37.0-*' kubectl='1.37.0-*' && apt-mark hold kubelet kubectl
systemctl daemon-reload && systemctl restart kubelet
kubectl uncordon <node>
kubectl get nodes                              # VERSION column moves node by node

# --- Node maintenance
kubectl cordon <node>; kubectl drain <node> --ignore-daemonsets --delete-emptydir-data --force; kubectl uncordon <node>

# --- etcd: find the flags first (static pod on the control plane)
grep -E 'listen-client-urls|cert-file|key-file|trusted-ca-file|data-dir' /etc/kubernetes/manifests/etcd.yaml

# Snapshot
etcdctl --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  snapshot save /opt/etcd-backup.db
etcdutl snapshot status /opt/etcd-backup.db -w table

# Restore into a new data dir, then point the static pod at it
etcdutl snapshot restore /opt/etcd-backup.db --data-dir /var/lib/etcd-restored
# edit /etc/kubernetes/manifests/etcd.yaml: the etcd-data hostPath volume -> /var/lib/etcd-restored
# kubelet notices the manifest change and recreates etcd; wait, then:
crictl ps | grep etcd; kubectl get pods -A

# --- Static pods and the control plane
ls /etc/kubernetes/manifests/                 # kube-apiserver, controller-manager, scheduler, etcd
grep staticPodPath /var/lib/kubelet/config.yaml
kubectl -n kube-system get pods -o wide         # control-plane pods are named <component>-<node>
Architecture: Helm, Kustomize, CRDs and operatorsbash
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx; helm repo update
helm search repo ingress-nginx --versions | head
helm show values ingress-nginx/ingress-nginx > values.yaml
helm install ingress ingress-nginx/ingress-nginx -n ingress --create-namespace --version 4.13.0 -f values.yaml --set controller.replicaCount=2
helm upgrade ingress ingress-nginx/ingress-nginx -n ingress --version 4.13.1 --reuse-values
helm list -A; helm status ingress -n ingress; helm get values ingress -n ingress
helm history ingress -n ingress; helm rollback ingress 1 -n ingress
helm template ingress ingress-nginx/ingress-nginx -n ingress > rendered.yaml   # inspect without installing
helm uninstall ingress -n ingress

kubectl kustomize overlays/prod                  # render
kubectl apply -k overlays/prod; kubectl delete -k overlays/prod
# kustomization.yaml keys you will touch: resources, namespace, namePrefix, labels, images (name/newTag), patches (path + target)

kubectl get crd; kubectl get crd <name> -o yaml | less
kubectl explain <kind> --recursive | less        # works for CRD kinds too
kubectl api-resources | grep <group>
kubectl get <plural>.<group> -A                   # fully qualified when short names collide
Architecture: CSR object, kustomization.yaml and a minimal CRDyaml
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: jane
spec:
  request: <base64 of jane.csr, one line>
  signerName: kubernetes.io/kube-apiserver-client
  expirationSeconds: 86400
  usages:
    - client auth
---
# overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
namespace: prod
namePrefix: prod-
labels:
  - pairs:
      env: prod
    includeSelectors: true
images:
  - name: nginx
    newTag: "1.27"
patches:
  - path: replicas.yaml
    target:
      kind: Deployment
      name: web
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: backups.ops.example.com
spec:
  group: ops.example.com
  scope: Namespaced
  names:
    plural: backups
    singular: backup
    kind: Backup
    shortNames: ["bk"]
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                schedule: { type: string }
                retainDays: { type: integer }
Workloads (15%): rollouts, scheduling, autoscalingbash
k rollout status deploy/web --timeout=120s
k rollout history deploy/web; k rollout history deploy/web --revision=2
k rollout undo deploy/web; k rollout undo deploy/web --to-revision=1
k rollout pause deploy/web; k rollout resume deploy/web; k rollout restart deploy/web
k scale deploy web --replicas=4; k scale sts db --replicas=3
k autoscale deploy web --min=2 --max=6 --cpu-percent=70; k get hpa

k taint node cka-worker dedicated=gpu:NoSchedule        # NoSchedule | PreferNoSchedule | NoExecute
k taint node cka-worker dedicated=gpu:NoSchedule-       # remove
k label node cka-worker disk=ssd; k label node cka-worker disk-
k cordon cka-worker; k uncordon cka-worker
k get pods -o wide                                      # which node did it land on
k describe pod web | grep -A10 Events                   # FailedScheduling tells you why

k get ds,job,cj -A; k get job once -o jsonpath='{.status.succeeded}'
k create job manual --from=cronjob/nightly
k get pdb; k get priorityclass; k get limitrange,resourcequota -n team-a
k describe quota -n team-a
Workloads: Pod spec skeletons (scheduling, probes, resources, config, sidecar)yaml
apiVersion: v1
kind: Pod
metadata:
  name: web
  labels: { app: web }
spec:
  priorityClassName: high
  serviceAccountName: app
  nodeSelector:
    disk: ssd
  tolerations:
    - key: dedicated
      operator: Equal          # or Exists (then omit value)
      value: gpu
      effect: NoSchedule
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
          - matchExpressions:
              - { key: disk, operator: In, values: [ssd] }   # In NotIn Exists DoesNotExist Gt Lt
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        - labelSelector:
            matchLabels: { app: web }
          topologyKey: kubernetes.io/hostname
  topologySpreadConstraints:
    - maxSkew: 1
      topologyKey: kubernetes.io/hostname
      whenUnsatisfiable: DoNotSchedule
      labelSelector:
        matchLabels: { app: web }
  initContainers:
    - name: init-cfg
      image: busybox:1.36
      command: ["sh", "-c", "echo ready > /work/ok"]
      volumeMounts: [{ name: work, mountPath: /work }]
    - name: log-shipper              # sidecar: an init container that keeps running
      image: busybox:1.36
      restartPolicy: Always
      command: ["sh", "-c", "tail -F /work/app.log"]
      volumeMounts: [{ name: work, mountPath: /work }]
  containers:
    - name: nginx
      image: nginx:1.27
      ports: [{ containerPort: 80 }]
      resources:
        requests: { cpu: 100m, memory: 64Mi }
        limits: { cpu: 200m, memory: 128Mi }
      env:
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef: { name: db, key: password }
        - name: LOG_LEVEL
          valueFrom:
            configMapKeyRef: { name: app-cfg, key: LOG_LEVEL }
      envFrom:
        - configMapRef: { name: app-cfg }
      startupProbe:
        httpGet: { path: /, port: 80 }
        failureThreshold: 30
        periodSeconds: 2
      readinessProbe:
        httpGet: { path: /, port: 80 }
        initialDelaySeconds: 2
        periodSeconds: 5
      livenessProbe:
        exec:
          command: ["sh", "-c", "test -f /tmp/healthy"]
        periodSeconds: 10
        failureThreshold: 3
      volumeMounts:
        - { name: work, mountPath: /work }
        - { name: cfg, mountPath: /etc/app, readOnly: true }
  volumes:
    - name: work
      emptyDir: {}
    - name: cfg
      configMap:
        name: app-cfg
    - name: secrets
      secret:
        secretName: db
  restartPolicy: Always            # Pod-level: Always | OnFailure | Never
Workloads: HPA (autoscaling/v2), PDB, LimitRange, ResourceQuota, CronJobyaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web
  minReplicas: 2
  maxReplicas: 6
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 60
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: web-pdb
spec:
  minAvailable: 2                 # or maxUnavailable: 1
  selector:
    matchLabels: { app: web }
---
apiVersion: v1
kind: LimitRange
metadata:
  name: defaults
spec:
  limits:
    - type: Container
      default: { cpu: 200m, memory: 128Mi }
      defaultRequest: { cpu: 100m, memory: 64Mi }
      max: { cpu: "1", memory: 512Mi }
---
apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-quota
spec:
  hard:
    pods: "10"
    requests.cpu: "2"
    requests.memory: 2Gi
    limits.cpu: "4"
---
apiVersion: batch/v1
kind: CronJob
metadata:
  name: nightly
spec:
  schedule: "0 2 * * *"
  concurrencyPolicy: Forbid
  successfulJobsHistoryLimit: 3
  jobTemplate:
    spec:
      backoffLimit: 2
      activeDeadlineSeconds: 300
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: run
              image: busybox:1.36
              command: ["sh", "-c", "date"]
Networking (20%): Services, endpoints, DNS, Ingress, policiesbash
k expose deploy web --name=web-svc --port=80 --target-port=8080 --type=NodePort
k get svc web-svc -o wide; k get endpointslices -l kubernetes.io/service-name=web-svc
k get svc web-svc -o jsonpath='{.spec.ports[0].nodePort}'         # 30000-32767
k run tmp --image=busybox:1.36 --restart=Never -it --rm -- wget -qO- --timeout=2 http://web-svc.team-a.svc.cluster.local
k run tmp --image=busybox:1.36 --restart=Never -it --rm -- nslookup web-svc.team-a.svc.cluster.local
# DNS names: <svc>.<ns>.svc.cluster.local   <pod-ip-dashed>.<ns>.pod.cluster.local   <pod>.<headless-svc>.<ns>.svc.cluster.local

k -n kube-system get deploy coredns; k -n kube-system get svc kube-dns
k -n kube-system get cm coredns -o yaml                   # the Corefile
k -n kube-system logs deploy/coredns --tail=50
k -n kube-system rollout restart deploy coredns
k get pod tmp -o jsonpath='{.spec.dnsPolicy}'; cat /etc/resolv.conf   # inside a pod

k get ingressclass; k get ingress -A; k describe ingress web
curl -H 'Host: shop.example.com' http://localhost:8080/              # lab: ingress-nginx on 8080
k -n ingress-nginx logs deploy/ingress-nginx-controller --tail=50

k get gatewayclass,gateway,httproute -A; k describe httproute web

k get netpol -n team-a; k describe netpol deny-all -n team-a
k get pods -n team-a --show-labels                        # does the podSelector match anything?

# On a node: the pod network
ip addr; ip route; cat /etc/cni/net.d/*; crictl ps
Networking: Service, Ingress, Gateway, HTTPRoute, NetworkPolicyyaml
apiVersion: v1
kind: Service
metadata:
  name: web-svc
  namespace: team-a
spec:
  type: ClusterIP                 # ClusterIP | NodePort | LoadBalancer; clusterIP: None for headless
  selector:
    app: web
  ports:
    - name: http
      port: 80                    # the Service's port
      targetPort: 8080            # the container's port (number or port name)
      # nodePort: 30080           # NodePort only, 30000-32767
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web
  namespace: team-a
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  tls:
    - hosts: [shop.example.com]
      secretName: web-tls
  rules:
    - host: shop.example.com
      http:
        paths:
          - path: /
            pathType: Prefix      # Prefix | Exact | ImplementationSpecific
            backend:
              service:
                name: web-svc
                port:
                  number: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: shared-gw
  namespace: team-a
spec:
  gatewayClassName: nginx
  listeners:
    - name: http
      protocol: HTTP
      port: 80
      hostname: shop.example.com
      allowedRoutes:
        namespaces:
          from: Same              # Same | All | Selector
    - name: https
      protocol: HTTPS
      port: 443
      hostname: shop.example.com
      tls:
        mode: Terminate
        certificateRefs:
          - name: web-tls
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: web
  namespace: team-a
spec:
  parentRefs:
    - name: shared-gw
  hostnames: [shop.example.com]
  rules:
    - matches:
        - path:
            type: PathPrefix      # PathPrefix | Exact | RegularExpression
            value: /
      backendRefs:
        - name: web-svc
          port: 80
          weight: 90
        - name: web-canary
          port: 80
          weight: 10
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: web-policy
  namespace: team-a
spec:
  podSelector:
    matchLabels: { app: web }     # {} selects every pod in the namespace
  policyTypes: [Ingress, Egress]  # listing a type with no rules = deny all of that type
  ingress:
    - from:
        - podSelector:
            matchLabels: { app: frontend }
        - namespaceSelector:
            matchLabels: { kubernetes.io/metadata.name: monitoring }
        - ipBlock:
            cidr: 10.0.0.0/8
            except: [10.0.1.0/24]
      ports:
        - protocol: TCP
          port: 8080
  egress:
    - to:
        - namespaceSelector: {}
          podSelector:
            matchLabels: { k8s-app: kube-dns }
      ports:
        - { protocol: UDP, port: 53 }
        - { protocol: TCP, port: 53 }
# A podSelector and a namespaceSelector in ONE list item (no dash before the second) is AND; separate items are OR.
Storage (10%): StorageClass, PV, PVC, mountingyaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: rancher.io/local-path        # lab; kubernetes.io/no-provisioner for manual PVs
reclaimPolicy: Delete                      # Delete | Retain
volumeBindingMode: WaitForFirstConsumer    # or Immediate
allowVolumeExpansion: true
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-data
spec:
  capacity:
    storage: 1Gi
  accessModes: [ReadWriteOnce]             # ReadWriteOnce | ReadOnlyMany | ReadWriteMany | ReadWriteOncePod
  persistentVolumeReclaimPolicy: Retain
  storageClassName: manual
  hostPath:
    path: /data/pv-data
  # local volumes need nodeAffinity:
  # local: { path: /mnt/disks/ssd1 }
  # nodeAffinity:
  #   required:
  #     nodeSelectorTerms:
  #       - matchExpressions:
  #           - { key: kubernetes.io/hostname, operator: In, values: [cka-worker] }
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data
  namespace: team-a
spec:
  accessModes: [ReadWriteOnce]
  storageClassName: manual                 # must match the PV, or omit to use the default class
  resources:
    requests:
      storage: 500Mi                       # a PV with >= this capacity binds
  # volumeName: pv-data                    # pin to one PV
---
# In a Pod:
#   volumes:
#     - name: data
#       persistentVolumeClaim:
#         claimName: data
#   containers[].volumeMounts:
#     - { name: data, mountPath: /var/lib/data }
# Check: kubectl get pv,pvc -A   STATUS Bound; a Pending PVC with WaitForFirstConsumer is normal until a Pod uses it.
# Reclaim: Retain leaves the PV Released; delete it and recreate (or clear spec.claimRef) to reuse.
Troubleshooting (30%): inside the cluster, then on the nodebash
k get nodes; k describe node <node> | grep -A8 Conditions; k top nodes
k get pods -A --field-selector=status.phase!=Running
k get pods -A -o wide | grep -vE 'Running|Completed'
k describe pod web -n ns | tail -25                      # Events: image pull, scheduling, probes, mounts
k logs web -n ns; k logs web -c app --previous; k logs -l app=web --all-containers --tail=50
k logs deploy/web -n ns --since=10m -f
k get events -n ns --sort-by=.lastTimestamp; k events --for pod/web -n ns
k top pods -A --sort-by=memory; k top pod web --containers -n ns
k exec -it web -n ns -- sh; k exec web -n ns -- cat /etc/resolv.conf
k debug -it web -n ns --image=busybox:1.36 --target=app      # ephemeral container sharing the process namespace
k debug web -n ns --copy-to=web-debug --container=app -- sh   # a copy with a new command
k debug node/cka-worker -it --image=busybox:1.36              # host filesystem at /host
k get --raw /readyz?verbose; k get --raw /livez?verbose
k -n kube-system get pods -o wide; k -n kube-system logs kube-apiserver-cka-control-plane --tail=50
k -n kube-system logs kube-scheduler-cka-control-plane; k -n kube-system logs kube-controller-manager-cka-control-plane
k get svc,endpointslices -n ns; k get netpol -A
k auth can-i create pods --as=system:serviceaccount:ns:app -n ns
k get pod web -o yaml | grep -E 'image:|nodeName|serviceAccountName|phase|reason|message'

# --- On a node (lab: docker exec -it cka-control-plane bash; exam: ssh <node>, then sudo -i)
systemctl status kubelet; systemctl restart kubelet; systemctl enable --now kubelet
journalctl -u kubelet --no-pager --since '10 min ago' | tail -50
journalctl -u kubelet -f
cat /var/lib/kubelet/config.yaml                       # staticPodPath, clusterDNS, authentication
cat /etc/kubernetes/kubelet.conf                       # server URL, client certs
cat /var/lib/kubelet/kubeadm-flags.env                 # extra kubelet args
ls /etc/kubernetes/manifests/                          # static pod manifests; a typo here breaks the control plane
ls /etc/kubernetes/pki/                                # certificates

systemctl status containerd; journalctl -u containerd --no-pager | tail -30
crictl ps -a; crictl ps -a | grep -i apiserver
crictl logs <container-id>; crictl logs --tail=50 <container-id>
crictl pods; crictl images; crictl inspect <container-id>
cat /etc/crictl.yaml                                   # runtime endpoint if crictl complains

ip addr; ip route; cat /etc/cni/net.d/*                # pod network
ss -ltnp | grep -E '6443|10250|2379'                   # apiserver, kubelet, etcd listening?
df -h; free -m; top -bn1 | head -15                    # disk pressure, memory pressure
swapon --show                                          # kubelet refuses to start with swap on unless configured
cat /etc/hosts; nslookup kubernetes.default 10.96.0.10 # DNS from the node
TopicSearch phrase (kubernetes.io/docs)Page it lands on
Deployments, rollouts, undodeploymentDeployments
RBACrbacUsing RBAC Authorization
Service account tokensservice accountConfigure Service Accounts for Pods
Client certs, CSRcertificate signing requestsCertificate Signing Requests
kubeadm upgradekubeadm upgradeUpgrading kubeadm clusters
kubeadm init and joincreating a cluster with kubeadmCreating a cluster with kubeadm
HA control planehighly available kubeadmCreating Highly Available Clusters with kubeadm
etcd backup and restoreetcd backupOperating etcd clusters for Kubernetes
Drain a nodesafely drain nodeSafely Drain a Node
Static podsstatic podCreate static Pods
Helm(helm.sh/docs) helm install, helm upgrade, helm rollbackHelm Install / Upgrade / Rollback
KustomizekustomizeDeclarative Management of Kubernetes Objects Using Kustomize
CRDscustom resource definitionsExtend the Kubernetes API with CustomResourceDefinitions
Operatorsoperator patternOperator pattern
CNI, CSI, CRIcontainer runtime interfaceContainer Runtime Interface (CRI); also network plugins
ConfigMapsconfigmapConfigMaps
SecretssecretSecrets
Resources, requests, limitsresource management pods containersResource Management for Pods and Containers
LimitRange, ResourceQuotalimit range / resource quotasLimit Ranges / Resource Quotas
nodeSelector, affinityassign pods to nodesAssigning Pods to Nodes
Taints and tolerationstaints and tolerationsTaints and Tolerations
Topology spreadtopology spread constraintsPod Topology Spread Constraints
Probesliveness readiness startup probesConfigure Liveness, Readiness and Startup Probes
Init containers, sidecarsinit containers / sidecar containersInit Containers / Sidecar Containers
DaemonSet, Job, CronJob, StatefulSetdaemonset / job / cronjob / statefulsetThe controller's concept page
HPAhorizontalpodautoscaler walkthroughHorizontalPodAutoscaler Walkthrough
PodDisruptionBudgetpod disruption budgetSpecifying a Disruption Budget for your Application
Pod Security Admissionpod security admissionPod Security Admission
Priority and preemptionpod priority preemptionPod Priority and Preemption
ServicesserviceService
DNS namesdns pod serviceDNS for Services and Pods
CoreDNS customizationcustomizing dns serviceCustomizing DNS Service
IngressingressIngress
Gateway APIgateway apiGateway API (and gateway-api.sigs.k8s.io for the full spec)
NetworkPolicynetwork policiesNetwork Policies
PersistentVolumes, access modes, reclaimpersistent volumesPersistent Volumes
StorageClassstorage classesStorage Classes
VolumesvolumesVolumes
kubectl debugdebug running podDebug Running Pods
Node debugging, crictlcrictlDebugging Kubernetes nodes with crictl
Cluster troubleshootingtroubleshooting clustersTroubleshooting Clusters
Metrics, kubectl topresource metrics pipelineResource metrics pipeline
Logginglogging architectureLogging Architecture
kubectl referencecheat sheetkubectl Quick Reference
jsonpathjsonpathJSONPath Support
Multiple clusters, contextsconfigure access multiple clustersConfigure Access to Multiple Clusters

In the docs · the tab you get on exam day

Finished reading?

This is a reference lesson. Mark it done when you have read it.