130 lines
5.3 KiB
Markdown
130 lines
5.3 KiB
Markdown
# 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`
|
|
```bash
|
|
kind version # v0.31.x
|
|
helm version # v3.x
|
|
```
|
|
|
|
## 1. Cluster config — `kind-drills.yaml`
|
|
|
|
```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`
|
|
|
|
```bash
|
|
#!/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
|
|
|
|
```bash
|
|
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)
|
|
|
|
```bash
|
|
docker exec drills-worker grep staticPodPath /var/lib/kubelet/config.yaml
|
|
# expect: staticPodPath: /etc/kubernetes/manifests
|
|
```
|
|
|
|
## 5. Teardown / rebuild
|
|
|
|
```bash
|
|
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) | |