12 questions, all run from controlplane. Each question shows a weight (Q1 = 8) and the grader's checks (Q1: "Is the pod environment variable correctly set?", "Does the sidecar display logs?").
Task: mc-pod-1 = nginx:1-alpine with env NODE_NAME = node name; mc-pod-2 = busybox:1 appends date to /var/log/shared/date.log every second; mc-pod-3 = busybox:1 prints that file to stdout. Shared emptyDir at /var/log/shared. Background: §5.7 (env), §5.13/§5.14 (multi-container), §8.6 (volumes).
apiVersion: v1kind: Podmetadata: name: mc-pod namespace: mc # use the namespace the task names (the task screenshot shows mc-namespace)spec: volumes: - name: shared-volume emptyDir: {} # non-persistent; lives as long as the pod containers: - name: mc-pod-1 image: nginx:1-alpine env: - name: NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName # Downward API - name: mc-pod-2 image: busybox:1 command: ["sh", "-c", "while true; do date >> /var/log/shared/date.log; sleep 1; done"] volumeMounts: - name: shared-volume mountPath: /var/log/shared - name: mc-pod-3 image: busybox:1 command: ["sh", "-c", "until [ -f /var/log/shared/date.log ]; do sleep 1; done; tail -f /var/log/shared/date.log"] volumeMounts: - name: shared-volume mountPath: /var/log/shared restartPolicy: Always
kubectl apply -f question1.yamlkubectl logs mc-pod -n mc -c mc-pod-3 -f # timestamps written by mc-pod-2 appear continuouslykubectl exec mc-pod -n mc -c mc-pod-1 -- env | grep NODE_NAME # Beyond the course: check the env var
emptyDir is for sharing between containers of one pod and is gone when the pod goes. It survives container restarts within the same Pod, but is removed with the Pod; use suitable persistent storage for Pod replacement/node failure (§8.7).
[!WARNING]
The course notes use namespace mc, but the task screenshot says mc-namespace. Always copy names from the task text. Create the namespace first if it does not exist.
Task: SSH to node01 as bob, become root, install the cri-dockerd.deb in /root, then start and enable the service.
ssh bob@node01sudo su - # become rootcd /root && ls -l # find the package (the file name varies)dpkg -i ./cri-dockerd_0.3.16.3-0.debian.deb # output: package configured, unit symlinks createdsystemctl start cri-docker.servicesystemctl enable cri-docker.servicesystemctl status cri-docker.service # expect: Active: active (running)systemctl is-enabled cri-docker.service # expect: enabled
[!NOTE]
Beyond the course: systemctl enable --now cri-docker.service starts and enables in one command. Background on cri-dockerd (the Docker shim that lives outside Kubernetes): §2.3/§2.4.
kubectl expose pod messaging --port=6379 --name=messaging-service # type defaults to ClusterIPkubectl get svc messaging-servicekubectl describe svc messaging-service # Endpoints must show <messaging pod IP>:6379
expose builds the service selector from the pod's labels. Selector and labels must match, otherwise the service has no endpoints.
[!CAUTION]
Correction: the course notes say a pod with no labels gives a service with no selector. In fact kubectl expose fails with "the pod has no labels and cannot be exposed". Label the pod first (kubectl label pod messaging app=messaging) or pass --selector. Pods made with kubectl run already have the run=<name> label.
Use --force replace because a bare pod has no controller to recreate it, and the pod's command cannot be edited in place.
[!TIP]
kubectl edit pod orange rejects the change but saves a copy in /tmp/kubectl-edit-*.yaml. Run kubectl replace --force -f /tmp/kubectl-edit-….yaml.
Spec: type NodePort, port 8080, nodePort 30082, selector app: hr-web-app.
apiVersion: v1kind: Servicemetadata: name: hr-web-app-service labels: app: hr-web-appspec: type: NodePort selector: app: hr-web-app # must match the deployment's pod labels ports: - port: 8080 targetPort: 8080 # webapp-color listens on 8080 nodePort: 30082 protocol: TCP
kubectl apply -f question7.yamlkubectl describe svc hr-web-app-service # NodePort: 30082/TCP, Endpoints = the 2 pod IPs
[!WARNING]
nodePort must be in the cluster's NodePort range (default 30000-32767) and not already used by another service.
Beyond the course: kubectl create service nodeport hr-web-app-service --tcp=8080:8080 --node-port=30082 sets the selector app=hr-web-app-service, which is wrong here. Use kubectl expose deployment hr-web-app --name=hr-web-app-service --type=NodePort --port=8080 --dry-run=client -o yaml, add nodePort: 30082, then apply.
kubectl apply -f webapp-hpa.yamlkubectl get hpa webapp-hpakubectl describe hpa webapp-hpa
The HPA needs a metrics provider (metrics-server). Without one, the targets show <unknown>.
[!NOTE]
Beyond the course: kubectl autoscale deployment kk-app-deploy --name=webapp-hpa --min=2 --max=10 --cpu-percent=50, then kubectl edit hpa webapp-hpa to add behavior. autoscale has no flag for behavior.
kubectl apply -f question11.yamlkubectl get gateway -n nginx-gatewaykubectl describe gateway web-gateway -n nginx-gateway # status gets filled in once a controller programs it
helm list -n kk-ns # find the release and its current chart versionhelm repo updatehelm search repo kk-mock1 --versions # optional: list available versionshelm search repo kk-mock1/nginx --versions # when you know <repo>/<chart>helm upgrade kk-mock1 kk-mock1/nginx --version 18.1.5 -n kk-nshelm list -n kk-ns # CHART shows nginx-18.1.5helm status kk-mock1 -n kk-ns
[!WARNING]
Exam traps / remember:
Pass -n <ns> on namespace-scoped Helm release commands (list, get, upgrade, uninstall). helm repo / helm search repo operate on client repositories, not a release namespace.
--version is the chart version. It is not the app version.
Use -c <container> for logs in multi-container pods. Use --force replace for pod fields you cannot change in place.
[!CAUTION]
Correction: the sidecar examples wait for the shared log file before tail -f; the course version races the writer and can exit if the file does not yet exist. emptyDir survives container restarts, not Pod replacement. See emptyDir.
The upstream cri-dockerd package installs cri-docker.service / cri-docker.socket, despite the executable being named cri-dockerd. Inspect dpkg -L <installed-package-name> or systemctl list-unit-files "cri-docker*"; use the units supplied by the lab package if they differ. See upstream service.
[!NOTE]
Beyond the course: CPU/memory Utilization HPA targets depend on container resource requests as well as metrics-server. Verify kubectl describe hpa and target-Pod requests if the metric is unknown.
apiVersion: storage.k8s.io/v1kind: StorageClassmetadata: name: local-sc annotations: storageclass.kubernetes.io/is-default-class: "true" # this annotation makes it the default classprovisioner: kubernetes.io/no-provisioner # manual/static provisioningallowVolumeExpansion: truevolumeBindingMode: WaitForFirstConsumerparameters: {}
kubectl apply -f question1.yaml # storageclass.storage.k8s.io/local-sc createdkubectl get sc # Beyond the course: local-sc shows "(default)"
[!WARNING]
The annotation value must be the string"true". Beyond the course: if another class is already marked default, remove its annotation (or set it to "false") so only one default remains.
kubectl create namespace logging-ns # only if it does not existkubectl apply -f question2.yamlkubectl get pods -n logging-nskubectl logs <pod-name> -c log-agent -n logging-ns -f # "Log entry" lines
[!NOTE]
Beyond the course: native sidecars (v1.29+) are an initContainers entry with restartPolicy: Always. Use them only if the task asks for that. Otherwise use the regular second-container structure specified in the task, as above.
kubectl create namespace ingress-ns # only if absentkubectl apply -f question3.yamlkubectl get ingress -n ingress-nscurl -s http://kodekloud-ingress.app/ # the client must resolve the host to the ingress IP (DNS or /etc/hosts)
[!NOTE]
Beyond the course: kubectl create ingress webapp-ingress -n ingress-ns --class=nginx --rule="kodekloud-ingress.app/*=webapp-svc:80" (a trailing * gives pathType: Prefix).
kubectl create deployment nginx-deploy --image=nginx:1.16 --dry-run=client -o yaml > question4.yamlkubectl apply -f question4.yamlkubectl get deploy nginx-deploykubectl rollout history deployment nginx-deploykubectl set image deployment/nginx-deploy nginx=nginx:1.17 # container name "nginx" comes from the image namekubectl rollout status deployment/nginx-deploykubectl rollout history deployment nginx-deploy # now 2 revisionskubectl rollout history deployment nginx-deploy --revision=2 # shows image nginx:1.17
RollingUpdate is the default strategy, so there is nothing to configure. Background: §5.2.
apiVersion: rbac.authorization.k8s.io/v1kind: Rolemetadata: name: developer namespace: developmentrules: - apiGroups: [""] resources: ["pods"] verbs: ["create", "list", "get", "update", "delete"]---apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata: name: john-developer-role-binding namespace: developmentsubjects: - kind: User name: john # = CN in the CSR apiGroup: rbac.authorization.k8s.ioroleRef: kind: Role name: developer apiGroup: rbac.authorization.k8s.io
kubectl apply -f question5-rbac.yaml # create the namespace first if it is missingkubectl auth can-i create pods --as=john -n development # yeskubectl auth can-i create pods --as=john -n default # no
The username in the RoleBinding is the CN of the CSR subject.
The CSR does not contain the private key. Keep john.key safe and pair it with john.crt in the kubeconfig for john (§7.12).
[!NOTE]
Beyond the course, imperative RBAC: kubectl create role developer -n development --verb=create,list,get,update,delete --resource=pods and kubectl create rolebinding john-developer-role-binding -n development --role=developer --user=john.
kubectl run nginx-resolver --image=nginx --restart=Neverkubectl expose pod nginx-resolver --name=nginx-resolver-service --port=80 --target-port=80 --type=ClusterIPkubectl get svc nginx-resolver-service# Service lookup from a throwaway busybox pod; the output is saved locallykubectl run test-nslookup --image=busybox:1.28 --rm -it --restart=Never -- nslookup nginx-resolver-service > nginx.svc# Pod lookup: pod DNS name = <IP with dashes>.<ns>.pod.cluster.localPOD_IP=$(kubectl get pod nginx-resolver -o jsonpath='{.status.podIP}')IP_DASH=$(echo $POD_IP | tr '.' '-') # 172.17.1.18 -> 172-17-1-18kubectl run test-nslookup2 --image=busybox:1.28 --rm -it --restart=Never -- nslookup ${IP_DASH}.default.pod.cluster.local > nginx.pod
Service FQDN: nginx-resolver-service.default.svc.cluster.local.
Pod FQDN: <ip-with-dashes>.<namespace>.pod.cluster.local.
The example pins busybox:1.28; DNS utility behavior can differ by image. Confirm the lookup exits successfully and inspect the saved output.
The kubelet watches /etc/kubernetes/manifests. Background: §3.16.
kubectl run nginx-critical --image=nginx --restart=Never --dry-run=client -o yaml > static.yaml# copy the manifest to the node (scp, or paste it into a file over ssh), then on cluster1-node01:sudo mv static.yaml /etc/kubernetes/manifests/static.yaml# back on the control plane:kubectl get pod -o wide # nginx-critical-cluster1-node01, NODE = cluster1-node01
The mirror pod's name has the node name appended.
The file must be on the node. A YAML file left on the control plane does nothing.
[!NOTE]
Beyond the course: confirm the path on the node with grep staticPodPath /var/lib/kubelet/config.yaml.
kubectl create namespace backend # only if it does not existkubectl apply -f webapp-hpa.yamlkubectl describe hpa backend-hpa -n backend
metrics-server must be running. Beyond the course: memory Utilization is measured against the containers' memory requests, so the target pods need requests set.
kubectl get nodes # connection refusedsudo systemctl status kubelet # inactive (dead)sudo systemctl start kubeletsudo systemctl enable kubeletcrictl ps -a | grep kube-apiserver # the API server container comes backkubectl get pods -n kube-systemkubectl get nodes
The lab’s stopped kubelet prevents the missing API-server static Pod from being started/recovered. Stopping kubelet does not automatically stop containers already running under the runtime; diagnose the actual missing/exited component with crictl.
spec: gatewayClassName: kodekloud # keep the existing class listeners: - name: https port: 443 protocol: HTTPS hostname: kodekloud.com tls: certificateRefs: # Secret in the Gateway's namespace (mode defaults to Terminate) - name: kodekloud-tls allowedRoutes: namespaces: from: Same
kubectl apply -f question10.yamlkubectl get gateway -n cka5673
[!CAUTION]
Correction:
The course runs kubectl create namespace cka5673 before applying. The namespace already exists because the Gateway lives in it, so that command just errors. Skip it.
The course also says the TLS field could be tls.certificateRefs or tls.secretRef depending on version. In Gateway API v1 it is tls.certificateRefs (kind Secret by default). There is no secretRef. Check with kubectl explain gateway.spec.listeners.tls.
helm list -A # every release, every namespacehelm get manifest <release-name> -n <namespace> | grep -i "kodekloud/webapp-color:v1"helm uninstall <release-name> -n <namespace> # e.g. helm uninstall atlanta-page-apd -n atlanta-page-04
helm uninstall removes the release’s managed resources; kept objects, CRDs and separately managed persistent data may remain.
[!NOTE]
Beyond the course, check every release in one go:
helm list -A --no-headers | while read n ns _; do helm get manifest $n -n $ns | grep -q "webapp-color:v1" && echo "$n $ns"; done
Requirement: allow ingress to the backend pods only from the frontend namespace and block the database namespace. Do not delete existing policies. Choose and apply the most restrictive candidate that meets the requirement.
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: net-policy-3 namespace: backendspec: podSelector: {} # every pod in backend ingress: - from: - namespaceSelector: matchLabels: name: frontend # only namespaces labelled name=frontend ports: - protocol: TCP port: 80 # and only TCP/80
kubectl apply -f net-pol-3.yaml
This candidate permits TCP/80 from namespaces labelled name=frontend. Background: §7.27/§7.28.
[!CAUTION]
Correction: NetworkPolicies are additive. This candidate cannot revoke traffic allowed by another policy selecting the backend Pods. Inspect every applicable policy (kubectl get netpol -n backend -o yaml) and verify connectivity; obey the task’s instruction to preserve existing policies. See NetworkPolicy semantics.
Beyond the course: check the label actually on the namespace with kubectl get ns --show-labels. If it is missing, use kubernetes.io/metadata.name: frontend, which every namespace has automatically.
Symptom: the ReplicaSet events show exceeded quota: cpu-mem-quota on requests.memory (e.g. used 256Mi, hard 300Mi).
kubectl describe deployment backend-apikubectl describe rs backend-api-<rs-suffix> # FailedCreate ... exceeded quotakubectl describe resourcequota cpu-mem-quota # Used vs Hardkubectl edit deployment backend-api # lower spec.template.spec.containers[].resources.requests.memory, e.g. 90Mikubectl delete rs backend-api-6b6454f5cf # optional: drop the old RS so its pods release quotakubectl get deployment backend-api # READY 3/3
Root cause: the namespace quota is exceeded. Budget replicas × request + requests of other counted Pods ≤ quota, including temporary rollout surge Pods.
If you are not allowed to change the requests, ask for a higher quota (when that is permitted).
Course rationale: the updated template must produce a new ReplicaSet with lower requests. More precisely, editing the Deployment template already triggers that rollout; deleting an old ReplicaSet is not normally required, but its old Pods can consume quota and stall progress. Delete only the old lab ReplicaSet if the task permits it. Background: §2.25 (ResourceQuota), §3.12.
curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.29.2/manifests/custom-resources.yaml# edit: Installation spec.calicoNetwork.ipPools[0].cidr: 172.17.0.0/16kubectl apply -f custom-resources.yamlkubectl run web-app --image=nginx --restart=Neverkubectl get pod web-app -o widePOD_IP=$(kubectl get pod web-app -o jsonpath='{.status.podIP}')kubectl run test --rm -it --image=jrecord/nettools --restart=Never -- curl http://${POD_IP}/ # nginx welcome HTML
Set the IPPool CIDR before pods get IPs. Pods that already have IPs keep them.
[!CAUTION]
Correction:custom-resources.yaml only contains Installation/APIServer custom resources. The Tigera operator must be installed first, or the apply fails with "no matches for kind Installation":
Use create, not apply: the CRDs are too large for the last-applied annotation. Then edit and apply custom-resources.yaml, and watch kubectl get pods -n calico-system until everything is Running.
CSR: signerName is required, usages includes client auth, decode .status.certificate. RBAC subject: kind: User, name = CN.
Static pod: the file goes in /etc/kubernetes/manifestson the target node.
"connection refused :6443" on a kubeadm control plane: check the kubelet first, then the apiserver static pod (crictl ps -a).
Do not delete or edit policies, PVs or other objects the task says to keep. Only change what is asked.
[!NOTE]
Beyond the course:allowVolumeExpansion: true does not give kubernetes.io/no-provisioner a resize controller. Actual expansion requires backend/driver support. Helm uninstall also has exceptions (e.g. kept resources, CRDs and separately managed PVC/data); inspect the release rather than assuming all persistent data was deleted.
Needed: net.ipv4.ip_forward = 1 and net.bridge.bridge-nf-call-iptables = 1. The docs page to use is Creating a cluster with kubeadm / container runtime prerequisites (kubernetes.io docs are allowed in the exam). Background: §11.3.
cat <<EOF | sudo tee /etc/sysctl.d/k8s.confnet.ipv4.ip_forward = 1net.bridge.bridge-nf-call-iptables = 1EOFsudo sysctl --system # apply now and on every bootsysctl net.ipv4.ip_forward # = 1sysctl net.bridge.bridge-nf-call-iptables # = 1# if net.bridge.* keys did not exist, load the module and APPLY AGAIN:sudo modprobe br_netfilterecho "br_netfilter" | sudo tee /etc/modules-load.d/br_netfilter.confsudo sysctl --systemsysctl net.bridge.bridge-nf-call-iptables
sysctl --system may print "permission denied" for unrelated keys. That is fine as long as the two k8s keys are set.
A file in /etc/sysctl.d/ makes the setting persistent. sysctl -w alone is lost on reboot.
kubectl apply -f question2.yamlkubectl get pod pvviewer # Runningkubectl describe pod pvviewer # Service Account: pvviewerkubectl get pod pvviewer -o yaml | grep serviceAccountName # pvviewerkubectl auth can-i list persistentvolumes --as=system:serviceaccount:default:pvviewer # Beyond the course: yes
PVs are cluster-scoped, so this needs a ClusterRole + ClusterRoleBinding. A Role cannot grant it.
--serviceaccount takes <namespace>:<name>.
[!NOTE]
Beyond the course:kubectl run --serviceaccount was removed. Generate the pod with kubectl run pvviewer --image=redis --dry-run=client -o yaml and add serviceAccountName by hand.
apiVersion: storage.k8s.io/v1kind: StorageClassmetadata: name: rancher-scprovisioner: rancher.io/local-pathallowVolumeExpansion: truevolumeBindingMode: WaitForFirstConsumer # binding waits until a pod uses the PVC
kubectl apply -f question3.yamlkubectl get storageclass rancher-sckubectl describe storageclass rancher-sc
kubectl create configmap app-config -n cm-namespace \ --from-literal=ENV=production \ --from-literal=LOG_LEVEL=infokubectl describe cm app-config -n cm-namespacekubectl edit deploy cm-webapp -n cm-namespace # add envFrom (below) under the container
spec: template: spec: containers: - name: <container-name> image: <image> envFrom: # imports every key as an env var - configMapRef: name: app-config
kubectl get pod -n cm-namespace # pods restart (new rollout)kubectl describe pod -n cm-namespace -l app=cm-webappkubectl exec -n cm-namespace <pod-name> -- env | egrep 'ENV|LOG_LEVEL'
[!NOTE]
Beyond the course: kubectl set env deployment/cm-webapp -n cm-namespace --from=configmap/app-config also works. It writes one env[].valueFrom.configMapKeyRef per key instead of envFrom. If the task says envFrom, edit the YAML.
apiVersion: scheduling.k8s.io/v1kind: PriorityClassmetadata: name: low-priorityvalue: 50000globalDefault: falsedescription: "Low priority class for test pods"
kubectl apply -f question5.yamlkubectl get priorityclasskubectl get pod lp-pod -n low-priority -o yaml > question5-pod.yaml# edit: add spec.priorityClassName: low-priority ; delete the numeric spec.priority linekubectl delete pod lp-pod -n low-prioritykubectl apply -f question5-pod.yaml # or skip the delete: kubectl replace --force -f question5-pod.yamlkubectl get pod -n low-priority
[!WARNING]
The exported pod YAML already has priority: 0. If you keep it and add priorityClassName, the API server can reject the pod because the number no longer matches the class. Delete the numeric priority field and let the class set it.
[!NOTE]
Beyond the course:from: [podSelector: {}] limits sources to the policy's own namespace. To allow port 80 from any source, leave out from (just - ports: [...]). Test with kubectl run t --rm -it --image=busybox:1.28 --restart=Never -- wget -qO- -T2 <svc-or-pod-ip>.
kubectl taint node node01 env_type=production:NoSchedulekubectl describe node node01 | grep -i taintkubectl run dev-redis --image=redis:alpine --restart=Never # will not be scheduled on node01
kubectl apply -f question7.yamlkubectl get pod -o wide # prod-redis on node01, dev-redis on another node
[!WARNING]
A toleration only allows scheduling on node01. It does not attract the pod there (§3.11). prod-redis ends up on node01 here only because the other nodes are not suitable (e.g. the tainted control plane). If the task says it must run on node01, also add nodeSelector/nodeName (Beyond the course).
kubectl scale deploy nginx-deploy --replicas=3kubectl get deploy nginx-deploy; kubectl get rs; kubectl get pods # RS stuck at 1kubectl get pod -n kube-system # kube-controller-manager-* in ImagePullBackOff / CrashLoopBackOffsudo vi /etc/kubernetes/manifests/kube-controller-manager.yaml # fix the typo in image / command / volumeskubectl get pod -n kube-system # the kubelet recreates the static pod once the file is savedkubectl get deploy nginx-deploy # 3/3 once the controller reconciles
Deployment → ReplicaSet → Pods scaling is done by the controller-manager. If it is down, kubectl scale updates the spec but nothing creates the pods.
Beyond the course: for errors in args, read kubectl logs -n kube-system kube-controller-manager-controlplane or crictl logs <id>.
helm lint /root/new-version # must report 0 failureshelm install new-version-release /root/new-version # install from the local chart directoryhelm listhelm uninstall webpage-server-01helm list
Beyond the course: if the old release is not in default, find it with helm list -A and add -n <ns> to install/uninstall.
kubectl get node -o jsonpath='{.items[0].spec.podCIDR}' > /root/pod-cidr.txt # first nodekubectl get node controlplane -o jsonpath='{.spec.podCIDR}' > /root/pod-cidr.txt # a specific nodecat /root/pod-cidr.txt # e.g. 172.17.0.0/24
[!NOTE]
Beyond the course:node.spec.podCIDR is the per-node slice (here a /24). The cluster-wide range is in --cluster-cidr (grep cluster-cidr /etc/kubernetes/manifests/kube-controller-manager.yaml), in kubectl -n kube-system get cm kubeadm-config -o yaml | grep podSubnet, or in the kube-proxy ConfigMap clusterCIDR. Read the task wording to decide which one it wants. The course answer uses the node's podCIDR.
[!WARNING]
Exam traps / remember:
Cluster-scoped resources (PVs, nodes, StorageClasses) need a ClusterRole + ClusterRoleBinding.
A pod's priority comes from priorityClassName. Delete the numeric priority field before reapplying.
Exported YAML (-o yaml) contains status, uid, resourceVersion, creationTimestamp. Strip them before recreating, or use kubectl replace --force.
Scaling does nothing: suspect the controller-manager. Pods stay Pending with no node assigned: suspect the scheduler. Fix both in /etc/kubernetes/manifests/.
kubeconfig problems: check server: (host and port 6443), the certificate paths/data, and the context → cluster/user mapping.
Introduction to KodeKloud's Ultimate CKA Mock Exam Series (10 mock exams). Take it after finishing the core course, its mock exams and the lightning labs. The mocks are harder than the course labs on purpose, are timed, and use several clusters.
You start on the student node, a client shell that has contexts for all clusters. Switch with kubectl contexts. SSH to a control-plane or worker node only when a task needs node-level access.
The lab takes ~30 s to load (sometimes 1–2 min) and has ~20 questions. Each question belongs to one domain. You can scroll and jump between questions.
When the timer reaches zero the exam is auto-submitted and graded. End Exam submits early and starts grading. The mock results screen shows the pass mark: 66%.
kubectl config get-clusters # cluster1..cluster4kubectl config use-context cluster3 # switch FIRST, for every questionkubectl get nodes # confirm which cluster you are onkubectl get ns # target namespace existskubectl get secrets -n beta-ns-cka14-arch # beta-sec-cka14-arch Opaque 1kubectl get secret beta-sec-cka14-arch -n beta-ns-cka14-arch -o yaml # data.secret: VGhpcyBpcyB0aGUgc2VjcmV0IQo=echo 'VGhpcyBpcyB0aGUgc2VjcmV0IQo=' | base64 -d # This is the secret!echo 'VGhpcyBpcyB0aGUgc2VjcmV0IQo=' | base64 -d > /opt/beta-sec-cka14-arch # the file goes on the student node
[!NOTE]
Beyond the course, a one-liner with no copy/paste:
kubectl get secret beta-sec-cka14-arch -n beta-ns-cka14-arch -o jsonpath='{.data.secret}' | base64 -d > /opt/beta-sec-cka14-arch (§15.1).
Service account identity for --as: system:serviceaccount:<ns>:<name>.
[!WARNING]
Exam traps / remember:
Read every task for the cluster, namespace and output path it names. Working in the wrong context means the requested cluster was not changed.
Pass --context <ctx> (or run use-context first) so you never change the wrong cluster.
Output files (e.g. /opt/...) go on the student node unless the task says otherwise. Leave any SSH session before writing them.
Practise the troubleshooting routine (logs, events, describe, node-level checks such as kubelet and static pods), since it is worth 30%.
Watch the timer. Unfinished work is graded as it stands when time runs out.
[!NOTE]
Beyond the course:kubectl config get-clusters lists clusters, not contexts. kubectl config get-contexts (and current-context) shows the names use-context accepts. The real CKA is 2 hours with a 66% pass mark, and its exact setup can change (e.g. a per-task ssh <host> instead of contexts). Run whatever setup command the task gives before you start.