CertGrid CertGrid
Concepts·Kubernetes and Cloud Native Associate

The KCNA Practice Cluster

Four nodes, Kubernetes 1.36.4, containerd 2.2.6 - and a kubectl one minor behind the server, which is supported and worth understanding rather than fixing.

Orientation Guide 2 of 46 Beginner

Written against the versions above. Domain weights come from the published KCNA curriculum. Check the current one before you book - the Linux Foundation revises it.

One control plane and three workers. Nothing in this path needs a second cluster.
Server NameIP AddressOSRolesCPURAMHDD
CKA1001192.168.0.175Ubuntu 26.04 LTSControl Plane Node2 Core4 GB50 GB
CKA1001-NODE01192.168.0.176Ubuntu 26.04 LTSWorker Node2 Core4 GB50 GB
CKA1001-NODE02192.168.0.177Ubuntu 26.04 LTSWorker Node2 Core4 GB50 GB
CKA1001-NODE03192.168.0.178Ubuntu 26.04 LTSWorker Node2 Core4 GB50 GB

Before you start

  1. Four nodes, one version

    Every node reports v1.36.4, Ubuntu 26.04 LTS, and containerd://2.2.6. Uniformity is deliberate: a mixed-version cluster is a legitimate production state during an upgrade, and a bad place to learn, because you cannot tell whether odd behaviour is the concept or the skew.

    The ROLES column reads because this query asks for a label kubeadm does not set - the role is expressed as node-role.kubernetes.io/control-plane instead. Worth knowing before you go looking for a missing role: plain kubectl get nodes shows it correctly.

    bash Example session
    kubectl --context cka1001 get nodes -o custom-columns=NAME:.metadata.name,ROLES:.metadata.labels.kubernetes\.io/role,VERSION:.status.nodeInfo.kubeletVersion,OS:.status.nodeInfo.osImage,RUNTIME:.status.nodeInfo.containerRuntimeVersionNAME             ROLES    VERSION   OS                 RUNTIMEcka1001          <none>   v1.36.4   Ubuntu 26.04 LTS   containerd://2.2.6cka1001-node01   <none>   v1.36.4   Ubuntu 26.04 LTS   containerd://2.2.6cka1001-node02   <none>   v1.36.4   Ubuntu 26.04 LTS   containerd://2.2.6cka1001-node03   <none>   v1.36.4   Ubuntu 26.04 LTS   containerd://2.2.6

    Expected resultFour nodes on the same Kubernetes version, OS and container runtime.

    Success conditionAll nodes report the same version.

  2. The client is a minor behind the server

    client v1.35.2 / server v1.36.4

    This is supported, not broken. Kubernetes guarantees kubectl works within one minor version either side of the API server, so 1.35 against 1.36 is inside the window.

    What it costs you is narrow and specific: a flag or subcommand added in 1.36 will not exist in your client, and the error looks like the feature is missing from the cluster. When a documented flag is rejected, check the client version before anything else.

    The skew rules matter more generally, because they constrain how you upgrade: the kubelet may be up to three minors behind the API server, but never ahead. Control plane first, always.

    bash Example session
    kubectl --context cka1001 version -o json | python -c "import json,sys; d=json.load(sys.stdin); print('client', d['clientVersion']['gitVersion'], '/ server', d['serverVersion']['gitVersion'])"client v1.35.2 / server v1.36.4

    Expected resultA client version within one minor of the server.

    Success conditionYou know your own skew rather than assuming they match.

  3. What is already on it

    86 Pods and 32 Deployments across these namespaces - Calico, ingress-nginx, CSI drivers, the Prometheus stack, Argo CD, and the leftovers of earlier guides.

    That matters for two reasons. First, this is what a *used* cluster looks like, and reading one is a skill in itself. Second, it explains why later guides create their own namespaces: on a cluster with this much on it, dropping test objects into default becomes impossible to clean up.

    If you are following along on a fresh cluster, expect far fewer Pods and do not try to match these numbers.

    bash Example session
    kubectl --context cka1001 get ns --no-headers | awk '{print $1}' | tr '\n' ' 'argocd calico-system csid default guestbook gw hlm hpa-demo ing ingress-nginx kube-node-lease kube-public kube-system kz local-path-storage metallb-system mlb monitoring nginx-gateway npt npt-other psa-open psa-strict tigera-operator trikubectl --context cka1001 get deploy -A --no-headers | wc -l32kubectl --context cka1001 get pods -A --no-headers | wc -l86

    Expected resultA namespace list, and Deployment and Pod counts well above a fresh install.

    Success conditionYou can see what is running before you add to it.

  4. Is the control plane actually healthy

    /readyz?verbose is the honest health check, and it is worth knowing because kubectl get nodes showing Ready tells you about kubelets, not about the API server.

    Each line is a separate check: etcd ok means storage is reachable, informer-sync ok means the caches are warm, and the poststart hooks confirm initialisation finished. A failing check appears as [-] with a reason, which is far more useful than a timing-out kubectl.

    Run this first whenever the cluster feels wrong. It distinguishes "the API server is unhealthy" from "my request is being denied", which is the fork every investigation starts with.

    bash Example session
    kubectl --context cka1001 get --raw='/readyz?verbose' | head -8[+]ping ok[+]log ok[+]etcd ok[+]etcd-readiness ok[+]informer-sync ok[+]poststarthook/start-apiserver-admission-initializer ok[+]poststarthook/generic-apiserver-start-informers ok[+]poststarthook/priority-and-fairness-config-consumer ok

    Expected resultA list of checks, each [+] ... ok.

    Success conditionEvery readiness check passes.

Troubleshooting

Official sources