Files
kodekloud-engineer/kubernetes/mock exams/cka-exams-env-setup.md

5.3 KiB

CKA Range Bring-Up — kind + Cilium (matches Mock Exam Pack v1)

Produces cluster drills on Kubernetes v1.35.0 (= exam version) with nodes named exactly as the drill/mock packs expect: drills-control-plane, drills-worker, drills-worker2. CNI: Cilium 1.19.x — real NetworkPolicy enforcement (kindnet has none; netpol drills would silently pass on it). Versions verified 2026-07-29. Re-check pins if you're reading this much later: kind releases page, cilium.io stable docs.


0. Host prerequisites

  • Docker (or compatible), ≥ 8GB RAM free for the 3 nodes
  • cgroup v2 on the host — mandatory: k8s 1.35 node images dropped cgroup v1. Check: stat -fc %T /sys/fs/cgroup → must print cgroup2fs. Any current distro qualifies.
  • Tools: kind ≥ v0.31.0 (ships the v1.35.0 default image), kubectl, helm
    kind version        # v0.31.x
    helm version        # v3.x
    

1. Cluster config — kind-drills.yaml

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: drills                     # ⇒ node names drills-control-plane / drills-worker / drills-worker2
networking:
  disableDefaultCNI: true        # kindnet out, Cilium in
nodes:
- role: control-plane
  image: kindest/node:v1.35.0    # pin explicitly = exam version, survives kind upgrades
- role: worker
  image: kindest/node:v1.35.0
- role: worker
  image: kindest/node:v1.35.0

Note: kube-proxy stays (default). Do NOT enable Cilium's kube-proxy replacement — the exam cluster runs kube-proxy, and iptables-visible Services are part of the troubleshooting surface you're training.

2. Bring-up — range-up.sh

#!/usr/bin/env bash
set -euo pipefail
CILIUM_VER=1.19.6

kind create cluster --config kind-drills.yaml
# nodes will sit NotReady until CNI lands — expected

# --- Cilium (per cilium.io kind guide) ---
docker pull quay.io/cilium/cilium:v${CILIUM_VER}
kind load docker-image quay.io/cilium/cilium:v${CILIUM_VER} --name drills   # skip registry pulls on each node

helm repo add cilium https://helm.cilium.io/ 2>/dev/null; helm repo update
helm install cilium cilium/cilium --version ${CILIUM_VER} \
  --namespace kube-system \
  --set image.pullPolicy=IfNotPresent \
  --set ipam.mode=kubernetes

kubectl -n kube-system rollout status ds/cilium --timeout=180s
kubectl wait --for=condition=Ready node --all --timeout=180s

# --- Gateway API CRDs (standard channel) ---
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.1/standard-install.yaml

# --- metrics-server (for HPA TARGETS + kubectl top) ---
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
kubectl -n kube-system patch deploy metrics-server --type=json \
  -p='[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]'
# ^ mandatory on kind: kubelet serves self-signed certs; without this metrics-server never goes Ready

# --- helm repo used by drill K4 / mock Q8 ---
helm repo add bitnami https://charts.bitnami.com/bitnami 2>/dev/null; helm repo update

echo "RANGE UP"

3. Smoke test — run before ANY drill session

kubectl get nodes -o wide
# drills-control-plane / drills-worker / drills-worker2 — all Ready, VERSION v1.35.0

kubectl get pods -A | grep -v Running | grep -v Completed     # empty
kubectl api-resources | grep -i httproute                     # gateway.networking.k8s.io present
kubectl top nodes                                             # numbers (may need ~60s after install)
kubectl -n kube-system exec ds/cilium -- cilium status --brief # OK

# NetworkPolicy ENFORCEMENT check — the one that matters (kindnet would pass traffic anyway):
kubectl create ns smoke
kubectl -n smoke run a --image=nginx --labels=app=a --port=80
kubectl -n smoke run b --image=busybox -- sleep 600
kubectl -n smoke wait --for=condition=Ready pod --all --timeout=60s
kubectl -n smoke apply -f - <<'EOF'
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: {name: deny-all}
spec:
  podSelector: {}
  policyTypes: [Ingress]
EOF
AIP=$(kubectl -n smoke get pod a -o jsonpath='{.status.podIP}')
kubectl -n smoke exec b -- wget -qO- -T 2 $AIP && echo "FAIL: netpol NOT enforced" || echo "OK: netpol enforced"
kubectl delete ns smoke --wait=false

If that last line prints FAIL, the CNI install went sideways — do not run K1/Q3 until fixed (kubectl -n kube-system logs ds/cilium | tail).

4. Static pod path sanity (mock Q17 depends on it)

docker exec drills-worker grep staticPodPath /var/lib/kubelet/config.yaml
# expect: staticPodPath: /etc/kubernetes/manifests

5. Teardown / rebuild

kind delete cluster --name drills          # full nuke, ~10s
# rebuild = run range-up.sh again, ~3 min total

Rebuild is cheap — prefer a fresh cluster over archaeologically cleaning a broken one between mock attempts. The mock pack's RESET script is for same-day reruns; a new day gets a new cluster.

6. Known deltas vs the real exam (accept, don't fight)

Real exam This range
ssh nodeX docker exec -it drills-<node> bash
multiple kubectl contexts one context; discipline = read each task's target ns/node
kubeadm package upgrades (apt) not possible — node image is baked; upgrade tasks stay on KodeKloud/killer
several CNIs possible Cilium everywhere (netpol semantics are standard, so drills transfer)