These ten questions turn on Kubernetes 5,150 behaviors that catch experienced developers: controllers that undo your edits, a crash loop that rarely says so, rollback history, configuration that changes in one place only, tokens that outlive their request, a policy that blocks DNS, a debugger the namespace refuses, storage that outlives its StatefulSet and a Helm 29,435 value that comes back. Every snippet ran on this chapter's kind 14,561 cluster, l3-booknest (Kubernetes 1.37.0, kubectl 1.37.1 5,150 , Helm 3.22.0), as Observability and Debugging left it, from the BookNest repository. Run the blocks in order in one shell, write down what each prints and why, and only then check Appendix H, which gives the real output, the reason and the section it comes from.
kubectl create namespace ty && kubectl config set-context --current --namespace=ty
I=localhost:33500/booknest-web:1.3
kubectl create configmap q4 --from-literal=level=info
kubectl run server --image=$I -l app=server --port=80 --expose
kubectl run client --image=$I -l role=client
kubectl apply -f - <<'EOF'
apiVersion: v1
kind: Pod
metadata: { name: probe }
spec:
containers:
- { name: c, image: localhost:33500/booknest-web:1.3, command: [sleep, infinity],
env: [{ name: LEVEL, valueFrom: { configMapKeyRef: { name: q4, key: level } } }],
volumeMounts: [{ name: cfg, mountPath: /cfg }, { name: short, mountPath: /short },
{ name: cfg, mountPath: /sub/level, subPath: level }] }
volumes:
- { name: cfg, configMap: { name: q4 } }
- { name: short, projected: { sources: [{ serviceAccountToken: { path: token,
expirationSeconds: 600 } }] } }
EOF
kubectl wait --for=condition=Ready pod --all# 1. Scale a Deployment's ReplicaSet by hand, then delete it. (Sections 6.4.2 and 6.9.1)
kubectl create deployment web --image=$I --replicas=2 >/dev/null
kubectl rollout status deploy/web >/dev/null && RS=$(kubectl get rs -l app=web -o name)
kubectl scale $RS --replicas=5 >/dev/null; sleep 5; kubectl get rs -l app=web
kubectl delete $RS >/dev/null; sleep 5; kubectl get rs -l app=web
# 2. What do these three Pods show after 45 seconds? (Sections 6.8.4 and 6.26.6)
kubectl run exit0 --image=$I -- sh -c 'exit 0' >/dev/null
kubectl run exit1 --image=$I -- sh -c 'exit 1' >/dev/null
kubectl run once1 --image=$I --restart=Never -- sh -c 'exit 1' >/dev/null
sleep 45; kubectl get pods exit0 exit1 once1
kubectl events --types=Warning | grep -o 'Back-off restarting failed container [a-z0-9]*' | sort -u
# 3. Label the next change first, as Section 6.9.3 did, then undo it. (Sections 6.9.2-6.9.4)
kubectl create deployment q3 --image=$I >/dev/null && kubectl rollout status deploy/q3 >/dev/null
kubectl annotate deploy/q3 kubernetes.io/change-cause="GREETING=hello" >/dev/null
kubectl set env deploy/q3 GREETING=hello >/dev/null && kubectl rollout status deploy/q3 >/dev/null
kubectl rollout undo deploy/q3 >/dev/null && kubectl rollout status deploy/q3 >/dev/null
kubectl rollout history deploy/q3; kubectl get deploy q3 -o jsonpath='env={..env}{"\n"}'# 4. Change the ConfigMap, wait 90 seconds, and read it three ways. (Section 6.12.2)
kubectl patch configmap q4 -p '{"data": {"level": "debug"}}' >/dev/null; sleep 90
kubectl exec probe -- sh -c 'echo "env=$LEVEL volume=$(cat /cfg/level) subPath=$(cat /sub/level)"'
# 5. Limits only, then no resources at all in namespace booknest. (Sections 6.16.4 and 6.18.3)
O='{"spec": {"containers": [{"name": "q5", "image": "'$I'", "command": ["sleep", "infinity"],
"resources": {"limits": {"cpu": "100m", "memory": "32Mi"}}}]}}'
kubectl run q5 --image=$I --overrides="$O" >/dev/null
kubectl run q5 -n booknest --image=$I -- sleep infinity >/dev/null 2>&1
kubectl wait --for=condition=Ready pod/q5 >/dev/null
kubectl wait -n booknest --for=condition=Ready pod/q5 >/dev/null
for n in ty booknest; do
kubectl get pod q5 -n $n -o jsonpath='{.status.qosClass} {.spec.containers[0].resources}{"\n"}'
done
# 6. How many seconds does each token live? (Section 6.19.3)
jwt() { jq -R 'split(".")[1] | @base64d | fromjson | .exp - .iat'; }
kubectl exec probe -- cat /var/run/secrets/kubernetes.io/serviceaccount/token | jwt
kubectl exec probe -- cat /short/token | jwt
kubectl create token default | jwt# 7. Allow egress only to the server's port 80. Can the client reach it? (Sections 6.20.3-6.20.4)
kubectl apply -f - <<'EOF'
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: { name: only-server }
spec:
podSelector: {}
policyTypes: [Egress]
egress: [{ to: [{ podSelector: { matchLabels: { app: server } } }], ports: [{ port: 80 }] }]
EOF
IP=$(kubectl get service server -o jsonpath='{.spec.clusterIP}')
for u in server $IP; do kubectl exec client -- wget -qO- -T 3 http://$u/healthz 2>&1 | head -1; done
# 8. Three debugger profiles in namespace booknest (enforce baseline). (Sections 6.20.2, 6.26.4)
P=$(kubectl get pod -n booknest -l tier=api -o name | head -1)
for p in general baseline restricted; do kubectl debug -n booknest $P -q --image=busybox:1.37 \
--profile=$p -c dbg-$p -- true 2>&1 | fold -s -w 95; done
sleep 10; kubectl get -n booknest $P \
-o jsonpath='{range .status.ephemeralContainerStatuses[*]}{.name} {.state.*.reason}{"\n"}{end}'
# 9. Delete PostgreSQL's StatefulSet, then apply it again. (Sections 6.14.3 and 6.14.4)
kubectl delete -n booknest statefulset postgres >/dev/null
kubectl wait -n booknest --for=delete pod/postgres-0 >/dev/null; kubectl get pvc -n booknest
kubectl apply -n booknest -f k8s/postgres.yaml >/dev/null 2>&1
kubectl rollout status -n booknest sts/postgres >/dev/null
kubectl exec -n booknest postgres-0 -- psql -U booknest -tAc 'SELECT count(*) FROM books'
# 10. Install the chart without its database, then change one other value. (Section 6.22.7)
helm install q10 helm/booknest --no-hooks --set postgres.enabled=false,db.host=db >/dev/null
helm upgrade q10 helm/booknest --no-hooks --set web.replicas=1 >/dev/null
helm get values q10; kubectl get statefulsets -o name