From 9715b45481a34ade1af527f0749a735b1539e2eb Mon Sep 17 00:00:00 2001 From: vumast3r Date: Mon, 7 Sep 2026 12:03:05 -0600 Subject: [PATCH] docs: CKA_SOLUTIONS_EXPLAINED.md created to give a depper step-by-step guide and understanding of the exam --- CKA_SOLUTIONS_EXPLAINED.md | 661 +++++++++++++++++++++++++++++++++++++ 1 file changed, 661 insertions(+) create mode 100644 CKA_SOLUTIONS_EXPLAINED.md diff --git a/CKA_SOLUTIONS_EXPLAINED.md b/CKA_SOLUTIONS_EXPLAINED.md new file mode 100644 index 0000000..c3d2d5c --- /dev/null +++ b/CKA_SOLUTIONS_EXPLAINED.md @@ -0,0 +1,661 @@ +# CKA Simulator — Step-by-Step Solutions & Conceptual Guide + +This guide explains how to approach and solve every question in the CKA exam bank. It breaks down the **underlying Kubernetes concepts**, **the step-by-step commands**, **why specific flags are used**, and **how to verify your solution** before submitting. + +--- + +## Domain 1: Cluster Architecture, Installation & Configuration (25%) + +### Q01 · RBAC for a Deployment Bot +- **Concept**: Role-Based Access Control (RBAC) separates permissions using `Roles` (namespaced) and `ClusterRoles` (cluster-wide), bound to users/ServiceAccounts via `RoleBindings` or `ClusterRoleBindings`. +- **Step-by-Step**: + 1. Create the ServiceAccount in the target namespace: + ```bash + k -n rbac-app create sa deploy-bot + ``` + 2. Create the Role with explicit verbs on `deployments.apps`: + ```bash + k -n rbac-app create role deploy-manager \ + --verb=get,list,watch,create,update,patch,delete \ + --resource=deployments.apps + ``` + 3. Bind the Role to the ServiceAccount: + ```bash + k -n rbac-app create rolebinding deploy-bot-binding \ + --role=deploy-manager \ + --serviceaccount=rbac-app:deploy-bot + ``` + 4. **Verify** using `kubectl auth can-i`: + ```bash + k auth can-i create deployments -n rbac-app --as=system:serviceaccount:rbac-app:deploy-bot # yes + k auth can-i delete pods -n rbac-app --as=system:serviceaccount:rbac-app:deploy-bot # no + ``` + +--- + +### Q02 · etcd Snapshot +- **Concept**: etcd stores all cluster state. Snapshots require TLS certificates (CA cert, server cert, server key) and `ETCDCTL_API=3`. +- **Step-by-Step**: + 1. SSH / access the control plane node (`podman exec -it bash` or `ssh `). + 2. Run `etcdctl snapshot save` pointing to the etcd TLS certificates: + ```bash + ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \ + --cacert=/etc/kubernetes/pki/etcd/ca.crt \ + --cert=/etc/kubernetes/pki/etcd/server.crt \ + --key=/etc/kubernetes/pki/etcd/server.key \ + snapshot save /opt/cka/etcd-snapshot.db + ``` + 3. **Verify** snapshot integrity: + ```bash + etcdutl snapshot status /opt/cka/etcd-snapshot.db -w table + ``` + +--- + +### Q03 · Kustomize Overlay +- **Concept**: Kustomize allows environment-specific customization (like `prod` overlays) without templating YAMLs. +- **Step-by-Step**: + 1. Create the overlay folder: `mkdir -p workspace/q03/overlays/prod && cd workspace/q03/overlays/prod` + 2. Create `namespace.yaml` for `store-prod`. + 3. Write `kustomization.yaml` referencing `../../base`, adding namespace, labels, and replica count. + 4. Apply via `kubectl apply -k .` + 5. **Verify**: `k -n store-prod get deploy,pod -l env=prod` + +--- + +### Q04 · CustomResourceDefinition (CRD) & Custom Resource +- **Concept**: CRDs extend Kubernetes APIs with custom objects. Schema validation uses OpenAPI v3. +- **Step-by-Step**: + 1. Create the `CustomResourceDefinition` YAML specifying `group`, `names`, `scope: Namespaced`, and `openAPIV3Schema`. + 2. Apply the CRD: `k apply -f crd.yaml`. + 3. Instantiate the Custom Resource (`Backup` named `nightly`). + 4. **Verify**: `k get bk` or `k get backups`. + +--- + +### Q05 · Static Pod Creation +- **Concept**: Static pods are managed directly by the Kubelet on a specific node without API server scheduling. Kubelet creates a mirror pod in the API server. +- **Step-by-Step**: + 1. SSH / access the target node. + 2. Check static pod path: `grep staticPodPath /var/lib/kubelet/config.yaml` (usually `/etc/kubernetes/manifests`). + 3. Create the pod manifest in that directory: `/etc/kubernetes/manifests/static-web.yaml`. + 4. **Verify**: Kubelet creates the mirror pod within seconds: `k get pods -o wide | grep static-web`. + +--- + +### Q06 · Certificate Expiry & User CSR +- **Concept**: Kubeadm manages control-plane certs. Kubernetes CSR API (`certificates.k8s.io/v1`) signs and approves client certificates. +- **Step-by-Step**: + 1. On the control plane: `kubeadm certs check-expiration | grep '^apiserver ' > apiserver-expiry.txt`. + 2. Generate user private key and CSR with OpenSSL: + ```bash + openssl genrsa -out jane.key 2048 + openssl req -new -key jane.key -subj "/CN=jane" -out jane.csr + ``` + 3. Submit `CertificateSigningRequest` with `base64 -w0 jane.csr` and signer `kubernetes.io/kube-apiserver-client`. + 4. Approve: `k certificate approve jane`. + 5. Extract certificate: `k get csr jane -o jsonpath='{.status.certificate}' | base64 -d > jane.crt`. + 6. Create RoleBinding binding user `jane` to ClusterRole `view`. + +--- + +### Q33 · Aggregated ClusterRole +- **Concept**: Aggregated ClusterRoles automatically aggregate permissions from other ClusterRoles that have matching labels defined in `aggregationRule.clusterRoleSelectors`. +- **Step-by-Step**: + 1. Create the parent ClusterRole with `aggregationRule: {clusterRoleSelectors: [{matchLabels: {rbac.example.com/aggregate-to-parent: "true"}}]}` and `rules: []`. + 2. Create sub-ClusterRoles (`pods`, `services`) with required verbs. + 3. Label the sub-ClusterRoles to trigger aggregation. + 4. Bind the parent ClusterRole to the user via `ClusterRoleBinding`. + 5. **Verify**: `k get clusterrole -o yaml` (rules will be automatically populated). + +--- + +### Q34 · Discover CRD Field with `kubectl explain` +- **Concept**: `kubectl explain . --recursive` inspects the live schema for any built-in or custom resource. +- **Step-by-Step**: + 1. Inspect CRD schema: `k explain .spec --recursive`. + 2. Check field description: `k explain .spec.tuning.`. + 3. Write path to file: `echo spec.tuning. > path.txt`. + 4. Create sample custom resource with that field configured. + +--- + +### Q40 · Kubeadm Join Token Creation +- **Concept**: `kubeadm token create` generates authentication bootstrap tokens used by new nodes to join the cluster. +- **Step-by-Step**: + 1. On control plane: `kubeadm token create --ttl 1h --print-join-command`. + 2. Save output to `join.sh`. + 3. Verify with `kubeadm token list`. + +--- + +### Q41 · Component Versions Inspection +- **Concept**: Control-plane components run as static pods; Kubelet runs as a systemd service. +- **Step-by-Step**: + 1. Server version: `k version`. + 2. Node versions: `k get node -o jsonpath='{.status.nodeInfo.kubeletVersion} {.status.nodeInfo.containerRuntimeVersion}'`. + 3. etcd version: `k -n kube-system get pod -l component=etcd -o jsonpath='{.items[0].spec.containers[0].image}'`. + +--- + +### Q101 · [HARD] RBAC Cleanup & Granular Privileges +- **Concept**: Principle of least privilege. Remove over-privileged admin bindings before granting surgical access. +- **Step-by-Step**: + 1. Find and delete over-granting binding: `k delete clusterrolebinding -legacy-admin`. + 2. Create Role for deployments & replicasets: `k -n create role -role --verb=get,list,watch,patch --resource=deployments.apps,replicasets.apps`. + 3. Add `pods/exec` create permissions to the Role. + 4. Create ClusterRole with `list` on `nodes` and bind it. + 5. **Verify**: `k auth can-i --list -n --as=system:serviceaccount::`. + +--- + +### Q102 · [HARD] etcd Restore +- **Concept**: Restoring etcd from a snapshot requires stopping etcd, restoring data to a new data directory, and updating the etcd static pod hostPath volume. +- **Step-by-Step**: + 1. On control plane, restore snapshot: `etcdutl snapshot restore /opt/cka/backup.db --data-dir /var/lib/etcd-restore`. + 2. Edit `/etc/kubernetes/manifests/etcd.yaml`: + - Update the `etcd-data` hostPath volume path from `/var/lib/etcd` to `/var/lib/etcd-restore`. + 3. Wait for Kubelet to restart etcd and the API server to reconnect (`watch crictl ps`). + 4. **Verify**: `k get cm `. + +--- + +### Q103 · [HARD] Static Pod on Relocated Path +- **Concept**: Some nodes may have custom `staticPodPath` configured in `/var/lib/kubelet/config.yaml` instead of `/etc/kubernetes/manifests`. +- **Step-by-Step**: + 1. Find target node: `k get nodes -l tier=edge`. + 2. On node, inspect `grep staticPodPath /var/lib/kubelet/config.yaml`. + 3. Write pod manifest directly into that specific directory. + 4. **Verify**: `k get pods -n -o wide`. + +--- + +### Q104 · [HARD] Self-Contained Kubeconfig Creation +- **Concept**: A portable kubeconfig embeds all certificates using `--embed-certs` rather than referencing file paths. +- **Step-by-Step**: + 1. Issue & approve CSR for the user; save `user.crt` and `user.key`. + 2. Extract cluster CA: `k config view --minify --raw -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' | base64 -d > ca.crt`. + 3. Set cluster, credentials, context, and current-context with `--kubeconfig= --embed-certs`. + 4. **Verify**: `kubectl --kubeconfig= get pods`. + +--- + +### Q122 · [HARD] Renew Control Plane Certificates +- **Concept**: `kubeadm certs renew all` generates new certificates for all control-plane components. Static pods must be bounced to reload the new certs. +- **Step-by-Step**: + 1. On control plane: `kubeadm certs renew all`. + 2. Bounce static pods: `mv /etc/kubernetes/manifests/*.yaml /tmp/ && sleep 20 && mv /tmp/*.yaml /etc/kubernetes/manifests/`. + 3. Update admin config: `cp /etc/kubernetes/admin.conf ~/.kube/config`. + 4. **Verify**: `kubeadm certs check-expiration`. + +--- + +## Domain 2: Workloads & Scheduling (15%) + +### Q07 · Rolling Update Strategy & Scaling +- **Concept**: `maxSurge` controls how many extra pods can be created during updates; `maxUnavailable` controls how many pods can be unavailable. +- **Step-by-Step**: + 1. Update image: `k -n apps set image deploy web-frontend nginx=nginx:1.27`. + 2. Scale replicas: `k -n apps scale deploy web-frontend --replicas=4`. + 3. Patch strategy: `k -n apps patch deploy web-frontend -p '{"spec":{"strategy":{"rollingUpdate":{"maxSurge":1,"maxUnavailable":0}}}}'`. + 4. **Verify**: `k -n apps rollout status deploy web-frontend`. + +--- + +### Q08 · Sidecar Container & Shared Volume +- **Concept**: Multi-container pods share volumes (`emptyDir`) and localhost network namespace. +- **Step-by-Step**: + 1. Define Pod with an `emptyDir` volume mounted at `/var/log` in both the app container and sidecar container. + 2. App writes logs to `/var/log/app.log`; sidecar runs `tail -f /var/log/app.log`. + 3. **Verify**: `k -n apps logs log-shipper -c shipper`. + +--- + +### Q09 · Node Affinity & Resource Requests/Limits +- **Concept**: `nodeAffinity` matches node labels (`requiredDuringSchedulingIgnoredDuringExecution`). Resource `requests` are used for scheduling; `limits` enforce runtime boundaries. +- **Step-by-Step**: + 1. Create deployment template: `k -n apps create deploy cache --image=redis:7-alpine --replicas=2 $do > cache.yaml`. + 2. Add `affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution` with `matchExpressions: [{key: disktype, operator: In, values: [ssd]}]`. + 3. Add `resources: {requests: {cpu: 100m, memory: 64Mi}, limits: {cpu: 200m, memory: 128Mi}}`. + 4. Apply and verify scheduling: `k -n apps get pods -o wide`. + +--- + +### Q10 · ConfigMap & Secret Consumption +- **Concept**: ConfigMaps and Secrets can be mounted as files via volumes, loaded as individual environment variables (`valueFrom`), or loaded entirely (`envFrom`). +- **Step-by-Step**: + 1. Create ConfigMap: `k -n apps create cm app-config --from-literal=APP_MODE=production --from-literal=LOG_LEVEL=debug`. + 2. Create Secret: `k -n apps create secret generic db-creds --from-literal=username=admin --from-literal='password=S3cr3t!'`. + 3. In Pod spec: mount ConfigMap as volume at `/etc/config`, inject `APP_MODE` from CM, and use `envFrom` for `db-creds`. + 4. **Verify**: `k -n apps exec config-pod -- ls /etc/config` and `k -n apps exec config-pod -- env`. + +--- + +### Q23 · Metrics Server Repair & HPA +- **Concept**: Metrics Server provides CPU/memory metrics for `kubectl top` and Horizontal Pod Autoscalers. In non-production/kind environments, `--kubelet-insecure-tls` is required. +- **Step-by-Step**: + 1. Edit metrics-server deployment: `k -n kube-system edit deploy metrics-server`. Add `--kubelet-insecure-tls` under container args. + 2. Verify: `k top nodes`. + 3. Create HPA: `k -n autoscale deploy --min=2 --max= --cpu-percent=`. + 4. **Verify**: `k -n get hpa`. + +--- + +### Q24 · PriorityClass +- **Concept**: PriorityClasses determine pod preemption and scheduling order. Higher value = higher priority. +- **Step-by-Step**: + 1. Create `PriorityClass` with `value: ` and `globalDefault: false`. + 2. Assign `priorityClassName: ` in the Deployment pod template spec. + 3. **Verify**: `k -n rollout status deploy `. + +--- + +### Q25 · Taints & Tolerations +- **Concept**: Taints repel pods (`NoSchedule`, `PreferNoSchedule`, `NoExecute`). Pods require matching tolerations to be scheduled on tainted nodes. +- **Step-by-Step**: + 1. Taint node: `k taint node key=val:NoSchedule`. + 2. Add toleration to deployment pod spec: + ```yaml + tolerations: + - key: "key" + operator: "Equal" + value: "val" + effect: "NoSchedule" + ``` + 3. Set `nodeSelector: {kubernetes.io/hostname: }`. + +--- + +### Q26 · DaemonSet on All Nodes (including Control Plane) +- **Concept**: DaemonSets ensure all (or some) nodes run a copy of a pod. To run on control-plane nodes, they must tolerate control-plane taints (`node-role.kubernetes.io/control-plane:NoSchedule`). +- **Step-by-Step**: + 1. Write `DaemonSet` YAML with toleration: + ```yaml + tolerations: + - key: node-role.kubernetes.io/control-plane + operator: Exists + effect: NoSchedule + ``` + 2. Apply and verify: `k -n get pods -o wide -l app=`. + +--- + +### Q27 · CronJob Configuration +- **Concept**: CronJobs create Jobs on a time schedule (`schedule: "*/5 * * * *"`). `concurrencyPolicy: Forbid` ensures jobs do not overlap. +- **Step-by-Step**: + 1. Create CronJob: `k -n create cj --image=busybox:1.36 --schedule='*/5 * * * *' $do -- date > cj.yaml`. + 2. Add `concurrencyPolicy: Forbid`, `successfulJobsHistoryLimit: 3`, `failedJobsHistoryLimit: 1`, `activeDeadlineSeconds: 30`. + 3. Trigger manual execution: `k -n create job -manual --from=cronjob/`. + +--- + +### Q28 · Init Containers +- **Concept**: Init containers run to completion sequentially before application containers start. +- **Step-by-Step**: + 1. Define `initContainers` block in Pod spec with shared volume mount (`/work`). + 2. Init container writes content (`echo 'hello' > /work/index.html`). + 3. Main container mounts shared volume at `/usr/share/nginx/html`. + 4. **Verify**: `k -n exec -c web -- cat /usr/share/nginx/html/index.html`. + +--- + +### Q29 · Immutable ConfigMap Rotation +- **Concept**: Setting `immutable: true` on ConfigMaps prevents accidental updates and reduces API server load. To update apps, create a new ConfigMap (`v2`) and update Deployment volume references. +- **Step-by-Step**: + 1. Create `cm-v2` with `immutable: true`. + 2. Patch Deployment volume to point to `cm-v2`. + 3. Monitor rolling update: `k -n rollout status deploy `. + +--- + +### Q31 · Parallel Job +- **Concept**: Batch Jobs manage batch tasks. `completions` is total tasks to complete; `parallelism` is max concurrent pods. +- **Step-by-Step**: + 1. Define Job with `completions: 4`, `parallelism: 2`, `backoffLimit: 2`, `restartPolicy: Never`. + 2. Apply and wait: `k -n wait --for=condition=complete job/ --timeout=120s`. + +--- + +### Q32 · ResourceQuota & LimitRange +- **Concept**: `ResourceQuota` enforces aggregate consumption limits in a namespace; `LimitRange` enforces default/min/max resource requests and limits on individual containers. +- **Step-by-Step**: + 1. Create quota: `k -n create quota --hard=pods=4,requests.cpu=1,limits.memory=2Gi`. + 2. Create LimitRange with `default`, `defaultRequest`, `min`, `max`. + 3. **Verify**: `k -n describe quota` and `k -n describe limitrange`. + +--- + +### Q107 · [HARD] Anti-Affinity under Strict Quota +- **Concept**: Spread replicas across distinct nodes using `podAntiAffinity` while ensuring total resource requests do not breach namespace quotas. +- **Step-by-Step**: + 1. Inspect quota: `k -n get quota`. + 2. Configure deployment with `podAntiAffinity` on `topologyKey: kubernetes.io/hostname`. + 3. Size container requests to fit within namespace quota. + 4. **Verify**: Each pod runs on a distinct node (`k get pods -o wide`). + +--- + +### Q108 · [HARD] Rollback Revision and Pause Rollout +- **Concept**: `rollout undo --to-revision=N` rolls back to a specific ReplicaSet revision. `rollout pause` halts further container rollout. +- **Step-by-Step**: + 1. Inspect history: `k -n rollout history deploy `. + 2. Undo: `k -n rollout undo deploy --to-revision=`. + 3. Pause: `k -n rollout pause deploy `. + +--- + +### Q109 · [HARD] Native Sidecar Container (K8s 1.28+) +- **Concept**: Native sidecar containers are defined in `initContainers` with `restartPolicy: Always`. They start before app containers and keep running throughout the pod's life. +- **Step-by-Step**: + 1. Define initContainer with `restartPolicy: Always` and readiness probe. + 2. Define main container with liveness probe. + 3. **Verify**: `k -n get pod ` shows all containers running. + +--- + +## Domain 3: Services & Networking (20%) + +### Q11 · NetworkPolicy (Ingress Restriction) +- **Concept**: By default, pods accept traffic from any source. A `NetworkPolicy` selects target pods with `podSelector` and restricts traffic using ingress/egress rules. +- **Step-by-Step**: + 1. Create NetworkPolicy in namespace: + ```yaml + apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: {name: allow-frontend, namespace: marketing} + spec: + podSelector: {matchLabels: {app: api}} + policyTypes: [Ingress] + ingress: + - from: + - podSelector: {matchLabels: {role: frontend}} + ports: + - protocol: TCP + port: 80 + ``` + 2. **Verify**: `k -n marketing describe netpol allow-frontend`. + +--- + +### Q12 · NodePort Service +- **Concept**: `NodePort` exposes the Service on each Node's IP at a static port (default range: 30000–32767). +- **Step-by-Step**: + 1. Expose deployment: `k -n web expose deploy web-server --type=NodePort --port=80 --target-port=80 $do > svc.yaml`. + 2. Edit `spec.ports[0].nodePort: 30080`. + 3. Apply and verify: `k -n web get svc web-server` and `k -n web get endpoints web-server`. + +--- + +### Q13 · Ingress Routing +- **Concept**: Ingress manages external HTTP/HTTPS routing to cluster Services based on hostname and URI path prefixes. +- **Step-by-Step**: + 1. Create Ingress imperatively: + ```bash + k -n web create ingress web-ingress \ + --class=nginx \ + --rule="order.example.com/api*=order-service:8080" + ``` + 2. **Verify**: `k -n web describe ingress web-ingress`. + +--- + +### Q14 · Cluster DNS Querying +- **Concept**: Services get DNS names in the format `..svc.cluster.local`. Pods with IP `a.b.c.d` get `..pod.cluster.local`. +- **Step-by-Step**: + 1. Run transient debug pod: `k run dns-test --image=busybox:1.36 --rm -it --restart=Never -- nslookup web-service.apps.svc.cluster.local`. + 2. Query pod IP record: `nslookup 10-244-1-5.apps.pod.cluster.local`. + +--- + +### Q22 · Gateway API Configuration +- **Concept**: Gateway API is the modern successor to Ingress. `GatewayClass` defines the controller, `Gateway` defines listeners/ports, and `HTTPRoute` defines routing rules. +- **Step-by-Step**: + 1. Create `GatewayClass` (`controllerName: example.com/gw`). + 2. Create `Gateway` with HTTP listener on port 80. + 3. Create `HTTPRoute` attaching to the Gateway with path prefix matching `/api` forwarding to target service. + 4. **Verify**: `k -n get gateway,httproute`. + +--- + +### Q30 · Named Ports in Service +- **Concept**: Services can map `targetPort` to the `name` of a container port rather than a numeric port. +- **Step-by-Step**: + 1. In Pod/Deployment container: `ports: [{name: http-web, containerPort: 80}]`. + 2. In Service: `ports: [{name: http, port: 8080, targetPort: http-web}]`. + 3. **Verify**: `k -n get endpoints `. + +--- + +### Q42 · Egress-Only NetworkPolicy +- **Concept**: Egress NetworkPolicies restrict outbound traffic from pods to specific IP CIDR blocks or namespaces. +- **Step-by-Step**: + 1. Define policy with `policyTypes: [Egress]`. + 2. Add `egress: [{to: [{ipBlock: {cidr: 192.168.1.0/24}}], ports: [{port: 443}]}]`. + 3. **Verify**: `k -n describe netpol `. + +--- + +### Q43 · Headless & ExternalName Services +- **Concept**: `clusterIP: None` (Headless) returns direct Pod IPs on DNS queries. `type: ExternalName` returns a CNAME pointing to an external domain. +- **Step-by-Step**: + 1. Create Headless Service: `spec.clusterIP: None`, `spec.selector: {app: db}`. + 2. Create ExternalName Service: `spec.type: ExternalName`, `spec.externalName: api.partner.com`. + 3. **Verify**: `k -n get svc`. + +--- + +### Q111 · [HARD] Zero-Trust Namespace Network Policies +- **Concept**: Zero-trust architecture starts with default-deny on both ingress and egress, then explicitly allows DNS to kube-system (port 53 UDP/TCP) and tiered service-to-service communication. +- **Step-by-Step**: + 1. Create `default-deny` for both `[Ingress, Egress]`. + 2. Create `allow-dns` egress policy to `kube-system` on port 53. + 3. Create `api-ingress` from external labeled namespace. + 4. Create `api-to-db` egress and `db-ingress` policies on port 5432. + +--- + +### Q112 · [HARD] TLS Ingress with Certificate & Fingerprint +- **Concept**: Secure Ingress with TLS Secrets containing `tls.crt` and `tls.key`. +- **Step-by-Step**: + 1. Generate TLS key and self-signed certificate: + ```bash + openssl req -x509 -newkey rsa:2048 -nodes -days 365 -subj "/CN=" -keyout tls.key -out tls.crt + ``` + 2. Create TLS secret: `k -n create secret tls -tls --cert=tls.crt --key=tls.key`. + 3. Create Ingress with `tls: [{hosts: [], secretName: -tls}]` and annotation `nginx.ingress.kubernetes.io/ssl-redirect: "true"`. + 4. Extract fingerprint: `openssl x509 -in tls.crt -noout -fingerprint -sha256 | cut -d= -f2 > fp.txt`. + +--- + +### Q114 · [HARD] Multi-Fault CoreDNS Repair +- **Concept**: CoreDNS failures can be caused by blocking NetworkPolicies in `kube-system`, deployment scaled to 0, or bad upstream forwarding in `Corefile`. +- **Step-by-Step**: + 1. Check and delete rogue NetworkPolicy in `kube-system`: `k -n kube-system delete netpol maintenance-lockdown`. + 2. Scale CoreDNS back to 2 replicas: `k -n kube-system scale deploy coredns --replicas=2`. + 3. Fix `Corefile` in ConfigMap: `k -n kube-system edit cm coredns` (change `forward . ` to `forward . /etc/resolv.conf`). + 4. Restart: `k -n kube-system rollout restart deploy coredns`. + +--- + +## Domain 4: Storage (10%) + +### Q15 · PersistentVolume, PVC & Pod Mounting +- **Concept**: `PersistentVolume` (PV) represents physical cluster storage; `PersistentVolumeClaim` (PVC) is a request for storage by a user. +- **Step-by-Step**: + 1. Create PV: `capacity: 1Gi`, `accessModes: [ReadWriteOnce]`, `persistentVolumeReclaimPolicy: Retain`, `storageClassName: manual`, `hostPath: {path: /mnt/data}`. + 2. Create PVC: `storageClassName: manual`, `requests.storage: 500Mi`. + 3. Create Pod referencing PVC under `spec.volumes` and mounting it in the container. + 4. **Verify**: `k get pv` and `k -n storage get pvc` show `Bound`. + +--- + +### Q16 · Default StorageClass & Dynamic Provisioning +- **Concept**: When a PVC omits `storageClassName`, Kubernetes provisions storage using the StorageClass annotated with `storageclass.kubernetes.io/is-default-class: "true"`. +- **Step-by-Step**: + 1. Create new StorageClass with annotation `storageclass.kubernetes.io/is-default-class: "true"`. + 2. Remove default annotation from old StorageClass: `k annotate sc storageclass.kubernetes.io/is-default-class-`. + 3. Create PVC without `storageClassName` and attach to Pod. + 4. **Verify**: Storage is dynamically created and bound upon pod scheduling (`WaitForFirstConsumer`). + +--- + +### Q35 · Re-bind Released PersistentVolume +- **Concept**: When a PVC is deleted, a PV with `Retain` policy enters `Released` status because `spec.claimRef` still points to the old PVC UID. Removing `spec.claimRef` returns it to `Available`. +- **Step-by-Step**: + 1. Remove old claimRef: `k patch pv --type=json -p='[{"op":"remove","path":"/spec/claimRef"}]'`. + 2. Verify PV is now `Available`: `k get pv `. + 3. Create new PVC specifying `volumeName: `. + 4. **Verify**: Status transitions back to `Bound`. + +--- + +### Q36 · Data Persistence Across Pod Restarts +- **Concept**: Data written to a PersistentVolume survives pod termination and rescheduling. +- **Step-by-Step**: + 1. Create PVC. + 2. Run writer Pod (`restartPolicy: Never`) writing data to `/data/marker.txt`. + 3. Wait for writer Pod completion: `k wait --for=jsonpath='{.status.phase}'=Succeeded pod/writer`. + 4. Run reader Pod mounting the same PVC. + 5. Verify data: `k exec reader -- cat /data/marker.txt`. + +--- + +### Q115 · [HARD] Local PV with Node Affinity Matching +- **Concept**: Local PersistentVolumes use `nodeAffinity` to bind to specific worker nodes. Pods mounting the claim are automatically scheduled onto the matching node. +- **Step-by-Step**: + 1. Inspect PV labels and node affinity: `k get pv -l media --show-labels`. + 2. Create PVC matching `selector: {matchLabels: {media: nvme}}`. + 3. Create Pod mounting the PVC. + 4. **Verify**: Pod schedules onto the node containing the NVMe disk without explicit `nodeSelector`. + +--- + +### Q116 · [HARD] Data Migration Between PVCs via Batch Job +- **Concept**: Migrating data between volumes requires running a migration Job mounting both the old claim (`src`) and new claim (`dst`). +- **Step-by-Step**: + 1. Create `new-data` PVC. + 2. Run batch Job mounting `old-data` to `/src` and `new-data` to `/dst` running `cp -a /src/. /dst/`. + 3. Wait for Job completion: `k wait --for=condition=complete job/migrate`. + 4. Update application Pod to reference `new-data` claim. + 5. Delete `old-data` claim (PV remains retained). + +--- + +## Domain 5: Troubleshooting (30%) + +### Q17 · Node `NotReady` (Kubelet Inactive) +- **Concept**: A node reports `NotReady` when the local `kubelet` service is stopped, disabled, or failing to communicate with the API server. +- **Step-by-Step**: + 1. Identify broken node: `k get nodes`. + 2. SSH / access the node: `podman exec -it bash` or `ssh `. + 3. Check status: `systemctl status kubelet`. + 4. Enable & start service: `systemctl enable --now kubelet`. + 5. Check logs: `journalctl -u kubelet -f --no-pager`. + 6. **Verify**: Node transitions to `Ready`. + +--- + +### Q18 · Deployment & Service Misconfiguration +- **Concept**: Pods in `ImagePullBackOff` have invalid image names/tags; Services without endpoints have mismatched `spec.selector` or incorrect `targetPort`. +- **Step-by-Step**: + 1. Fix Deployment image: `k -n troubleshoot set image deploy payments payments=nginx:1.27`. + 2. Inspect Service: `k -n troubleshoot get svc payments -o yaml`. + 3. Fix typo in selector (`app: payments`) and match `targetPort: 80` to container port. + 4. **Verify**: `k -n troubleshoot get endpointslices -l kubernetes.io/service-name=payments`. + +--- + +### Q19 · `CrashLoopBackOff` Diagnosis +- **Concept**: `CrashLoopBackOff` means the application process started and crashed. Check previous logs with `--previous`. +- **Step-by-Step**: + 1. Read crash logs: `k -n troubleshoot logs crasher --previous | tee crasher.log`. + 2. Locate missing configuration: `FATAL: required environment variable DB_HOST is not set`. + 3. Export pod YAML, add `env: [{name: DB_HOST, value: db.internal}]`, strip metadata, delete and recreate pod. + 4. **Verify**: Pod reaches `Running` status and stays healthy. + +--- + +### Q20 · Control Plane Component Failure (Kube-Scheduler Static Pod) +- **Concept**: Static pods for `kube-apiserver`, `kube-scheduler`, `kube-controller-manager`, and `etcd` live in `/etc/kubernetes/manifests/`. Kubelet watches and restarts them automatically. +- **Step-by-Step**: + 1. Check failing control-plane pod: `k -n kube-system get pods`. + 2. Check logs: `k -n kube-system logs kube-scheduler-`. + 3. SSH into control plane. + 4. Edit `/etc/kubernetes/manifests/kube-scheduler.yaml`: fix binary command typo (`kube-schedulerr` -> `kube-scheduler`). + 5. **Verify**: Kubelet reloads the manifest and pods schedule normally. + +--- + +### Q37 · CoreDNS Misconfiguration (Invalid Forwarding) +- **Concept**: CoreDNS forwards external queries based on the `Corefile` in ConfigMap `coredns` in `kube-system`. +- **Step-by-Step**: + 1. Inspect logs: `k -n kube-system logs -l k8s-app=kube-dns`. + 2. Edit ConfigMap: `k -n kube-system edit cm coredns`. + 3. Replace invalid forward IP (`10.255.255.1`) with `/etc/resolv.conf`. + 4. Restart deployment: `k -n kube-system rollout restart deploy coredns`. + 5. **Verify**: `k run test-dns --image=busybox:1.36 --rm -it --restart=Never -- nslookup kubernetes.default`. + +--- + +### Q38 · Controller-Manager Crash (Invalid Flag) +- **Concept**: Invalid CLI flags in static pod manifests prevent components from starting. +- **Step-by-Step**: + 1. Check logs: `k -n kube-system logs kube-controller-manager-`. + 2. Error: `invalid flag: --leader-elect-lease-duration=1s`. + 3. On control plane, edit `/etc/kubernetes/manifests/kube-controller-manager.yaml` and remove the bad flag. + 4. **Verify**: Controller manager restarts and reconciles deployments and ReplicaSets. + +--- + +### Q39 · Kubelet Configuration Drift (Certificate Path) +- **Concept**: Kubelet configuration lives at `/var/lib/kubelet/config.yaml`. Broken certificate paths prevent Kubelet from starting. +- **Step-by-Step**: + 1. On broken worker, inspect `journalctl -u kubelet -n 30 --no-pager`. + 2. Error: `open /etc/kubernetes/pki/ca-bundle.crt: no such file or directory`. + 3. In `/var/lib/kubelet/config.yaml`, fix `clientCAFile: /etc/kubernetes/pki/ca.crt`. + 4. Restart kubelet: `systemctl restart kubelet && systemctl enable kubelet`. + 5. **Verify**: `systemctl status kubelet` is active. + +--- + +### Q117 · [HARD] Multi-Fault Worker Node (Dead Kubelet + Wrong CA + Cordoned) +- **Concept**: Killer.sh-style compound failures combine multiple root causes on a single node. +- **Step-by-Step**: + 1. Check node in cluster: `k get node ` (shows `NotReady,SchedulingDisabled`). + 2. Access node, check `systemctl status kubelet`. + 3. Fix wrong CA file in `/var/lib/kubelet/config.yaml` (`ca-wrong.crt` -> `ca.crt`). + 4. Start kubelet: `systemctl enable --now kubelet`. + 5. Exit node back to main terminal. + 6. **Uncordon** the node: `k uncordon `. + 7. **Verify**: Test scheduling on the node (`k run test-pod --overrides='{"spec":{"nodeName":""}}'`). + +--- + +### Q118 · [HARD] Two Control Plane Components Down Simultaneously +- **Concept**: Both `kube-scheduler` and `kube-controller-manager` fail for different reasons (command typo + broken image tag). +- **Step-by-Step**: + 1. On control plane, fix `kube-scheduler.yaml` command typo (`kube-schedulerr` -> `kube-scheduler`). + 2. Fix `kube-controller-manager.yaml` image tag (remove broken suffix). + 3. **Verify**: `k -n kube-system get pods -w` shows all control-plane pods Running. + +--- + +### Q119 · [HARD] Application Failure (4 Compound Reasons) +- **Concept**: Quota exhaustion + image tag typo + missing Secret key + broken Service selector. +- **Step-by-Step**: + 1. Patch namespace quota hard limit from 1 to 3 pods. + 2. Fix deployment image tag to `nginx:1.27`. + 3. Add missing key to Secret `DATABASE_URL` and restart rollout. + 4. Fix Service selector and targetPort. + 5. **Verify**: All 3 deployment replicas are Available with active endpoints. + +--- + +### Q120 · [HARD] Extract Cluster Networking Facts +- **Concept**: Extract network configuration directly from control-plane manifests and ConfigMaps. +- **Step-by-Step**: + 1. Pod CIDR: `k -n kube-system get pod -l component=kube-controller-manager -o yaml | grep cluster-cidr`. + 2. Service CIDR: `k -n kube-system get pod -l component=kube-apiserver -o yaml | grep service-cluster-ip-range`. + 3. CoreDNS ClusterIP: `k -n kube-system get svc kube-dns -o jsonpath='{.spec.clusterIP}'`. + 4. Kube-proxy mode: `k -n kube-system get cm kube-proxy -o yaml | grep '^ *mode:'` (default: `iptables`). + 5. Node PodCIDR: `k get node -o jsonpath='{.spec.podCIDR}'`.