Aquesta és l'última lliçó del curs i funciona d'una manera diferent de totes les anteriors: no es llegeix, es fa. És un examen de pràctiques complet, amb quinze tasques cronometrades a l'estil de les certificacions, sobre la plataforma Rutas Norte que has construït al llarg dels onze mòduls anteriors. Té la seva puntuació, el seu solucionari i una taula d'autoavaluació que tradueix el teu resultat en un veredicte clar: a punt per reservar data, repassar dos dominis concrets, o tornar a determinats mòduls.
La regla més important: fes el simulacre abans de llegir les solucions. El valor d'aquesta lliçó no és al solucionari —és a descobrir, amb un cronòmetre corrent, què saps fer sense ajuda i què no. Llegir-lo primer converteix un diagnòstic en una lectura agradable i sense utilitat.
Prepara el clúster, posa el cronòmetre a 120 minuts i comença.
Contingut
- Instruccions del simulacre
- Preparació de l'entorn
- Les quinze tasques
- Repartiment del temps i estratègia
- Instruccions del simulacre
1.1 Regles
Aquestes regles repliquen les condicions reals de l'examen. Respectar-les és el que fa que el resultat signifiqui alguna cosa.
| Regla | Detall |
|---|---|
| Temps total | 120 minuts, cronometrats des de la primera tasca |
| Sense pauses | Res d'aturar el rellotge. Ves al bany abans. |
| Documentació | Només kubernetes.io/docs. Una pestanya. Res més. |
| Prohibit | Cercadors, fòrums, GitHub, notes pròpies, aquesta lliçó, eines d'IA |
| Editor | vim o nano al terminal. No un IDE gràfic. |
| Mòbil | En una altra habitació |
| Puntuació | 100 punts repartits entre les 15 tasques |
| Correcció | Al final, amb el solucionari. Mai durant. |
1.2 Com puntuar
Cada tasca indica el seu criteri d'acceptació. Puntua així:
- Puntuació completa si es compleix tot el criteri.
- Puntuació parcial (la meitat) si es compleix una part substancial però falta algun requisit.
- Zero si l'objecte no existeix, està al namespace equivocat o no funciona.
Sigues honest amb tu mateix. Inflar la nota només et perjudica.
1.3 Què anotar mentre treballes
Tingues un fitxer de notes obert (o paper, aquí sí que val) i registra per a cada tasca:
T1 5p ✔ 3 min
T2 7p ½ 9 min - no em va sortir l Ingress a la primera
T3 6p ✔ 4 min
T4 8p ⏸ saltada - PVC en Pending i no vaig saber per que
...Aquesta informació és tan valuosa com la nota final: et diu on se't va el temps.
- Preparació de l'entorn
2.1 Opció recomanada: kind amb tres nodes
kind aixeca un clúster multinode en un minut i suporta gairebé tot el que necessita el simulacre. Necessites Docker o Podman instal·lat.
# kind-simulacre.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30080
hostPort: 30080
- role: worker
- role: worker
networking:
disableDefaultCNI: true # instal·larem Calico per a les NetworkPolicieskind create cluster --name simulacre --config kind-simulacre.yaml
# CNI amb suport de NetworkPolicies (imprescindible per a la tasca 9)
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/calico.yaml
# Esperar que tots els nodes estiguin Ready
kubectl wait --for=condition=Ready nodes --all --timeout=300s
kubectl get nodesNAME STATUS ROLES AGE VERSION
simulacre-control-plane Ready control-plane 2m v1.30.0
simulacre-worker Ready <none> 2m v1.30.0
simulacre-worker2 Ready <none> 2m v1.30.02.2 Alternativa: minikube
minikube start --nodes=3 --cni=calico --kubernetes-version=v1.30.0
minikube addons enable ingress
minikube addons enable metrics-serverMinikube té l'avantatge de portar el controlador d'Ingress i el metrics-server com a addons, que a kind cal instal·lar a part.
2.3 Components addicionals
Perquè totes les tasques siguin resolubles, instal·la això abans d'engegar el cronòmetre:
# Controlador d'Ingress (necessari per a la tasca 2)
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.11.2/deploy/static/provider/kind/deploy.yaml
kubectl wait --namespace ingress-nginx --for=condition=ready pod \
--selector=app.kubernetes.io/component=controller --timeout=180s
# metrics-server (necessari per a la tasca 11)
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
kubectl patch deployment metrics-server -n kube-system --type='json' \
-p='[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]'2.4 Script de preparació (executa'l abans del cronòmetre)
Aquest script crea els namespaces, les càrregues de partida i les tres avaries de les tasques de resolució de problemes. Desa'l com a preparar-simulacre.sh i executa'l. No el llegeixis amb detall: les avaries han de ser una sorpresa.
#!/bin/bash
set -e
for ns in rutas-norte-dev rutas-norte-pre rutas-norte-pro; do
kubectl create namespace $ns --dry-run=client -o yaml | kubectl apply -f -
done
# Etiquetes de node per a la tasca 5
kubectl label node simulacre-worker2 tipus=batch --overwrite
kubectl taint node simulacre-worker2 dedicat=batch:NoSchedule --overwrite
# Càrrega de partida per a les tasques 7, 11 i 12
kubectl create deployment api-reserves --image=nginx:1.27-alpine \
--replicas=2 -n rutas-norte-pre
kubectl create deployment botiga-web --image=nginx:1.27-alpine \
--replicas=3 -n rutas-norte-pro
# --- AVARIA 1 (tasca 13) ---
kubectl create deployment worker-notificacions --image=busybox:1.36 \
-n rutas-norte-dev
kubectl set env deployment/worker-notificacions -n rutas-norte-dev \
--from=secret/credencials-cua --prefix=CUA_ 2>/dev/null || \
kubectl patch deployment worker-notificacions -n rutas-norte-dev --type='json' \
-p='[{"op":"add","path":"/spec/template/spec/containers/0/envFrom",
"value":[{"secretRef":{"name":"credencials-cua"}}]}]'
# --- AVARIA 2 (tasca 14) ---
kubectl create deployment redis-cache --image=redis:7-alpine -n rutas-norte-pre
kubectl expose deployment redis-cache --name=redis-cache-svc --port=6379 \
-n rutas-norte-pre
kubectl patch svc redis-cache-svc -n rutas-norte-pre \
-p '{"spec":{"selector":{"app":"redis"}}}'
# --- AVARIA 3 (tasca 15) ---
kubectl run informes-ocupacio --image=busybox:1.36 -n rutas-norte-pro \
--overrides='{"spec":{"nodeSelector":{"disc":"nvme"}}}' \
--command -- sleep 3600
echo "Entorn preparat. Engega el cronometre."2.5 Ara sí: engega el cronòmetre
Abans de llegir la tasca 1, tecleja el teu bloc d'arrencada (lliçó 12-04):
alias k=kubectl
export do='--dry-run=client -o yaml'
export now='--force --grace-period=0'
source <(kubectl completion bash)
complete -o default -F __start_kubectl k
cat <<'EOF' > ~/.vimrc
set number
set expandtab
set tabstop=2
set shiftwidth=2
set softtabstop=2
set autoindent
set paste
EOF120 minuts. Comença.
- Les quinze tasques
Tasca 1 — Desplegament bàsic i escalat
Namespace: rutas-norte-dev · Pes: 5 punts · Objectiu: 4 min
Crea un Deployment anomenat botiga-web amb la imatge nginx:1.27-alpine i 4 rèpliques. Tots els seus pods han de portar l'etiqueta entorn=dev a més de les que posi el controlador. Després, escala'l a 6 rèpliques.
Criteri d'acceptació: kubectl get deploy botiga-web -n rutas-norte-dev mostra 6/6 i tots els pods tenen l'etiqueta entorn=dev.
Tasca 2 — Exposició: Service i Ingress
Namespace: rutas-norte-dev · Pes: 7 punts · Objectiu: 8 min
Exposa el Deployment botiga-web de la tasca anterior amb un Service ClusterIP anomenat botiga-web-svc al port 80. Crea a més un Ingress botiga-ingress amb la IngressClass nginx que encamini l'amfitrió www.rutasnorte.es, ruta /, cap a aquest Service al port 80.
Criteri d'acceptació: el Service té endpoints poblats i kubectl describe ingress botiga-ingress mostra la regla amb el backend correcte.
Tasca 3 — Configuració i secrets
Namespace: rutas-norte-dev · Pes: 6 punts · Objectiu: 6 min
Crea:
- Un ConfigMap
config-apiamb les clausnivell_log=infoimax_connexions=100. - Un Secret
credencials-postgresambusuari=reservesipassword=N0rt3-2026.
Crea un Pod api-reserves amb la imatge nginx:1.27-alpine que rebi totes les claus del ConfigMap com a variables d'entorn i munti el Secret com a fitxers a /etc/secrets en mode només lectura.
Criteri d'acceptació: kubectl exec api-reserves -- env | grep nivell_log retorna nivell_log=info i kubectl exec api-reserves -- cat /etc/secrets/usuari retorna reserves.
Tasca 4 — Emmagatzematge persistent
Namespace: rutas-norte-pre · Pes: 8 punts · Objectiu: 9 min
Crea un PersistentVolume pv-reserves de 3Gi, mode d'accés ReadWriteOnce, storageClassName: manual, política de reclamació Retain, amb hostPath a /mnt/dades-reserves.
Crea un PersistentVolumeClaim pvc-reserves de 2Gi que s'enllaci a aquest PV, i un Pod postgres-reserves amb imatge busybox:1.36 que executi sleep 3600 i munti el volum a /var/lib/dades.
Criteri d'acceptació: el PVC apareix com a Bound al PV pv-reserves i el pod està Running amb el volum muntat.
Tasca 5 — Planificació amb taints i etiquetes de node
Namespace: rutas-norte-pro · Pes: 6 punts · Objectiu: 6 min
El node simulacre-worker2 té el taint dedicat=batch:NoSchedule i l'etiqueta tipus=batch.
Crea un Deployment worker-notificacions amb imatge busybox:1.36, comanda sleep 3600, 2 rèpliques, que s'executi exclusivament en aquell node.
Criteri d'acceptació: els 2 pods estan Running a simulacre-worker2 (comprova-ho amb -o wide).
Tasca 6 — Treball programat
Namespace: rutas-norte-pro · Pes: 5 punts · Objectiu: 5 min
Crea un CronJob informes-nocturns que s'executi cada dia a les 2:30, amb imatge busybox:1.36 i comanda echo informe ocupacio generat. Requisits: no ha de permetre execucions solapades, cada Job pot reintentar com a màxim 2 vegades, i només es conserven 3 Jobs reeixits a l'historial.
Criteri d'acceptació: el CronJob existeix amb schedule: "30 2 * * *", concurrencyPolicy: Forbid, backoffLimit: 2 i successfulJobsHistoryLimit: 3. Una execució manual produeix la sortida esperada.
Tasca 7 — Sondes i qualitat de servei
Namespace: rutas-norte-pre · Pes: 7 punts · Objectiu: 7 min
El Deployment api-reserves ja existeix. Modifica'l perquè:
- No rebi trànsit fins que respongui
GET /al port 80 (readinessProbe). - Es reiniciï si
GET /falla 3 vegades seguides (livenessProbe). - Tingui classe de QoS
Guaranteedamb 200m de CPU i 256Mi de memòria.
Criteri d'acceptació: kubectl describe pod -l app=api-reserves -n rutas-norte-pre mostra QoS Class: Guaranteed i les dues sondes configurades.
Tasca 8 — RBAC i ServiceAccount
Namespace: rutas-norte-pro · Pes: 7 punts · Objectiu: 7 min
Crea la ServiceAccount suport-n1 a rutas-norte-pro. Concedeix-li permís per llistar i veure pods i llegir-ne els logs, únicament en aquell namespace. No ha de poder esborrar res ni accedir a altres namespaces.
Assigna aquesta ServiceAccount al Deployment botiga-web de rutas-norte-pro.
Criteri d'acceptació: kubectl auth can-i list pods --as=system:serviceaccount:rutas-norte-pro:suport-n1 -n rutas-norte-pro retorna yes; la mateixa consulta amb delete o en un altre namespace retorna no.
Tasca 9 — Política de xarxa
Namespace: rutas-norte-pro · Pes: 7 punts · Objectiu: 8 min
Crea a rutas-norte-pro una NetworkPolicy anomenada denegar-tot-entrada que denegui tot el trànsit d'entrada a tots els pods del namespace.
Afegeix una segona política permetre-botiga-des-dingress que permeti el trànsit d'entrada al port 80 dels pods amb etiqueta app=botiga-web únicament des de pods del namespace ingress-nginx.
Criteri d'acceptació: totes dues polítiques existeixen; un pod de prova dins de rutas-norte-pro no pot arribar a botiga-web al port 80.
Tasca 10 — Enduriment i admissió
Namespace: rutas-norte-pre · Pes: 7 punts · Objectiu: 7 min
Etiqueta el namespace rutas-norte-pre perquè apliqui l'estàndard restricted de Pod Security Admission en mode enforce, amb la versió v1.30.
Després, crea un Pod auditor-segur (imatge busybox:1.36, comanda sleep 3600) que compleixi aquell estàndard: usuari no root, sense escalada de privilegis, totes les capacitats descartades i perfil seccomp per defecte.
Criteri d'acceptació: el namespace té l'etiqueta d'enforce; el pod auditor-segur està Running; un kubectl run insegur --image=nginx -n rutas-norte-pre és rebutjat.
Tasca 11 — Autoescalat
Namespace: rutas-norte-pre · Pes: 5 punts · Objectiu: 4 min
Crea un HorizontalPodAutoscaler per al Deployment api-reserves que mantingui entre 2 i 8 rèpliques, amb un objectiu d'utilització de CPU del 65 %.
Criteri d'acceptació: kubectl get hpa -n rutas-norte-pre mostra l'HPA amb MINPODS 2, MAXPODS 8 i l'objectiu del 65 %, i amb mètriques llegides (no <unknown>).
Tasca 12 — Actualització i reversió
Namespace: rutas-norte-pro · Pes: 6 punts · Objectiu: 6 min
Sobre el Deployment botiga-web de rutas-norte-pro:
- Configura l'estratègia perquè cap pod no deixi d'estar disponible durant l'actualització (
maxUnavailable: 0,maxSurge: 1). - Actualitza la imatge a
nginx:1.27.2-alpinei anota la causa del canvi com apujada a 1.27.2. - Espera que acabi el desplegament i després reverteix a la revisió anterior.
Criteri d'acceptació: kubectl rollout history mostra almenys dues revisions amb la causa anotada, i la imatge final torna a ser nginx:1.27-alpine.
Tasca 13 — Resolució de problemes: el worker que no arrenca
Namespace: rutas-norte-dev · Pes: 8 punts · Objectiu: 8 min
El Deployment worker-notificacions de rutas-norte-dev no aconsegueix arrencar cap pod. Troba'n la causa, corregeix-la sense canviar la imatge ni la configuració del contenidor, i deixa el Deployment amb almenys un pod en Running.
Escriu a /opt/diagnostic-13.txt una línia explicant la causa arrel.
Criteri d'acceptació: el Deployment té 1/1 pods a punt i el fitxer de diagnòstic existeix i no està buit.
Tasca 14 — Resolució de problemes: el servei que no respon
Namespace: rutas-norte-pre · Pes: 8 punts · Objectiu: 8 min
El Service redis-cache-svc de rutas-norte-pre no està servint trànsit: les aplicacions que el criden reben un rebuig de connexió, tot i que els pods de redis-cache estan Running. Troba'n la causa i arregla-la sense modificar els pods.
Escriu a /opt/diagnostic-14.txt una línia explicant la causa arrel.
Criteri d'acceptació: kubectl get endpoints redis-cache-svc -n rutas-norte-pre mostra almenys una adreça IP.
Tasca 15 — Resolució de problemes: el pod que mai no es planifica
Namespace: rutas-norte-pro · Pes: 8 punts · Objectiu: 8 min
El Pod informes-ocupacio de rutas-norte-pro fa minuts que està en estat Pending. Esbrina per què i aconsegueix posar-lo en Running. Pots triar entre corregir el pod o adaptar el clúster; justifica la teva decisió.
Escriu a /opt/diagnostic-15.txt una línia explicant la causa arrel i la solució triada.
Criteri d'acceptació: el pod informes-ocupacio està en Running.
- Repartiment del temps i estratègia
4.1 Temps objectiu
| Tasca | Tema | Punts | Objectiu | Acumulat |
|---|---|---|---|---|
| 1 | Deployment i escalat | 5 | 4 min | 4 |
| 2 | Service i Ingress | 7 | 8 min | 12 |
| 3 | ConfigMap i Secret | 6 | 6 min | 18 |
| 4 | PV, PVC i Pod | 8 | 9 min | 27 |
| 5 | Taints i nodeSelector | 6 | 6 min | 33 |
| 6 | CronJob | 5 | 5 min | 38 |
| 7 | Sondes i QoS | 7 | 7 min | 45 |
| 8 | RBAC | 7 | 7 min | 52 |
| 9 | NetworkPolicy | 7 | 8 min | 60 |
| 10 | Pod Security | 7 | 7 min | 67 |
| 11 | HPA | 5 | 4 min | 71 |
| 12 | Rollout i rollback | 6 | 6 min | 77 |
| 13 | TS: worker caigut | 8 | 8 min | 85 |
| 14 | TS: Service sense endpoints | 8 | 8 min | 93 |
| 15 | TS: pod Pending | 8 | 8 min | 101 |
| — | Revisió final | — | ~19 min | 120 |
Total: 100 punts en 101 minuts de feina, amb 19 de marge. Aquest marge és deliberat: a l'examen real es consumeix en dubtes, tasques que s'allarguen i la revisió.
4.2 Estratègia suggerida
Aplicant el que s'ha après a la lliçó 12-04:
Min 0-4 Bloc d arrencada + lectura de les 15 tasques
Min 4-30 Fase 1 (barates i rapides): T1, T11, T6, T3, T12 → 27 punts
Min 30-85 Fase 2 (bloc central per pes): T4, T13, T14, T15, T9, T8, T10, T7, T2, T5
Min 85-105 Fase 3: pendents i mig fetes
Min 105-120 Revisio: context, namespace i funcionament de cada objecteSi t'ajustes a l'ordre numèric també funciona, però fixa't que les tasques 11 i 6 valen 10 punts entre totes dues i es resolen en 9 minuts: són les de millor rendiment del simulacre.
4.3 Recordatori abans de començar
- Fixa el namespace en començar cada tasca, o fes servir
-na totes les comandes. - Verifica cada tasca abans de passar a la següent.
- Si una tasca supera el seu objectiu en més del 50 %, marca-la i salta.
- No deixis mai una tasca completament buida: hi ha puntuació parcial.
Quan acabis, encara no llegeixis el solucionari. Primer fes els exercicis integradors de la secció següent si et queden forces, o descansa i torna-hi més tard.
Errors Comuns i Consells
Aquestes són les fallades que més es repeteixen en aquest simulacre concret.
| Error | Tasca afectada | Com evitar-ho |
|---|---|---|
| Crear el Deployment sense l'etiqueta demanada als pods (només al Deployment) | 1 | L'etiqueta va a spec.template.metadata.labels |
Ingress amb pathType: Exact en lloc de Prefix |
2 | Fer servir --rule="host/*=svc:80" amb asterisc |
Confondre envFrom amb env |
3 | "Totes les claus" → envFrom; "una clau" → valueFrom |
storageClassName diferent entre PV i PVC |
4 | Ha de coincidir exactament, o el PVC queda Pending |
Posar només la tolerància i oblidar el nodeSelector |
5 | La tolerància permet, no obliga: calen totes dues coses |
backoffLimit al nivell equivocat del CronJob |
6 | Va a jobTemplate.spec, no a CronJob.spec |
QoS Burstable en lloc de Guaranteed |
7 | requests i limits idèntics en CPU i memòria |
Oblidar el subrecurs pods/log |
8 | Sense ell, kubectl logs falla encara que puguis llistar pods |
NetworkPolicy sense policyTypes |
9 | Sense policyTypes: [Ingress] no hi ha denegació efectiva |
Aplicar restricted i oblidar seccompProfile |
10 | L'estàndard restricted ho exigeix explícitament |
HPA amb <unknown> a les mètriques |
11 | Falta el metrics-server o el Deployment no té requests de CPU |
rollout undo sense comprovar la imatge resultant |
12 | Verificar amb jsonpath la imatge final |
| Diagnosticar sense mirar els esdeveniments | 13, 14, 15 | kubectl describe i kubectl get events --sort-by=.lastTimestamp |
| Esborrar pods d'un Deployment per "arreglar-los" | 13 | Es recreen idèntics: cal corregir la causa |
Tres consells finals per al simulacre:
- Tracta les tres tasques de resolució de problemes com l'examen real les tracta: valen 24 dels 100 punts, gairebé una quarta part. Si vas just de temps, prioritza-les abans que les de creació.
- Si un objecte queda
PendingoCrashLoopBackOff, la tasca no està feta. No n'hi ha prou que el YAML s'hagi aplicat. - Anota el temps real de cada tasca. L'anàlisi posterior d'on se't va anar el temps val tant com la nota.
Exercicis
Aquests tres reptes integradors són de més calat que les tasques del simulacre: cadascun ajunta diversos mòduls del curs en un únic objectiu. Fes-los després del simulacre, sense límit estricte de temps però mesurant-lo.
Exercici 1 — Component complet des de zero
Partint d'un namespace buit rutas-norte-qa, deixa operatiu el component api-reserves complet, a punt per a producció:
- Un ConfigMap
config-apii un Secretcredencials-postgres. - Un Deployment
api-reservesamb 3 rèpliques, imatgenginx:1.27-alpine, que consumeixi el ConfigMap per variables i el Secret per fitxer. - Sondes de readiness i liveness, i QoS
Guaranteed. - Una ServiceAccount pròpia
sa-apiamb permís per llegir únicament el ConfigMapconfig-api, i sense muntatge automàtic del token. - Un Service ClusterIP i un Ingress amb amfitrió
qa.rutasnorte.es. - Un HPA entre 3 i 9 rèpliques al 70 % de CPU.
- Un PodDisruptionBudget que garanteixi almenys 2 pods disponibles.
- NetworkPolicy de denegació d'entrada per defecte, amb excepció per al namespace
ingress-nginx.
Objectiu: 30 minuts. Criteri: tot Running, endpoints poblats, auth can-i correcte i el pod sense token muntat.
Exercici 2 — Recuperar un servei caigut
Provoca deliberadament aquesta situació a rutas-norte-pro i després recupera-la com si fos una incidència real (fes servir el runbook mental del mòdul 11):
El símptoma que et donen: "els usuaris reben 503 en entrar a la botiga; l'Ingress respon però no arriba res al darrere".
Preparació de l'avaria (que la faci una altra persona, o fes-la tu i espera un dia per oblidar-ne els detalls):
kubectl scale deployment botiga-web --replicas=0 -n rutas-norte-pro
kubectl patch svc botiga-web-svc -n rutas-norte-pro \
-p '{"spec":{"ports":[{"port":80,"targetPort":8080}]}}'
kubectl set image deployment/botiga-web botiga-web=nginx:9.9-noexisteix -n rutas-norte-proEl que se't demana: diagnosticar en ordre (Ingress → Service → endpoints → pods → contenidor), documentar cada troballa, arreglar les tres causes i deixar el servei servint amb 3 rèpliques. Escriu un breu informe d'incidència amb línia temporal, causa arrel i acció preventiva.
Exercici 3 — Migració amb zero talls
A rutas-norte-pro, el Deployment botiga-web serveix trànsit. Migra el seu emmagatzematge de configuració d'un ConfigMap muntat com a fitxer a un ConfigMap diferent amb contingut nou, sense que cap pod deixi d'estar disponible en cap moment i sense que se serveixi contingut inconsistent.
Passos que has de resoldre: crear el nou ConfigMap, ajustar l'estratègia del Deployment, pausar el rollout per agrupar canvis, aplicar la modificació, reprendre, verificar a cada fase que hi ha almenys 3 pods a punt, i tenir preparat el rollout undo si alguna cosa falla.
Demostra amb un bucle de peticions que no hi ha hagut ni una sola fallada durant la migració.
Solucions
Solució a l'Exercici 1
k create namespace rutas-norte-qa
k config set-context --current --namespace=rutas-norte-qa
# 1. Configuració
k create configmap config-api --from-literal=nivell_log=info --from-literal=max_connexions=100
k create secret generic credencials-postgres \
--from-literal=usuari=reserves --from-literal=password='N0rt3-2026'
# 4a. ServiceAccount i RBAC mínim
k create serviceaccount sa-api
k patch serviceaccount sa-api -p '{"automountServiceAccountToken": false}'
k create role lector-config --verb=get --resource=configmaps --resource-name=config-api
k create rolebinding lector-config-b --role=lector-config \
--serviceaccount=rutas-norte-qa:sa-apiEl Deployment amb tot integrat:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-reserves
namespace: rutas-norte-qa
spec:
replicas: 3
selector:
matchLabels: { app: api-reserves }
template:
metadata:
labels: { app: api-reserves }
spec:
serviceAccountName: sa-api
automountServiceAccountToken: false
containers:
- name: api
image: nginx:1.27-alpine
ports:
- containerPort: 80
envFrom:
- configMapRef: { name: config-api }
volumeMounts:
- name: secrets
mountPath: /etc/secrets
readOnly: true
resources:
requests: { cpu: 200m, memory: 256Mi }
limits: { cpu: 200m, memory: 256Mi }
readinessProbe:
httpGet: { path: /, port: 80 }
initialDelaySeconds: 3
periodSeconds: 10
livenessProbe:
httpGet: { path: /, port: 80 }
periodSeconds: 15
failureThreshold: 3
volumes:
- name: secrets
secret: { secretName: credencials-postgres }k apply -f api-qa.yaml
# 5. Exposició
k expose deployment api-reserves --name=api-reserves-svc --port=80 --target-port=80
k create ingress api-ingress --class=nginx --rule="qa.rutasnorte.es/*=api-reserves-svc:80"
# 6. HPA
k autoscale deployment api-reserves --min=3 --max=9 --cpu-percent=70
# 7. PDB
k create poddisruptionbudget api-pdb --selector=app=api-reserves --min-available=2# 8. NetworkPolicies
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: { name: denegar-entrada, namespace: rutas-norte-qa }
spec:
podSelector: {}
policyTypes: [Ingress]
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: { name: permetre-des-dingress, namespace: rutas-norte-qa }
spec:
podSelector:
matchLabels: { app: api-reserves }
policyTypes: [Ingress]
ingress:
- from:
- namespaceSelector:
matchLabels: { kubernetes.io/metadata.name: ingress-nginx }
ports:
- protocol: TCP
port: 80Verificació completa:
k get deploy,svc,ing,hpa,pdb,netpol -n rutas-norte-qa
k describe pod -l app=api-reserves -n rutas-norte-qa | grep "QoS Class" # Guaranteed
k exec deploy/api-reserves -n rutas-norte-qa -- ls /var/run/secrets/kubernetes.io/serviceaccount
# No such file or directory ← el token NO està muntat
k auth can-i get configmap/config-api --as=system:serviceaccount:rutas-norte-qa:sa-api -n rutas-norte-qa # yes
k auth can-i list configmaps --as=system:serviceaccount:rutas-norte-qa:sa-api -n rutas-norte-qa # noLes dues trampes de l'exercici: automountServiceAccountToken: false cal posar-lo al pod (o a la SA), i el --resource-name=config-api al Role és el que converteix "llegir un ConfigMap concret" en un permís realment mínim.
Solució a l'Exercici 2
Diagnòstic en l'ordre correcte, de fora cap endins:
Host Path Backends
www.rutasnorte.es / botiga-web-svc:80 (<error: endpoints "botiga-web-svc" not found>)# 3. Hi ha pods?
k get pods -l app=botiga-web -n rutas-norte-pro
k get deploy botiga-web -n rutas-norte-proTroballa 1: el Deployment està escalat a 0.
k scale deployment botiga-web --replicas=3 -n rutas-norte-pro
k get pods -l app=botiga-web -n rutas-norte-proTroballa 2: imatge inexistent.
k describe pod -l app=botiga-web -n rutas-norte-pro | grep -A3 Events
# Failed to pull image "nginx:9.9-noexisteix": manifest unknown
k set image deployment/botiga-web botiga-web=nginx:1.27-alpine -n rutas-norte-pro
k rollout status deployment/botiga-web -n rutas-norte-pro
k get endpoints botiga-web-svc -n rutas-norte-proEls pods estan Running però el Service continua sense endpoints: hi ha una tercera causa.
Troballa 3: targetPort equivocat.
k patch svc botiga-web-svc -n rutas-norte-pro \
-p '{"spec":{"ports":[{"port":80,"targetPort":80,"protocol":"TCP"}]}}'
k get endpoints botiga-web-svc -n rutas-norte-proInforme d'incidència:
INCIDENCIA: 503 a www.rutasnorte.es
Impacte: botiga-web no disponible, 42 minuts.
Linia temporal:
T+0 Alerta de 503 des de l Ingress
T+2 Ingress OK, Service sense endpoints
T+4 Deployment escalat a 0 -> escalat a 3
T+6 Pods en ImagePullBackOff (nginx:9.9-noexisteix) -> imatge corregida
T+9 Pods Running pero Service encara sense endpoints
T+11 targetPort 8080 davant del port real 80 -> corregit
T+12 Servei restablert
Causa arrel: tres canvis manuals no revisats sobre produccio.
Prevencio: gestionar rutas-norte-pro per GitOps (modul 10), impedir canvis
manuals amb RBAC, i alerta sobre "Service sense endpoints" a Prometheus.La lliçó d'aquest exercici: un símptoma pot amagar diverses causes encadenades. Arreglar la primera i donar per tancada la incidència és l'error clàssic. La verificació d'extrem a extrem (endpoints poblats) és l'única cosa que demostra que està resolt.
Solució a l'Exercici 3
# 0. Bucle de comprovació en un altre terminal
while true; do
k run probe-$RANDOM --rm -q --image=busybox:1.36 --restart=Never -n rutas-norte-pro \
-- wget -qO- --timeout=2 botiga-web-svc >/dev/null 2>&1 \
&& echo -n "." || echo -n "X"
sleep 1
done# 1. Nou ConfigMap
k create configmap config-web-v2 \
--from-literal=index.html='<h1>Rutas Norte v2</h1>' -n rutas-norte-pro
# 2. Estratègia sense talls
k patch deployment botiga-web -n rutas-norte-pro -p '
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0'
# 3. Pausar per agrupar canvis
k rollout pause deployment/botiga-web -n rutas-norte-pro
# 4. Aplicar els canvis (encara no se'n desplega cap)
k patch deployment botiga-web -n rutas-norte-pro --type='json' -p='[
{"op":"replace","path":"/spec/template/spec/volumes/0/configMap/name","value":"config-web-v2"}
]'
k annotate deployment botiga-web -n rutas-norte-pro \
kubernetes.io/change-cause="migracio a config-web-v2" --overwrite
# 5. Reprendre: ara sí, un únic rollout
k rollout resume deployment/botiga-web -n rutas-norte-pro
k rollout status deployment/botiga-web -n rutas-norte-pro --timeout=120sVerificació durant el procés (en un tercer terminal):
watch -n1 'kubectl get deploy botiga-web -n rutas-norte-pro; \
kubectl get endpoints botiga-web-svc -n rutas-norte-pro'El bucle de peticions ha de mostrar només punts, sense cap X.
Pla de reversió preparat abans de començar:
k rollout undo deployment/botiga-web -n rutas-norte-pro
k rollout status deployment/botiga-web -n rutas-norte-proLes tres claus de l'exercici:
maxUnavailable: 0és el que garanteix que mai no faltin pods;maxSurge: 1és el que permet que el rollout avanci (amb tots dos a 0 es bloquejaria).rollout pause/resumeevita dos rollouts consecutius quan hi ha diversos canvis: sense pausar, elpatchdel volum i l'anotació provocarien dues onades de reemplaçament.- La
readinessProbeés imprescindible: sense ella, Kubernetes considera "disponible" un pod que encara no serveix, i sí que hi hauria talls encara quemaxUnavailablesigui 0.
Solucionari del Simulacre
Ara sí. Corregeix tasca per tasca i anota la teva puntuació.
Tasca 1 (5 punts)
k create deployment botiga-web --image=nginx:1.27-alpine --replicas=4 \
-n rutas-norte-dev $do > t1.yamlAfegir l'etiqueta a la plantilla del pod:
Comprovació:
NAME READY UP-TO-DATE AVAILABLE
botiga-web 6/6 6 6
botiga-web-6c9d... 1/1 Running app=botiga-web,entorn=dev,pod-template-hash=...La trampa: posar entorn=dev només a metadata.labels del Deployment. Els pods no l'hereten: va a spec.template.metadata.labels. Alternativa vàlida i més ràpida: crear el Deployment i després k label pods -l app=botiga-web entorn=dev, però llavors els pods nous de l'escalat no la portarien.
Tasca 2 (7 punts)
k expose deployment botiga-web --name=botiga-web-svc \
--port=80 --target-port=80 -n rutas-norte-dev
k create ingress botiga-ingress -n rutas-norte-dev --class=nginx \
--rule="www.rutasnorte.es/*=botiga-web-svc:80"Comprovació:
k get endpoints botiga-web-svc -n rutas-norte-dev
k describe ingress botiga-ingress -n rutas-norte-dev | grep -A4 RulesNAME ENDPOINTS
botiga-web-svc 10.244.1.5:80,10.244.1.6:80,... (6 adreces)
Rules:
Host Path Backends
www.rutasnorte.es / botiga-web-svc:80 (10.244.1.5:80,...)La trampa: el /* genera pathType: Prefix. Sense l'asterisc obtindries Exact, que només casa l'arrel literal. I si el describe mostra <error: endpoints not found>, el Service està malament.
Tasca 3 (6 punts)
k create configmap config-api --from-literal=nivell_log=info \
--from-literal=max_connexions=100 -n rutas-norte-dev
k create secret generic credencials-postgres \
--from-literal=usuari=reserves --from-literal=password='N0rt3-2026' -n rutas-norte-dev
k run api-reserves --image=nginx:1.27-alpine -n rutas-norte-dev $do > t3.yamlspec:
containers:
- name: api-reserves
image: nginx:1.27-alpine
envFrom:
- configMapRef:
name: config-api
volumeMounts:
- name: secrets
mountPath: /etc/secrets
readOnly: true
volumes:
- name: secrets
secret:
secretName: credencials-postgresComprovació:
k exec api-reserves -n rutas-norte-dev -- env | grep -E 'nivell_log|max_connexions'
k exec api-reserves -n rutas-norte-dev -- cat /etc/secrets/usuariLa trampa: envFrom és germà d'env, no fill. I "muntar el Secret com a fitxers" significa volum, no secretKeyRef.
Tasca 4 (8 punts)
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-reserves
spec:
capacity: { storage: 3Gi }
accessModes: [ReadWriteOnce]
persistentVolumeReclaimPolicy: Retain
storageClassName: manual
hostPath: { path: /mnt/dades-reserves }
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-reserves
namespace: rutas-norte-pre
spec:
accessModes: [ReadWriteOnce]
storageClassName: manual
resources:
requests: { storage: 2Gi }
---
apiVersion: v1
kind: Pod
metadata:
name: postgres-reserves
namespace: rutas-norte-pre
spec:
containers:
- name: postgres
image: busybox:1.36
command: ["sleep", "3600"]
volumeMounts:
- name: dades
mountPath: /var/lib/dades
volumes:
- name: dades
persistentVolumeClaim:
claimName: pvc-reservesComprovació:
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM
pv-reserves 3Gi RWO Retain Bound rutas-norte-pre/pvc-reserves
NAME STATUS VOLUME CAPACITY
persistentvolumeclaim/pvc-reserves Bound pv-reserves 3GiLa trampa doble: el PV és d'àmbit de clúster (sense namespace), i el storageClassName: manual ha d'estar en tots dos. Si l'omets al PVC, l'aprovisionador dinàmic per defecte intentaria crear un altre volum i el PVC no s'enllaçaria al teu.
Tasca 5 (6 punts)
apiVersion: apps/v1
kind: Deployment
metadata:
name: worker-notificacions
namespace: rutas-norte-pro
spec:
replicas: 2
selector:
matchLabels: { app: worker-notificacions }
template:
metadata:
labels: { app: worker-notificacions }
spec:
nodeSelector:
tipus: batch
tolerations:
- key: dedicat
operator: Equal
value: batch
effect: NoSchedule
containers:
- name: worker
image: busybox:1.36
command: ["sleep", "3600"]Comprovació:
NAME READY STATUS NODE
worker-notificacions-x 1/1 Running simulacre-worker2
worker-notificacions-y 1/1 Running simulacre-worker2La trampa: calen les dues peces. La toleration només permet que el pod entri en aquell node; el nodeSelector és el que l'obliga a anar-hi. Amb només la tolerància, els pods anirien a qualsevol node lliure.
Tasca 6 (5 punts)
apiVersion: batch/v1
kind: CronJob
metadata:
name: informes-nocturns
namespace: rutas-norte-pro
spec:
schedule: "30 2 * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
jobTemplate:
spec:
backoffLimit: 2
template:
spec:
restartPolicy: OnFailure
containers:
- name: informes
image: busybox:1.36
command: ["/bin/sh", "-c", "echo informe ocupacio generat"]Comprovació:
k get cronjob informes-nocturns -n rutas-norte-pro
k create job prova-t6 --from=cronjob/informes-nocturns -n rutas-norte-pro
k logs job/prova-t6 -n rutas-norte-proLa trampa: backoffLimit va a jobTemplate.spec; concurrencyPolicy i successfulJobsHistoryLimit a CronJob.spec. I restartPolicy ha de ser OnFailure o Never: Always fa que l'API rebutgi el manifest.
Tasca 7 (7 punts)
containers:
- name: nginx
image: nginx:1.27-alpine
resources:
requests: { cpu: 200m, memory: 256Mi }
limits: { cpu: 200m, memory: 256Mi }
readinessProbe:
httpGet: { path: /, port: 80 }
initialDelaySeconds: 3
periodSeconds: 10
livenessProbe:
httpGet: { path: /, port: 80 }
periodSeconds: 10
failureThreshold: 3Comprovació:
k rollout status deployment/api-reserves -n rutas-norte-pre
k describe pod -l app=api-reserves -n rutas-norte-pre | grep "QoS Class"La trampa: Guaranteed exigeix requests idèntics a limits en CPU i memòria i a tots els contenidors. Posar només limits també funciona (Kubernetes copia els requests), però posar requests diferents dels limits dona Burstable i la tasca puntua a la meitat.
Tasca 8 (7 punts)
k create serviceaccount suport-n1 -n rutas-norte-pro
k create role suport-lectura --verb=get,list,watch \
--resource=pods,pods/log -n rutas-norte-pro
k create rolebinding suport-lectura-b --role=suport-lectura \
--serviceaccount=rutas-norte-pro:suport-n1 -n rutas-norte-pro
k set serviceaccount deployment/botiga-web suport-n1 -n rutas-norte-proComprovació:
SA=system:serviceaccount:rutas-norte-pro:suport-n1
k auth can-i list pods --as=$SA -n rutas-norte-pro # yes
k auth can-i get pods/log --as=$SA -n rutas-norte-pro # yes
k auth can-i delete pods --as=$SA -n rutas-norte-pro # no
k auth can-i list pods --as=$SA -n rutas-norte-dev # no
k get deploy botiga-web -n rutas-norte-pro \
-o jsonpath='{.spec.template.spec.serviceAccountName}' # suport-n1La trampa: pods/log és un recurs a part. Sense ell, kubectl logs retorna Forbidden encara que puguis llistar pods. I fer servir ClusterRole+ClusterRoleBinding donaria accés a tots els namespaces: violaria el criteri.
Tasca 9 (7 punts)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: denegar-tot-entrada
namespace: rutas-norte-pro
spec:
podSelector: {}
policyTypes: [Ingress]
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: permetre-botiga-des-dingress
namespace: rutas-norte-pro
spec:
podSelector:
matchLabels:
app: botiga-web
policyTypes: [Ingress]
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress-nginx
ports:
- protocol: TCP
port: 80Comprovació:
k get netpol -n rutas-norte-pro
# Des de dins del namespace: ha de FALLAR
k run test --rm -it --image=busybox:1.36 --restart=Never -n rutas-norte-pro \
-- wget -qO- --timeout=3 botiga-web-svcLa trampa: sense policyTypes: [Ingress] a la primera política, l'objecte existeix però no denega res. I kubernetes.io/metadata.name és una etiqueta que Kubernetes posa automàticament a tots els namespaces des de la 1.21: és la manera fiable de seleccionar-ne un pel nom.
Tasca 10 (7 punts)
k label namespace rutas-norte-pre \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/enforce-version=v1.30 --overwriteapiVersion: v1
kind: Pod
metadata:
name: auditor-segur
namespace: rutas-norte-pre
spec:
securityContext:
runAsNonRoot: true
runAsUser: 10001
seccompProfile:
type: RuntimeDefault
containers:
- name: auditor
image: busybox:1.36
command: ["sleep", "3600"]
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]Comprovació:
k get ns rutas-norte-pre --show-labels
k get pod auditor-segur -n rutas-norte-pre
k run insegur --image=nginx -n rutas-norte-preError from server (Forbidden): pods "insegur" is forbidden:
violates PodSecurity "restricted:v1.30": allowPrivilegeEscalation != false,
unrestricted capabilities, runAsNonRoot != true, seccompProfileLa trampa: l'estàndard restricted exigeix quatre coses alhora i la gent oblida seccompProfile: RuntimeDefault. El missatge d'error les enumera totes: fes-lo servir com a llista de comprovació.
Efecte lateral a tenir en compte: en aplicar enforce a rutas-norte-pre, el Deployment api-reserves de la tasca 7 continuarà corrent (PSA no expulsa pods existents), però no podrà crear pods nous. Si fas la tasca 10 abans que la 7 o la 11, el rollout es bloquejarà. És exactament el tipus d'interacció entre tasques que apareix a l'examen real.
Tasca 11 (5 punts)
Comprovació:
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS
api-reserves Deployment/api-reserves cpu: 0%/65% 2 8 2La trampa: si TARGETS mostra <unknown>/65%, hi ha dues causes possibles: el metrics-server no està instal·lat o no respon, o el Deployment no té requests de CPU (l'HPA calcula el percentatge sobre el request). Si vas fer la tasca 7 abans, els requests ja hi són i això funciona; si no, cal afegir-los.
Tasca 12 (6 punts)
k patch deployment botiga-web -n rutas-norte-pro -p '
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0'
k set image deployment/botiga-web nginx=nginx:1.27.2-alpine -n rutas-norte-pro
k annotate deployment botiga-web -n rutas-norte-pro \
kubernetes.io/change-cause="pujada a 1.27.2" --overwrite
k rollout status deployment/botiga-web -n rutas-norte-pro
k rollout history deployment/botiga-web -n rutas-norte-pro
k rollout undo deployment/botiga-web -n rutas-norte-proComprovació:
k rollout status deployment/botiga-web -n rutas-norte-pro
k get deploy botiga-web -n rutas-norte-pro \
-o jsonpath='{.spec.template.spec.containers[0].image}'La trampa: el nom del contenidor a set image no és lliure. Comprova'l primer:
Si set image no troba el contenidor, la comanda diu error: unable to find container named ... i no fa res.
Tasca 13 (8 punts) — Resolució de problemes
Causa arrel: el Deployment referencia amb envFrom un Secret que no existeix al namespace.
k create secret generic credencials-cua \
--from-literal=host=cua.rutasnorte.es --from-literal=token=abc123 \
-n rutas-norte-dev
k get pods -n rutas-norte-dev -w
echo "El Deployment referenciava amb envFrom el Secret credencials-cua, inexistent a rutas-norte-dev" \
> /opt/diagnostic-13.txtComprovació:
La trampa: CreateContainerConfigError sempre apunta a un ConfigMap o Secret absent, o a una clau inexistent dins d'un que sí que existeix. No ho confonguis amb CrashLoopBackOff (el procés arrenca i mor) ni amb ImagePullBackOff (problema d'imatge). I l'enunciat prohibeix canviar la configuració del contenidor: la solució és crear el Secret, no treure l'envFrom.
Tasca 14 (8 punts) — Resolució de problemes
pod/redis-cache-6f8b...-xyz 1/1 Running
service/redis-cache-svc ClusterIP 10.96.87.4 6379/TCP
endpoints/redis-cache-svc <none> ← el símptomaEls pods estan bé però el Service no els veu. Això només té una explicació: el selector no casa les etiquetes.
k get svc redis-cache-svc -n rutas-norte-pre -o jsonpath='{.spec.selector}'
k get pods -l app=redis-cache -n rutas-norte-pre --show-labelsCausa arrel: el Service selecciona app=redis, però els pods porten app=redis-cache.
k patch svc redis-cache-svc -n rutas-norte-pre \
-p '{"spec":{"selector":{"app":"redis-cache"}}}'
echo "El selector del Service era app=redis i els pods porten app=redis-cache" \
> /opt/diagnostic-14.txtComprovació:
La trampa: l'enunciat prohibeix tocar els pods, així que canviar-ne les etiquetes no val (i a més trencaria el ReplicaSet, que els recrearia). Cal corregir el Service. Recorda la regla: Service sense endpoints = selector que no casa en el 90 % dels casos; el 10 % restant són pods no Ready per una readinessProbe que falla.
Tasca 15 (8 punts) — Resolució de problemes
k get pod informes-ocupacio -n rutas-norte-pro
k describe pod informes-ocupacio -n rutas-norte-pro | tail -6NAME READY STATUS RESTARTS AGE
informes-ocupacio 0/1 Pending 0 14m
Events:
Warning FailedScheduling 2m (x8 over 14m) default-scheduler
0/3 nodes are available: 1 node(s) had untolerated taint
{node-role.kubernetes.io/control-plane: }, 2 node(s) didn't match
Pod's node affinity/selector.Causa arrel: el pod té nodeSelector: disc=nvme i cap node no porta aquesta etiqueta.
k get pod informes-ocupacio -n rutas-norte-pro -o jsonpath='{.spec.nodeSelector}'
k get nodes --show-labels | grep disc || echo "cap node te l etiqueta disc"Dues solucions vàlides. La millor és etiquetar el node, perquè el nodeSelector expressa un requisit real (un disc ràpid per generar informes) i el pod és immutable en aquest camp:
L'alternativa —recrear el pod sense nodeSelector— també deixa el pod Running, però perd la intenció del disseny:
k get pod informes-ocupacio -n rutas-norte-pro -o yaml > t15.yaml
# eliminar la seccio nodeSelector
k delete pod informes-ocupacio -n rutas-norte-pro
k apply -f t15.yamlecho "nodeSelector disc=nvme sense cap node etiquetat; solucio: etiquetar simulacre-worker amb disc=nvme per respectar el requisit de planificacio" \
> /opt/diagnostic-15.txtLa trampa: el missatge de FailedScheduling és la resposta completa i cal saber llegir-lo. didn't match Pod's node affinity/selector és nodeSelector o afinitat; untolerated taint és un taint sense tolerància; Insufficient cpu/memory són recursos; pod has unbound immediate PersistentVolumeClaims és emmagatzematge. Quatre missatges, quatre causes diferents.
Autoavaluació
Suma els punts obtinguts i busca la teva franja.
| Puntuació | Veredicte | Què fer |
|---|---|---|
| 90-100 | A punt per presentar-te. El teu nivell està clarament per damunt del llindar d'aprovat, amb marge per a un mal dia. | Reserva la data ja. Dedica els dies previs a mantenir velocitat, no a estudiar temes nous. |
| 75-89 | Pràcticament a punt. Aprovaries, però sense coixí. | Identifica les 2-3 tasques que vas fallar, repassa'n les lliçons i repeteix el simulacre d'aquí a una setmana. Reserva la data per d'aquí a 2-3 setmanes. |
| 60-74 | Al límit. És la franja del "pot caure de qualsevol costat". | Repassa els dominis de les teves fallades amb les taules de mapatge de les lliçons 12-01, 12-02 o 12-03. Practica 2 setmanes més i repeteix el simulacre. |
| 40-59 | Repassar dominis concrets. El coneixement hi és, però hi ha llacunes i falta velocitat. | Torna a les lliçons dels mòduls on vas fallar (veure taula següent). Treballa 3-4 setmanes abans de repetir. |
| 0-39 | Tornar als mòduls. Falten fonaments, no només pràctica. | Refés el curs des del mòdul corresponent, amb el clúster al davant i fent tots els exercicis. |
Diagnòstic per tasca fallada
Cada tasca apunta a un mòdul concret. Si en vas fallar una, saps exactament on tornar.
| Tasca fallada | Domini | Torna a |
|---|---|---|
| 1 | Càrregues de treball | 02-03-deployments |
| 2 | Serveis i xarxes | 04-02-tipus-de-serveis, 04-04-controladors-dingress |
| 3 | Configuració | 03-01-configmaps, 03-02-secrets, 03-03-variables-dentorn |
| 4 | Emmagatzematge | 05-02-volums-persistents, 05-03-reclamacions-de-volums-persistents |
| 5 | Planificació | 06-05-planificacio-afinitat-taints-i-toleracions |
| 6 | Càrregues per lots | 06-03-treballs-i-cronjobs |
| 7 | Observabilitat i recursos | 07-01-verificacions-de-salut-i-sondes, 03-05-limitranges-i-classes-de-qos |
| 8 | Seguretat i accés | 08-01-control-dacces-basat-en-rols, 03-06-serviceaccounts-i-acces-a-la-api |
| 9 | Seguretat de xarxa | 04-06-politiques-de-xarxa, 08-04-seguretat-de-xarxa |
| 10 | Enduriment | 08-02-contextos-de-seguretat-i-enduriment, 08-03-politiques-de-seguretat-de-pods |
| 11 | Escalat | 09-01-autoescalat-horitzontal-de-pods |
| 12 | Desplegaments | 02-04-actualitzacions-rollbacks-i-estrategies |
| 13, 14, 15 | Resolució de problemes | 07-06-depuracio-i-esdeveniments-del-cluster, 11-06-operacio-en-produccio |
Anàlisi del temps
A més de la nota, revisa els temps que has anotat:
| Situació | Què significa | Remei |
|---|---|---|
| Nota alta però sense acabar a temps | Ho saps fer, però a poc a poc | Àlies, $do, copiar de la documentació (lliçó 12-04) |
| Vas acabar aviat amb nota baixa | Vas ràpid però amb llacunes | Repassar els mòduls de la taula anterior |
| Et vas encallar més de 15 min en una tasca | Falta disciplina de temps | Entrenar el límit dur i el salt sense remordiments |
| Vas fallar per namespace o context | Problema de procés, no de coneixement | Entrenar el cicle context → resoldre → verificar |
| Vas fallar les tres de troubleshooting | El domini de més pes del CKA | Trenca el teu clúster a propòsit i arregla'l, una vegada i una altra |
Conclusió
Aquí acaba el curs.
Vas començar, al mòdul 1, llançant un Pod solt contra un clúster acabat de muntar i preguntant-te per què dimonis calia tanta maquinària per executar un contenidor. Acabes resolent un examen de quinze tasques contrarellotge sobre una plataforma completa en producció.
Entre aquests dos punts hi ha el recorregut de Rutas Norte. Li vas donar forma amb Deployments i Services, la vas configurar sense ficar contrasenyes al codi, la vas publicar amb Ingress i TLS, li vas donar memòria amb volums persistents i còpies de seguretat, li vas ensenyar a arrencar en l'ordre correcte amb initContainers i a sobreviure al manteniment d'un node amb taints i PodDisruptionBudgets. Li vas posar ulls amb Prometheus i Grafana, la vas tancar amb RBAC, NetworkPolicies, Pod Security i signatura d'imatges, la vas fer créixer sola amb HPA i KEDA, la vas empaquetar amb Helm i Kustomize, la vas desplegar sola des de Git amb Argo CD, i la vas operar de debò: amb incidències reals, runbooks, desplegaments canari i una factura de costos que calia justificar.
Què saps fer ara, dit sense adorns:
- Dissenyar i desplegar una aplicació completa a Kubernetes, des del manifest fins a la URL pública amb certificat.
- Triar la primitiva correcta per a cada problema: Deployment o StatefulSet, Job o CronJob, initContainer o sidecar, readiness o liveness.
- Gestionar configuració i secrets sense exposar-los, i controlar el consum de recursos de tot el que corre.
- Muntar, actualitzar i reparar un clúster: nodes, pla de control, etcd, certificats.
- Diagnosticar. I això és el que més et distingirà: davant d'un símptoma —un 503, un pod
Pending, un Service sense endpoints— saps per on començar, quina comanda executar i com arribar a la causa arrel en minuts. - Assegurar el que desplegues, en les tres fases: construcció, desplegament i execució.
- Escalar, mesurar i ajustar, amb dades en lloc d'intuïcions.
- Operar en producció com un professional: amb runbooks, amb procediments de reversió provats i amb consciència del cost.
I si et presentes a una certificació, saps també com funciona l'examen, quins dominis hi entren, on es va estudiar cada objectiu i com es gestionen dues hores de terminal contrarellotge.
Kubernetes continuarà canviant. Apareixeran APIs noves, se'n retiraran d'altres, la Gateway API acabarà desplaçant l'Ingress, i eines que avui són estàndard seran reemplaçades. El que no canvia és el que de debò has après: el model declaratiu, el bucle de reconciliació, la separació entre desig i realitat, i el mètode per esbrinar per què la realitat no coincideix amb el desig. Això es trasllada a qualsevol versió i a qualsevol eina que vingui després.
Munta un clúster propi i no l'apaguis. Trenca coses a propòsit. Desplega-hi els teus projectes encara que no calgui. L'única manera que això no s'oxidi és fer-lo servir.
Bon viatge.
Curs de Kubernetes
Mòdul 1: Introducció a Kubernetes
- Què és Kubernetes?
- Arquitectura de Kubernetes
- Conceptes i Terminologia Clau
- Configuració d'un Clúster de Kubernetes
- La CLI de Kubernetes: kubectl
- Objectes, Manifests YAML i el Model Declaratiu
- El Projecte del Curs: la Plataforma Rutas Norte
Mòdul 2: Components Principals de Kubernetes
- Pods
- ReplicaSets
- Deployments
- Actualitzacions, Rollbacks i Estratègies de Desplegament
- Serveis
- Namespaces
- Etiquetes, Selectors i Anotacions
Mòdul 3: Gestió de Configuració i Secrets
- ConfigMaps
- Secrets
- Variables d'Entorn
- Quotes i Límits de Recursos
- LimitRanges i Classes de Qualitat de Servei (QoS)
- ServiceAccounts i Accés a l'API des dels Pods
Mòdul 4: Xarxes a Kubernetes
- Xarxes de Clúster
- Tipus de Serveis
- DNS Intern i Descobriment de Serveis
- Controladors d'Ingress
- TLS i Gestió de Certificats amb cert-manager
- Polítiques de Xarxa
Mòdul 5: Emmagatzematge a Kubernetes
- Volums
- Volums Persistents
- Reclamacions de Volums Persistents
- Classes d'Emmagatzematge
- Aprovisionament Dinàmic, Expansió i Snapshots
- Còpies de Seguretat i Restauració de Dades
Mòdul 6: Conceptes Avançats de Kubernetes
- StatefulSets
- DaemonSets
- Treballs i CronJobs
- Init Containers, Sidecars i Patrons Multicontenidor
- Planificació: Afinitat, Taints i Toleracions
- Definicions de Recursos Personalitzats (CRDs)
- Operadors i el Patró Controlador
Mòdul 7: Monitoratge i Registre
- Verificacions de Salut i Sondes
- Servidor de Mètriques i kubectl top
- Monitoratge amb Prometheus
- Visualització i Alertes amb Grafana i Alertmanager
- Registre Centralitzat amb Elasticsearch, Fluentd i Kibana (EFK)
- Depuració d'Aplicacions i Esdeveniments del Clúster
Mòdul 8: Seguretat a Kubernetes
- Control d'Accés Basat en Rols (RBAC)
- Contextos de Seguretat i Enduriment del Contenidor
- Polítiques de Seguretat de Pods i Pod Security Standards
- Seguretat de Xarxa
- Seguretat d'Imatges
- Auditoria, Escaneig i Gestió de Vulnerabilitats
Mòdul 9: Escalat i Rendiment
- Autoescalat Horitzontal de Pods
- Autoescalat Vertical de Pods
- Autoescalat de Clúster
- Escalat per Esdeveniments i Mètriques Personalitzades amb KEDA
- Alta Disponibilitat: PodDisruptionBudgets i Topologia
- Ajust de Rendiment
Mòdul 10: Ecosistema i Eines de Kubernetes
- Minikube i Entorns Locals amb kind
- Kubeadm
- Helm
- Kustomize
- GitOps amb Argo CD i Flux
- Kubernetes Gestionat: EKS, AKS i GKE
Mòdul 11: Estudis de Cas i Aplicacions del Món Real
- Desplegament d'una Aplicació Web
- Execució d'Aplicacions amb Estat
- CI/CD amb Kubernetes
- Estratègies de Desplegament: Blue-Green i Canary
- Gestió Multi-Clúster
- Operació en Producció: Incidències, Runbooks i Costos
