KCA study materials
KCA study resources

KCA common mistakes

KCA · Understand the traps and how to avoid them.

Mistake 1

When asked to create a Pod, the candidate writes a Deployment or uses imperative flags that generate a Deployment (e.g., `kubectl create deployment`), or forgets to set `restartPolicy: Never` for a one-shot Pod.

Candidates default to Deployment because it is the most common workload in practice, and they overlook that the task explicitly says Pod. Also, the default restartPolicy is Always, which is wrong for a Pod that should terminate.

What to do instead

Read the task carefully: if it says Pod, use kubectl run <name> --image=<image> --restart=Never or a YAML with kind: Pod. For one-shot tasks, always set restartPolicy: Never or OnFailure. Verify with kubectl get pod <name> -o yaml that the kind is Pod.

Mistake 2

During cluster installation with kubeadm, the candidate runs `kubeadm init` without specifying `--pod-network-cidr`, or forgets to install a CNI plugin, leaving nodes NotReady.

The default kubeadm configuration does not include a pod network CIDR, and many CNI plugins (e.g., Calico, Flannel) require a matching CIDR. Without a CNI, the node's Ready condition remains false.

What to do instead

Always pass --pod-network-cidr that matches the CNI's default (e.g., 10.244.0.0/16 for Flannel, 192.168.0.0/16 for Calico). After init, install the CNI manifest. Verify with kubectl get nodes that the node becomes Ready within a few minutes.

Mistake 3

When configuring a pod to use a ConfigMap or Secret, the candidate mounts the entire object as a volume but then references a specific key as a file path incorrectly, or uses `envFrom` without considering key naming collisions.

Candidates confuse volume mounts (which expose each key as a file) with environment variables. They also forget that envFrom imports all keys and may conflict with existing env vars.

What to do instead

For volume mounts, use volumeMounts.mountPath to the directory and reference the file by key name. For environment variables, use valueFrom.configMapKeyRef or secretKeyRef with the exact key. Test by exec'ing into the pod and checking the file or env var.

Mistake 4

In security contexts, the candidate sets `runAsUser` at the pod level but forgets to set `runAsGroup` or `fsGroup`, causing permission errors when writing to mounted volumes. Or they set `privileged: true` unnecessarily.

Candidates focus on user ID but overlook group ownership and volume permissions. Also, they may default to privileged mode to 'make it work' without understanding the security implications.

What to do instead

For volumes, set fsGroup to the desired group ID so the kubelet changes ownership. Use runAsUser and runAsGroup together. Avoid privileged: true unless explicitly required; use specific capabilities instead. Verify with kubectl exec and id or ls -l on the mounted path.

Mistake 5

When troubleshooting a failing pod, the candidate immediately deletes and recreates it without checking logs or events, or they inspect the wrong namespace.

Candidates panic and try to 'fix' by recreation, losing evidence. They also forget that resources are namespace-scoped and default to default namespace.

What to do instead

First, run kubectl get pod <name> -o wide and kubectl describe pod <name> to see events. Check logs with kubectl logs <name> (and --previous if crashed). Confirm the namespace with -n <namespace>. Only then apply a fix.

Mistake 6

When creating a NetworkPolicy, the candidate writes a policy that selects pods but forgets to specify `policyTypes` or misconfigures ingress/egress rules, resulting in no effect or blocking all traffic.

NetworkPolicy is default-allow if no policy selects the pod. Once selected, if policyTypes is omitted, it defaults to Ingress only. Candidates often forget to allow DNS egress or to specify from/to selectors correctly.

What to do instead

Always specify policyTypes: [Ingress, Egress] if both are needed. For egress, include a rule allowing DNS (UDP/TCP port 53) to kube-dns. Test with kubectl exec and curl/nc from a pod. Use kubectl describe networkpolicy to verify.

Mistake 7

When scheduling a pod to a specific node, the candidate uses `nodeName` instead of `nodeSelector` or affinity, bypassing the scheduler and causing the pod to ignore taints and resource limits.

nodeName is a direct assignment that skips the scheduler, so taints are not honored and the pod may fail if resources are insufficient. Candidates use it as a shortcut.

What to do instead

Use nodeSelector with node labels for simple cases, or affinity.nodeAffinity for complex rules. For taints, add tolerations. Verify with kubectl get pod -o wide that the pod is on the intended node and check events for scheduling failures.

Mistake 8

When creating a PersistentVolumeClaim, the candidate forgets to set `storageClassName` or sets it to an empty string, causing the PVC to remain Pending if no default StorageClass exists.

Candidates assume a default StorageClass is present. In many clusters, especially kubeadm without a cloud provider, no default StorageClass is configured.

What to do instead

Check available StorageClasses with kubectl get storageclass. If none, create one or set storageClassName to match an existing class. If using a static PV, ensure the PVC's storageClassName matches the PV's and that access modes and capacity align.

Mistake 9

When upgrading a cluster with kubeadm, the candidate upgrades the control plane but forgets to upgrade kubelet and kubectl on worker nodes, or drains nodes incorrectly.

The upgrade process requires sequential steps: upgrade control plane, then workers. Candidates may skip kubeadm upgrade node on workers or forget to apt-mark hold/unhold packages.

What to do instead

Follow the official steps: on control plane, kubeadm upgrade plan and kubeadm upgrade apply. On each worker, drain, kubeadm upgrade node, upgrade kubelet/kubectl, then uncordon. Verify versions with kubectl get nodes.

Mistake 10

When configuring RBAC, the candidate creates a Role and RoleBinding but binds to the wrong subject (e.g., user vs. service account) or uses the wrong namespace, resulting in no permissions.

Candidates confuse User and ServiceAccount subjects, and forget that RoleBindings are namespace-scoped while ClusterRoleBindings are cluster-wide.

What to do instead

For a ServiceAccount, use subjects: [{kind: ServiceAccount, name: <sa>, namespace: <ns>}]. For a user, use kind: User. Ensure the RoleBinding is in the same namespace as the Role. Test with kubectl auth can-i <verb> <resource> --as=system:serviceaccount:<ns>:<sa>.