KLCP study materials
KLCP study resources

KLCP common mistakes

KLCP · Understand the traps and how to avoid them.

Mistake 1

Writing a Pod spec with containers[].image but no containers[].name, then re-applying the file repeatedly while kubectl rejects it.

Candidates copy fragments from memory or from a previous question and assume name is optional or auto-derived from the image; the API server requires it and the error text is easy to skim past under time pressure.

What to do instead

Before applying any manifest, mentally validate the four required Pod fields: apiVersion, kind, metadata.name, and spec.containers[].name plus spec.containers[].image. Use kubectl apply --dry-run=server -f file.yaml to surface schema errors before committing.

Mistake 2

Confusing kubectl imperative generators: using `kubectl run` expecting a Deployment, or `kubectl create deployment` expecting a bare Pod.

The default object type produced by kubectl run changed across versions, and candidates rely on muscle memory from older clusters or tutorials rather than checking what the command actually creates.

What to do instead

Memorize the explicit forms: kubectl run NAME --image=IMG creates a Pod (use --restart=Never to be certain), while kubectl create deployment NAME --image=IMG creates a Deployment. When unsure, add --dry-run=client -o yaml to see exactly what would be created.

Mistake 3

Assuming a Service will route to Pods without verifying that the Service selector matches the Pod labels and that the Pods are Ready.

Candidates create a Deployment and a Service in separate steps and never cross-check labels; they also forget that Endpoints only include Pods passing readiness probes, so a running-but-unready Pod silently yields an empty EndpointSlice.

What to do instead

After creating both objects, run kubectl get endpointslices -l kubernetes.io/service-name=NAME (or kubectl get endpoints NAME) and confirm addresses are listed. If empty, diff kubectl get svc NAME -o yaml selector keys/values against kubectl get pods --show-labels and check kubectl get pods READY column.

Mistake 4

Setting a container's resource requests higher than the node's allocatable capacity, then debugging the resulting Pending Pod as if it were an image or scheduling-policy problem.

Candidates pick round numbers like cpu: 2 or memory: 4Gi without checking node size, and a Pending Pod produces no container logs, so attention goes to the wrong layer.

What to do instead

On a Pending Pod, run kubectl describe pod NAME and read the Events section for 'Insufficient cpu/memory' and the scheduler message. Compare against kubectl describe node NODE Allocatable minus Allocated resources. Lower requests or add a node before touching image or selector settings.

Mistake 5

Mounting a ConfigMap or Secret as a volume when the referenced key or object does not exist, leaving the Pod stuck in ContainerCreating.

Candidates create the workload first and the config object second, or mistype the object name; the Pod never starts so kubectl logs returns nothing and the real cause is buried in events.

What to do instead

When a Pod is stuck in ContainerCreating, run kubectl describe pod NAME and read events for 'configmap/secret not found' or 'failed to mount'. Verify with kubectl get configmap NAME -o yaml that the object and the specific key exist. For non-critical config, set optional: true on the volume or env source so the Pod can still start.

Mistake 6

Building a multi-stage Dockerfile but copying artifacts from the wrong stage name or path, producing an image that builds locally yet crashes with 'no such file or directory' at runtime.

Candidates use COPY --from=0 or a stale stage alias after renaming stages, and the build succeeds because Docker only validates the source exists at copy time, not that the entrypoint path is correct.

What to do instead

Name each stage explicitly (FROM golang AS build) and reference it by name in COPY --from=build. Set WORKDIR consistently and use an absolute path in ENTRYPOINT/CMD that matches the copy destination. Verify by running the final image locally with docker run --rm IMAGE before pushing.

Mistake 7

Declaring a containerPort or Service targetPort that does not match the port the application actually listens on inside the container.

Candidates assume containerPort is functional rather than informational, and they conflate Service port, targetPort, and the app's bind port, so traffic is forwarded to a closed port.

What to do instead

Treat containerPort as documentation only and make targetPort equal the application's real listening port (check with kubectl exec POD -- netstat -tlnp or the app config). Remember Service port is what clients call, targetPort is the container port. Test end-to-end from inside the cluster with a temporary curl Pod.

Mistake 8

Writing a readiness or liveness probe with a path, port, or scheme that does not match the application, causing restart loops or a Service that never receives endpoints.

Candidates add probes reflexively without confirming the health endpoint exists, and they confuse liveness (restart on failure) with readiness (remove from endpoints on failure), so a wrong liveness probe kills healthy containers.

What to do instead

Confirm the exact health path and port from the app's own configuration, then test it with kubectl exec POD -- wget -qO- localhost:PORT/PATH. Use readiness for traffic gating and liveness only for true deadlock detection; set initialDelaySeconds and failureThreshold high enough for real startup time.

Mistake 9

Treating a Deployment's rolling update as instantly complete and validating the new version before the rollout has actually finished.

Candidates apply a new image and immediately test, but maxUnavailable/maxSurge and readiness gating mean old and new Pods coexist; some traffic still hits the old ReplicaSet, producing inconsistent results that look like a bug.

What to do instead

Always gate on kubectl rollout status deployment/NAME before validating, and use kubectl rollout history plus kubectl rollout undo for recovery. During validation, inspect kubectl get rs to confirm the old ReplicaSet has scaled to zero.

Mistake 10

Designing a workload as a single replica with no PodDisruptionBudget, no anti-affinity, and no graceful shutdown handling, then describing it as highly available.

Candidates equate 'running in Kubernetes' with resilience and overlook that a one-replica Deployment is unavailable during node drains, rolling updates, and voluntary disruptions; they also skip termination handling, so in-flight requests fail.

What to do instead

For availability, use at least two replicas spread with topologySpreadConstraints or podAntiAffinity across nodes/zones, add a PodDisruptionBudget with minAvailable, and implement SIGTERM handling plus a preStop hook and sufficient terminationGracePeriodSeconds so endpoints drain before the process exits.