Arranca el segundo dominio. Cómo Kubernetes corre y mantiene tus aplicaciones: Deployments, DaemonSets, StatefulSets, cómo se configuran con ConfigMaps y Secrets, y cómo escalan solos con HPA.
The second domain begins. How Kubernetes runs and keeps your applications alive: Deployments, DaemonSets, StatefulSets, how you configure them with ConfigMaps and Secrets, and how they scale on their own with the HPA.
Inizia il secondo dominio. Come Kubernetes esegue e mantiene le tue applicazioni: Deployment, DaemonSet, StatefulSet, come si configurano con ConfigMap e Secret, e come scalano da soli con l'HPA.
Duración60 min
Duration60 min
Durata60 min
DominioWorkloads & Scheduling
DomainWorkloads & Scheduling
DominioWorkloads & Scheduling
Peso15%
Weight15%
Peso15%
Base paraTroubleshooting
Feeds intoTroubleshooting
Base perTroubleshooting
Un Pod solo es frágil: si muere, no vuelve. Los controllers (Deployment, DaemonSet, StatefulSet) son los que mantienen tus pods vivos y en la cantidad correcta — el "estado deseado" del Módulo 1 aplicado a las cargas. Este módulo cubre qué controller usar en cada caso, cómo inyectarles configuración (ConfigMaps/Secrets) y cómo escalan automáticamente (HPA). Todo con foco imperativo: en el examen la velocidad manda.
A lone Pod is fragile: if it dies, it stays dead. Controllers (Deployment, DaemonSet, StatefulSet) are what keep your pods alive and at the right count — Module 1's "desired state" applied to workloads. This module covers which controller to use when, how to inject configuration (ConfigMaps/Secrets) and how they scale automatically (HPA). Imperative throughout: in the exam, speed wins.
Un Pod da solo è fragile: se muore, non torna. I controller (Deployment, DaemonSet, StatefulSet) sono ciò che tiene i pod vivi e nel numero giusto — lo "stato desiderato" del Modulo 1 applicato ai carichi. Questo modulo copre quale controller usare e quando, come iniettare la configurazione (ConfigMap/Secret) e come scalano automaticamente (HPA). Tutto in chiave imperativa: all'esame comanda la velocità.
4.1
Deployments y ReplicaSets
Deployments and ReplicaSets
Deployment e ReplicaSet
El controller estrella. Escalar, rollout, rollback.
The flagship controller. Scale, roll out, roll back.
Il controller di punta. Scalare, rollout, rollback.
4.2
DaemonSets y StatefulSets
DaemonSets and StatefulSets
DaemonSet e StatefulSet
Uno por nodo, o apps con estado e identidad.
One per node, or stateful apps with identity.
Uno per nodo, o app con stato e identità.
4.3
ConfigMaps y Secrets
ConfigMaps and Secrets
ConfigMap e Secret
Inyectar configuración sin hornearla en la imagen.
Inject configuration without baking it into the image.
Iniettare configurazione senza cuocerla nell'immagine.
4.4
HPA
Escalar réplicas automáticamente según carga.
Scale replicas automatically with load.
Scalare le repliche automaticamente in base al carico.
★
Práctica · 7 ejercicios
Practice · 7 exercises
Pratica · 7 esercizi
E1–E5 + 2 de troubleshooting, con solución colapsada.
E1–E5 plus 2 troubleshooting drills, solutions collapsed.
E1–E5 più 2 di troubleshooting, soluzioni collassate.
4.1
El controller estrella · 20 min
The flagship controller · 20 min
Il controller di punta · 20 min
Deployments y ReplicaSets
Deployments and ReplicaSets
Deployment e ReplicaSet
El 90% de lo que corrés en K8s es un Deployment. Dominá su ciclo de vida.
90% of what you run on K8s is a Deployment. Own its lifecycle.
Il 90% di ciò che esegui su K8s è un Deployment. Padroneggiane il ciclo di vita.
Práctica · Ciclo de vida
Practice · Lifecycle
Pratica · Ciclo di vita
Crear y escalar
Create and scale
Creare e scalare
# Crear un deployment# Create a deployment# Creare un deploymentk create deploy web --image=nginx:1.25 --replicas=3
# Escalar# Scale# Scalarek scale deploy web --replicas=5
# Ver el deployment, sus RS y pods# See the deployment, its RS and pods# Vedere il deployment, i suoi RS e i podk get deploy,rs,pods
Rollout: actualizar la imagen
Rollout: update the image
Rollout: aggiornare l'immagine
# Cambiar la imagen: <container>=<imagen># Change the image: <container>=<image># Cambiare l'immagine: <container>=<immagine>k set image deploy/web nginx=nginx:1.26
# Seguir el rollout (BLOQUEA hasta terminar o fallar)# Follow the rollout (BLOCKS until done or failed)# Seguire il rollout (BLOCCA fino a fine o errore)k rollout status deploy/web
# Dejar registrado el motivo (--record está deprecado)# Record the reason (--record is deprecated)# Registrare il motivo (--record è deprecato)k annotate deploy/web kubernetes.io/change-cause="update a 1.26"k rollout history deploy/web
Rollback: volver atrás
Rollback: go back
Rollback: tornare indietro
k rollout undo deploy/web
k rollout undo deploy/web --to-revision=2
★
El rollout es de examen puro: "actualizá esta imagen y verificá", o "volvé a la versión anterior porque la nueva falla". set image, rollout status/history/undo tienen que salir sin pensar.
The rollout family is pure exam material: "update this image and verify", or "roll back, the new version is broken". set image, rollout status/history/undo must come out without thinking.
La famiglia rollout è puro materiale d'esame: "aggiorna questa immagine e verifica", oppure "torna indietro, la nuova versione è rotta". set image, rollout status/history/undo devono uscire senza pensarci.
Teoría · La jerarquía
Theory · The hierarchy
Teoria · La gerarchia
Deployment → ReplicaSet → Pods
Deployment: gestiona rollouts y rollbacks. Es con el que interactuás.
ReplicaSet: mantiene N réplicas vivas. Lo crea el Deployment; casi nunca lo tocás.
Pod: la unidad que corre los containers.
Deployment: manages rollouts and rollbacks. The one you interact with.
ReplicaSet: keeps N replicas alive. Created by the Deployment; you rarely touch it.
Pod: the unit that runs the containers.
Deployment: gestisce rollout e rollback. È quello con cui interagisci.
ReplicaSet: mantiene N repliche vive. Lo crea il Deployment; quasi non lo tocchi.
Pod: l'unità che esegue i container.
Un RS por revisión
One RS per revision
Un RS per revisione
Cada cambio del pod template crea un ReplicaSet nuevo y el Deployment va moviendo pods del viejo al nuevo. El RS viejo queda con 0 réplicas — por eso el rollback es casi instantáneo: solo reescala el RS anterior.
Every change to the pod template creates a new ReplicaSet and the Deployment shifts pods from the old one to the new. The old RS stays at 0 replicas — which is why rollback is near-instant: it just rescales the previous RS.
Ogni modifica al pod template crea un nuovo ReplicaSet e il Deployment sposta i pod dal vecchio al nuovo. Il vecchio RS resta a 0 repliche — ecco perché il rollback è quasi istantaneo: riscala semplicemente il RS precedente.
★
Cambiar replicasno genera revisión: el número de réplicas no es parte del pod template. Y rollout undo no borra la revisión mala — crea una nueva igual a la buena.
Changing replicas does not create a revision: the replica count is not part of the pod template. And rollout undo does not delete the bad revision — it creates a new one identical to the good one.
Cambiare replicasnon genera una revisione: il numero di repliche non fa parte del pod template. E rollout undo non cancella la revisione sbagliata — ne crea una nuova identica a quella buona.
RollingUpdate vs Recreate
RollingUpdate vs Recreate
RollingUpdate vs Recreate
Por defecto es RollingUpdate (reemplaza de a poco, sin downtime). La alternativa es Recreate (mata todo y después crea todo): hay downtime, pero sirve si dos versiones no pueden coexistir.
The default is RollingUpdate (replaces gradually, no downtime). The alternative is Recreate (kill everything, then create everything): there is downtime, but it is what you need when two versions cannot coexist.
Il default è RollingUpdate (sostituisce gradualmente, senza downtime). L'alternativa è Recreate (uccide tutto, poi crea tutto): c'è downtime, ma serve quando due versioni non possono coesistere.
VisorExplorerVisore · qué hacen maxSurge y maxUnavailablewhat maxSurge and maxUnavailable actually docosa fanno davvero maxSurge e maxUnavailable
Los dos límites actúan a la vez: uno pone el techo de pods totales, el otro el piso de pods sirviendo.
Both limits apply at once: one sets the ceiling of total pods, the other the floor of serving pods.
I due limiti agiscono insieme: uno fissa il tetto dei pod totali, l'altro il pavimento dei pod che servono.
4.2
Controllers especializados · 15 min
Specialised controllers · 15 min
Controller specializzati · 15 min
DaemonSets y StatefulSets
DaemonSets and StatefulSets
DaemonSet e StatefulSet
Cuándo NO usar un Deployment.
When NOT to use a Deployment.
Quando NON usare un Deployment.
Práctica · Reconocerlos
Practice · Recognise them
Pratica · Riconoscerli
DaemonSet — uno por nodo
DaemonSet — one per node
DaemonSet — uno per nodo
# NO existe 'kubectl create daemonset'.# There is NO 'kubectl create daemonset'.# NON esiste 'kubectl create daemonset'.# Truco: generá un deployment y editá el kind# Trick: generate a deployment and edit the kind# Trucco: genera un deployment e cambia il kindk create deploy logger --image=fluentd $do > ds.yaml
# kind: Deployment → DaemonSet · borrar replicas y strategy# kind: Deployment → DaemonSet · drop replicas and strategy# kind: Deployment → DaemonSet · togli replicas e strategyk get daemonsets -A
# calico-node y kube-proxy ya son DaemonSets# calico-node and kube-proxy already are DaemonSets# calico-node e kube-proxy sono già DaemonSet
StatefulSet — identidad estable
StatefulSet — stable identity
StatefulSet — identità stabile
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web-sts
spec:
serviceName: nginx-h # ↔ headless service (clusterIP: None)# ↔ headless service (clusterIP: None)# ↔ headless service (clusterIP: None)replicas: 3
selector:
matchLabels: { app: web-sts } # ↔ labels del template# ↔ template labels# ↔ label del templatetemplate:
metadata:
labels: { app: web-sts }
spec:
containers:
- name: nginx
image: nginx
# pods: web-sts-0, -1, -2 (ordinales, en orden, sin hash)# pods: web-sts-0, -1, -2 (ordinal, in order, no hash)# pod: web-sts-0, -1, -2 (ordinali, in ordine, senza hash)
★
Ya conocés DaemonSets sin saberlo: calico-node y kube-proxy corren uno por nodo. Por eso en el upgrade usabas drain --ignore-daemonsets: no se pueden mover, hay uno fijo por nodo.
You already know DaemonSets without realising: calico-node and kube-proxy run one per node. That is why the upgrade needed drain --ignore-daemonsets: they cannot move, there is one pinned per node.
Conosci già i DaemonSet senza saperlo: calico-node e kube-proxy girano uno per nodo. Per questo nell'upgrade usavi drain --ignore-daemonsets: non si possono spostare, ce n'è uno fisso per nodo.
Teoría · Cuál para qué
Theory · Which for what
Teoria · Quale per cosa
Los tres controllers de pods
The three pod controllers
I tre controller di pod
Controller
Para qué
Controller
What for
Controller
A cosa serve
Deployment
Apps sin estado. Réplicas intercambiables
Deployment
Stateless apps. Interchangeable replicas
Deployment
App stateless. Repliche intercambiabili
DaemonSet
Un pod en CADA nodo (logs, red, monitoreo)
DaemonSet
One pod on EVERY node (logs, network, monitoring)
DaemonSet
Un pod su OGNI nodo (log, rete, monitoraggio)
StatefulSet
Apps con estado: identidad y storage estables
StatefulSet
Stateful apps: stable identity and storage
StatefulSet
App con stato: identità e storage stabili
Qué hace especial al StatefulSet
What makes a StatefulSet special
Cosa rende speciale uno StatefulSet
Nombres estables: db-0, db-1 (no aleatorios).
Orden: crea 0 → 1 → 2 y borra al revés.
Storage propio: cada pod tiene su PVC, que sobrevive al pod.
DNS por pod vía el headless service: web-sts-0.nginx-h.ns.svc.cluster.local.
Stable names: db-0, db-1 (not random).
Ordering: creates 0 → 1 → 2 and deletes in reverse.
Own storage: each pod has its PVC, which outlives the pod.
Per-pod DNS via the headless service: web-sts-0.nginx-h.ns.svc.cluster.local.
Nomi stabili: db-0, db-1 (non casuali).
Ordine: crea 0 → 1 → 2 e cancella al contrario.
Storage proprio: ogni pod ha il suo PVC, che sopravvive al pod.
DNS per pod tramite l'headless service: web-sts-0.nginx-h.ns.svc.cluster.local.
★
El bug número uno. Las labels del pod template son la fuente de verdad: tienen que coincidir con spec.selector.matchLabels del controller y con spec.selector del Service. Si no, k get endpoints muestra <none> y el DNS del StatefulSet devuelve NXDOMAIN.
The number-one bug. The pod template labels are the source of truth: they must match the controller's spec.selector.matchLabelsand the Service's spec.selector. Otherwise k get endpoints shows <none> and StatefulSet DNS returns NXDOMAIN.
Il bug numero uno. Le label del pod template sono la fonte di verità: devono coincidere con spec.selector.matchLabels del controller e con spec.selector del Service. Altrimenti k get endpoints mostra <none> e il DNS dello StatefulSet risponde NXDOMAIN.
Regla rápida
Quick rule
Regola rapida
¿Los pods son intercambiables? → Deployment. ¿Necesitás uno por nodo? → DaemonSet. ¿Cada pod es único y tiene datos propios? → StatefulSet.
Are the pods interchangeable? → Deployment. Need one per node? → DaemonSet. Is each pod unique with its own data? → StatefulSet.
I pod sono intercambiabili? → Deployment. Ti serve uno per nodo? → DaemonSet. Ogni pod è unico con dati propri? → StatefulSet.
4.3
Configuración · 15 min
Configuration · 15 min
Configurazione · 15 min
ConfigMaps y Secrets
ConfigMaps and Secrets
ConfigMap e Secret
Separar la configuración del código. La imagen se mantiene genérica.
Separate configuration from code. The image stays generic.
Separare la configurazione dal codice. L'immagine resta generica.
Práctica · Crear e inyectar
Practice · Create and inject
Pratica · Creare e iniettare
Crear
Create
Creare
# ConfigMap desde literales# ConfigMap from literals# ConfigMap da literalk create configmap app-cfg \
--from-literal=COLOR=blue \
--from-literal=MODE=prod
# ConfigMap desde un archivo# ConfigMap from a file# ConfigMap da un filek create configmap app-cfg --from-file=config.txt
# Secret (base64, NO cifrado por defecto)# Secret (base64, NOT encrypted by default)# Secret (base64, NON cifrato di default)k create secret generic db-pass \
--from-literal=password=s3cr3t
Manifiesto completo · las 4 formas juntas
Complete manifest · all 4 forms at once
Manifest completo · le 4 forme insieme
apiVersion: v1
kind: Pod
metadata:
name: demo
spec:
containers:
- name: app
image: nginx
# ─── (A) CM/Secret COMPLETOS como env ───# ─── (A) WHOLE CM/Secret as env vars ───# ─── (A) CM/Secret INTERI come env ───envFrom:
- configMapRef:
name: app-cfg # cada key del CM → env var (mismo nombre)# every CM key → env var (same name)# ogni key del CM → env var (stesso nome)
- secretRef:
name: db-pass # cada key del Secret → env var# every Secret key → env var# ogni key del Secret → env var# ─── (B) UNA key puntual como env (renombrando) ───# ─── (B) ONE specific key as env (renamed) ───# ─── (B) UNA key precisa come env (rinominata) ───env:
- name: APP_COLOR # nombre que VOS elegís# the name YOU pick# il nome che scegli TUvalueFrom:
configMapKeyRef:
name: app-cfg # ← ConfigMap app-cfg# ← ConfigMap app-cfg# ← ConfigMap app-cfgkey: COLOR # ← su key COLOR# ← its COLOR key# ← la sua key COLOR
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-pass # ← Secret db-pass# ← Secret db-pass# ← Secret db-passkey: password # ← su key password# ← its password key# ← la sua key password# ─── (C) montar como ARCHIVOS ───# ─── (C) mount as FILES ───# ─── (C) montare come FILE ───volumeMounts: # DENTRO del container# INSIDE the container# DENTRO il container
- name: cfg-vol # ↔ enlaza con volumes[].name de abajo# ↔ links to volumes[].name below# ↔ si lega a volumes[].name qui sottomountPath: /etc/config # keys de app-cfg = archivos acá# app-cfg keys = files in here# le key di app-cfg = file qui
- name: sec-vol
mountPath: /etc/secret
readOnly: true
volumes: # nivel POD (hermano de containers)# POD level (sibling of containers)# livello POD (fratello di containers)
- name: cfg-vol # ↔ el volumeMount cfg-vol# ↔ the cfg-vol volumeMount# ↔ il volumeMount cfg-volconfigMap:
name: app-cfg # ConfigMap: se usa name:# ConfigMap: uses name:# ConfigMap: usa name:
- name: sec-vol
secret:
secretName: db-pass # Secret: OJO → es secretName:# Secret: CAREFUL → it is secretName:# Secret: ATTENZIONE → è secretName:
💡
Este es un Pod (todo cuelga de spec). En un Deployment/DaemonSet/StatefulSet lo mismo va un nivel más abajo: spec.template.spec.containers[] y spec.template.spec.volumes. La estructura interna es idéntica.
This is a Pod (everything hangs off spec). In a Deployment/DaemonSet/StatefulSet the same thing sits one level deeper: spec.template.spec.containers[] and spec.template.spec.volumes. The inner structure is identical.
Questo è un Pod (tutto pende da spec). In un Deployment/DaemonSet/StatefulSet la stessa cosa sta un livello più sotto: spec.template.spec.containers[] e spec.template.spec.volumes. La struttura interna è identica.
🎯
Trampa clásica: en volumes, un ConfigMap usa name: pero un Secret usa secretName:. Si ponés name: en el volumen del secret, no monta.
Classic trap: under volumes, a ConfigMap uses name: but a Secret uses secretName:. Put name: on the secret volume and it will not mount.
Trappola classica: sotto volumes, un ConfigMap usa name: ma un Secret usa secretName:. Se metti name: nel volume del secret, non monta.
⚠
Dos niveles distintos.volumeMounts va dentro de cada container; volumes va al nivel del pod. El name del volumen y el del mount deben coincidir: así se enlazan.
Two different levels.volumeMounts goes inside each container; volumes goes at the pod level. The volume's name and the mount's must match: that is the link.
Due livelli diversi.volumeMounts va dentro ogni container; volumes va a livello pod. Il name del volume e quello del mount devono coincidere: è così che si legano.
Teoría · El porqué
Theory · The why
Teoria · Il perché
Por qué separar config del código
Why split config from code
Perché separare config e codice
La misma imagen debe correr en dev, staging y prod sin recompilar. La configuración cambia por entorno; la imagen no.
The same image must run in dev, staging and prod without a rebuild. Configuration varies per environment; the image does not.
La stessa immagine deve girare in dev, staging e prod senza ricompilare. La configurazione cambia per ambiente; l'immagine no.
ConfigMap vs Secret
ConfigMap
Secret
Config no sensible
Datos sensibles
Non-sensitive config
Sensitive data
Config non sensibile
Dati sensibili
Texto plano
base64 (NO cifrado)
Plain text
base64 (NOT encrypted)
Testo in chiaro
base64 (NON cifrato)
URLs, flags, modos
Passwords, tokens, certs
URLs, flags, modes
Passwords, tokens, certs
URL, flag, modalità
Password, token, certificati
⚠
Un Secret NO está cifrado por defecto: solo codificado en base64, que cualquiera decodifica. La seguridad real viene de RBAC (quién puede leerlos) y del encryption-at-rest, que se configura aparte.
A Secret is NOT encrypted by default: it is base64-encoded, which anyone can decode. Real security comes from RBAC (who may read them) and encryption-at-rest, configured separately.
Un Secret NON è cifrato di default: è codificato in base64, che chiunque può decodificare. La sicurezza vera viene da RBAC (chi può leggerli) e dall'encryption-at-rest, configurato a parte.
envFrom vs valueFrom
envFrom
env + valueFrom
Cuántas variables
Todas las del CM/Secret
Una (repetís el bloque)
How many vars
All of the CM/Secret
One (repeat the block)
Quante variabili
Tutte quelle del CM/Secret
Una (ripeti il blocco)
Nombre de la var
= la key (o prefix+key)
lo elegís vos
Variable name
= the key (or prefix+key)
you choose it
Nome della variabile
= la key (o prefix+key)
lo scegli tu
Uso típico
app que espera muchas vars
una key puntual o renombrarla
Typical use
app expecting many vars
one specific key, or renaming it
Uso tipico
app che si aspetta molte var
una key precisa, o rinominarla
Mnemotécnica: envFrom = "traeme todo con estos mismos nombres"; valueFrom = "traeme ESTA y la llamo como quiero".
Mnemonic: envFrom = "bring me everything under these same names"; valueFrom = "bring me THIS one and I'll name it myself".
Mnemonica: envFrom = "portami tutto con questi stessi nomi"; valueFrom = "portami QUESTA e la chiamo come voglio".
🎯
Si referenciás con valueFrom un CM/Secret o una key que no existe, el pod no arranca: queda en CreateContainerConfigError. Con envFrom pasa lo mismo si falta el objeto entero, salvo que pongas optional: true.
If valueFrom points at a CM/Secret or a key that does not exist, the pod will not start: it sits in CreateContainerConfigError. Same with envFrom if the whole object is missing, unless you set optional: true.
Se valueFrom punta a un CM/Secret o a una key inesistente, il pod non parte: resta in CreateContainerConfigError. Lo stesso con envFrom se manca l'oggetto intero, a meno di mettere optional: true.
⚠
Las env vars son una foto del arranque: si editás el ConfigMap después, el pod no ve el cambio hasta que lo recreás (k rollout restart). El montaje como volumen sí se actualiza solo. Ese es el trade-off. Y para verificar usá printenv, nunca echo $VAR (lo expande tu shell local, no el container).
Env vars are a boot-time snapshot: edit the ConfigMap afterwards and the pod will not see it until you recreate it (k rollout restart). A volume mount does refresh on its own. That is the trade-off. And to verify, use printenv, never echo $VAR (your local shell expands that, not the container).
Le env var sono una istantanea all'avvio: se modifichi il ConfigMap dopo, il pod non lo vede finché non lo ricrei (k rollout restart). Il mount come volume invece si aggiorna da solo. È questo il compromesso. E per verificare usa printenv, mai echo $VAR (lo espande la tua shell locale, non il container).
💡
Si definís env y envFrom y hay colisión de nombre, el valor explícito de envpisa al de envFrom.
If you define both env and envFrom and a name collides, the explicit env value wins over the envFrom one.
Se definisci sia env sia envFrom e c'è collisione di nome, il valore esplicito di envvince su quello di envFrom.
4.4
Escalado automático · 10 min
Autoscaling · 10 min
Scalabilità automatica · 10 min
Horizontal Pod Autoscaler
Que el cluster ajuste las réplicas solo, según la carga.
Let the cluster adjust replicas on its own, following load.
Che sia il cluster ad aggiustare le repliche da solo, in base al carico.
Práctica · Crear un HPA
Practice · Create an HPA
Pratica · Creare un HPA
Crear un autoscaler
Create an autoscaler
Creare un autoscaler
# El deployment DEBE tener requests.cpu primero# The deployment MUST have requests.cpu first# Il deployment DEVE avere prima requests.cpuk set resources deploy web --requests=cpu=100m
# Escalar entre 2 y 10 réplicas, objetivo 50% de CPU# Scale between 2 and 10 replicas, target 50% CPU# Scalare fra 2 e 10 repliche, obiettivo 50% di CPUk autoscale deploy web --min=2 --max=10 --cpu=50%
# --cpu-percent=50 sigue andando pero está deprecado# --cpu-percent=50 still works but is deprecated# --cpu-percent=50 funziona ancora ma è deprecatok get hpa
k describe hpa web
El <unknown> y cómo se arregla
The <unknown> and how to fix it
L'<unknown> e come si risolve
k get hpa # TARGETS <unknown>/50%# TARGETS <unknown>/50%# TARGETS <unknown>/50%k top pods # el test de 3 segundos: ¿hay métricas?# the 3-second test: are there metrics?# il test di 3 secondi: ci sono metriche?# Si no las hay, falta metrics-server (en labs kubeadm# If not, metrics-server is missing (in kubeadm labs# Se non ci sono, manca metrics-server (nei lab kubeadm# además hay que tolerar los certs self-signed del kubelet)# you must also tolerate the kubelet's self-signed certs)# bisogna anche tollerare i cert self-signed del kubelet)k patch deploy metrics-server -n kube-system --type=json \
-p='[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]'
Teoría · Cómo decide
Theory · How it decides
Teoria · Come decide
Qué hace el HPA
What the HPA does
Cosa fa l'HPA
Vigila una métrica (típicamente CPU) de los pods de un Deployment. Si la carga supera el objetivo, agrega réplicas; si baja, las quita. Todo dentro del rango min/max.
It watches a metric (typically CPU) across a Deployment's pods. If load exceeds the target it adds replicas; if it drops it removes them. All within the min/max range.
Sorveglia una metrica (tipicamente la CPU) sui pod di un Deployment. Se il carico supera l'obiettivo aggiunge repliche; se cala le toglie. Tutto entro il range min/max.
La cuenta simplificada
The simplified maths
Il conto semplificato
Si el objetivo es 50% y los pods están al 100%, el HPA duplica las réplicas para repartir la carga a la mitad. Es proporcional: apunta a que el promedio quede en el target.
If the target is 50% and pods sit at 100%, the HPA doubles the replicas to halve the load. It is proportional: it aims for the average to land on the target.
Se l'obiettivo è il 50% e i pod sono al 100%, l'HPA raddoppia le repliche per dimezzare il carico. È proporzionale: punta a far cadere la media sull'obiettivo.
Las 3 piezas necesarias
The 3 required pieces
I 3 pezzi necessari
metrics-server instalado y listo.
requests.cpu en el pod (base del cálculo del %).
el HPA con min/max/target.
metrics-server installed and ready.
requests.cpu on the pod (the base of the % calculation).
the HPA itself with min/max/target.
metrics-server installato e pronto.
requests.cpu nel pod (base del calcolo della %).
l'HPA stesso con min/max/target.
★
Falta cualquiera de las dos primeras → <unknown>. Y ojo: Horizontal = más pods (a lo ancho); el Vertical (VPA), que agranda cada pod, no entra en el CKA.
Miss either of the first two → <unknown>. And note: Horizontal = more pods (scale out); Vertical (VPA), which grows each pod, is not on the CKA.
Se manca uno dei primi due → <unknown>. E attenzione: Horizontal = più pod (in larghezza); il Vertical (VPA), che ingrandisce ogni pod, non è nel CKA.
★
Cierre del módulo
Module wrap-up
Chiusura del modulo
Lo que te llevás del Módulo 4
What you take from Module 4
Cosa porti via dal Modulo 4
Resumen · Comandos clave
Summary · Key commands
Riassunto · Comandi chiave
Para tu chuleta
For your cheat sheet
Per il tuo bigliettino
### Deploymentsk create deploy NAME --image=IMG --replicas=N
k scale deploy NAME --replicas=N
k set image deploy/NAME cont=img:tag
k rollout status|history|undo deploy/NAME
k rollout restart deploy/NAME
### ConfigMaps / Secretsk create configmap NAME --from-literal=K=V
k create secret generic NAME --from-literal=K=V
k exec POD -- printenv K
### HPAk autoscale deploy NAME --min=2 --max=10 --cpu=50%
### Sin generador imperativo → dry-run y editar kind### No imperative generator → dry-run and edit the kind### Senza generatore imperativo → dry-run e cambia kind# DaemonSet · StatefulSetk create service clusterip NAME --clusterip=None # headless# headless# headless
Teoría · Lo esencial
Theory · The essentials
Teoria · L'essenziale
Las 4 ideas que no se negocian
The 4 non-negotiable ideas
Le 4 idee non negoziabili
Deployment → ReplicaSet → Pods. El rollout crea un RS nuevo; el rollback reactiva el viejo.
DaemonSet = uno por nodo. StatefulSet = identidad + storage estables.
ConfigMap (config) vs Secret (sensible, base64 ≠ cifrado). Se consumen como env o como volumen.
HPA = más pods según carga. Necesita metrics-server + requests.cpu.
Deployment → ReplicaSet → Pods. A rollout creates a new RS; a rollback reactivates the old one.
DaemonSet = one per node. StatefulSet = stable identity + storage.
ConfigMap (config) vs Secret (sensitive, base64 ≠ encrypted). Consumed as env or as a volume.
HPA = more pods under load. Needs metrics-server + requests.cpu.
Deployment → ReplicaSet → Pod. Un rollout crea un nuovo RS; un rollback riattiva quello vecchio.
DaemonSet = uno per nodo. StatefulSet = identità + storage stabili.
ConfigMap (config) vs Secret (sensibile, base64 ≠ cifrato). Si consumano come env o come volume.
HPA = più pod sotto carico. Richiede metrics-server + requests.cpu.
★
Este módulo conecta con Troubleshooting (30%): muchos pods rotos son ConfigMaps/Secrets mal referenciados o rollouts que fallan. Entenderlo ahora te ahorra sufrir después.
This module feeds Troubleshooting (30%): a lot of broken pods are mis-referenced ConfigMaps/Secrets or failed rollouts. Getting it now saves pain later.
Questo modulo alimenta il Troubleshooting (30%): molti pod rotti sono ConfigMap/Secret referenziati male o rollout falliti. Capirlo ora ti risparmia dolore dopo.
E1–E5 construyen; T1–T2 diagnostican. ~5 min cada uno.
E1–E5 build; T1–T2 diagnose. ~5 min each.
E1–E5 costruiscono; T1–T2 diagnosticano. ~5 min ciascuno.
0 / 7
⚙
Setup.k create ns m4 y -n m4 en todo (el olvido más caro del examen). Cluster de 2 nodos: el control plane está tainteado, así que un DaemonSet sin toleration cae en 1 solo nodo — eso es parte del E2, no un error.
Setup.k create ns m4 and -n m4 on everything (the costliest thing to forget in the exam). Two-node cluster: the control plane is tainted, so a DaemonSet without a toleration lands on one node only — that is part of E2, not a bug.
Setup.k create ns m4 e -n m4 su tutto (la dimenticanza più cara all'esame). Cluster a 2 nodi: il control plane è taintato, quindi un DaemonSet senza toleration finisce su un solo nodo — fa parte dell'E2, non è un errore.
🧠
Modelo mental. Un controller mantiene un estado deseado: réplicas (Deployment), uno por nodo (DaemonSet), identidad ordinal (StatefulSet). La configuración entra desde afuera (CM/Secret) como env o como archivos. El HPA mueve el número de réplicas. Resolvé antes de abrir la solución.
Mental model. A controller maintains a desired state: replicas (Deployment), one per node (DaemonSet), ordinal identity (StatefulSet). Configuration comes from outside (CM/Secret) as env vars or files. The HPA moves the replica count. Solve it before opening the solution.
Modello mentale. Un controller mantiene uno stato desiderato: repliche (Deployment), uno per nodo (DaemonSet), identità ordinale (StatefulSet). La configurazione arriva da fuori (CM/Secret) come env o come file. L'HPA muove il numero di repliche. Risolvi prima di aprire la soluzione.
E1
Deployment — ciclo de vida completo
Deployment — the full lifecycle
Deployment — ciclo di vita completo
~5 min
Creá el Deployment web, imagen nginx:1.25, 3 réplicas.
Escalalo a 5.
Rolling update a nginx:1.26 y seguí el rollout hasta el final.
Mostrá el historial de revisiones con el motivo del cambio.
Rollback a la revisión anterior y confirmá que las 5 réplicas corren nginx:1.25.
Rolling-update to nginx:1.26 and follow the rollout to the end.
Show the revision history with the change reason.
Roll back to the previous revision and confirm all 5 replicas run nginx:1.25.
Crea il Deployment web, immagine nginx:1.25, 3 repliche.
Scalalo a 5.
Rolling update a nginx:1.26 e segui il rollout fino alla fine.
Mostra lo storico delle revisioni con il motivo della modifica.
Rollback alla revisione precedente e conferma che le 5 repliche eseguono nginx:1.25.
Ver soluciónShow solutionMostra soluzione
k create deploy web --image=nginx:1.25 --replicas=3 -n m4
k scale deploy web --replicas=5 -n m4
k set image deploy/web nginx=nginx:1.26 -n m4
k rollout status deploy/web -n m4
k annotate deploy/web -n m4 kubernetes.io/change-cause="update a 1.26"k rollout history deploy/web -n m4
k rollout undo deploy/web -n m4
k get deploy web -n m4 -o wide # IMAGES nginx:1.25 · READY 5/5# IMAGES nginx:1.25 · READY 5/5# IMAGES nginx:1.25 · READY 5/5
Claves
Key points
Punti chiave
El container de create deploy web --image=nginx:1.25 se llama nginx (por la imagen) → de ahí set image ... nginx=nginx:1.26, que es <container>=<imagen>.
rollout statusbloquea hasta terminar o fallar: ideal para saber que quedó sano.
Sin change-cause el historial muestra <none>. --record está deprecado.
El undo no borra la revisión mala: crea una nueva igual a la buena.
The container from create deploy web --image=nginx:1.25 is named nginx (after the image) → hence set image ... nginx=nginx:1.26, which is <container>=<image>.
rollout statusblocks until it finishes or fails: perfect for knowing it ended healthy.
Without change-cause the history shows <none>. --record is deprecated.
undo does not delete the bad revision: it creates a new one identical to the good one.
Il container di create deploy web --image=nginx:1.25 si chiama nginx (come l'immagine) → da qui set image ... nginx=nginx:1.26, cioè <container>=<immagine>.
rollout statusblocca fino a fine o errore: ideale per sapere che è andato a buon fine.
Senza change-cause lo storico mostra <none>. --record è deprecato.
undo non cancella la revisione sbagliata: ne crea una nuova identica a quella buona.
E2
DaemonSet — uno por nodo (y por qué a veces es uno solo)
DaemonSet — one per node (and why sometimes just one)
DaemonSet — uno per nodo (e perché a volte è uno solo)
~5 min
Creá un DaemonSet agente con imagen busybox que corra sleep 1d. Verificá cuántos pods hay y explicá por qué son 1 y no 2. Después conseguí que sean 2.
Create a DaemonSet agente with image busybox running sleep 1d. Check how many pods there are and explain why it is 1 and not 2. Then make it 2.
Crea un DaemonSet agente con immagine busybox che esegua sleep 1d. Verifica quanti pod ci sono e spiega perché è 1 e non 2. Poi fai in modo che siano 2.
Ver soluciónShow solutionMostra soluzione
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: agente
namespace: m4
spec:
selector:
matchLabels: { app: agente }
template:
metadata:
labels: { app: agente }
spec:
tolerations: # para llegar también al control plane# to reach the control plane too# per arrivare anche al control plane
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
containers:
- name: agente
image: busybox
command: ["sleep", "1d"]
k get ds agente -n m4 # DESIRED = nodos elegibles# DESIRED = eligible nodes# DESIRED = nodi eleggibilik get pods -n m4 -o wide # mirá la columna NODE# look at the NODE column# guarda la colonna NODE
Claves
Key points
Punti chiave
No existe k create daemonset. Truco: k create deploy tmp --image=busybox $do > ds.yaml, cambiar kind y borrar replicas/strategy.
Un DaemonSet no tiene replicas: un pod por nodo elegible. Escala solo al agregar o quitar nodos.
Por qué eran 1: el control plane tiene el taint node-role.kubernetes.io/control-plane:NoSchedule. Sin toleration, el DS solo cae en el worker. Con la toleration, DESIRED pasa de 1 a 2.
There is no k create daemonset. Trick: k create deploy tmp --image=busybox $do > ds.yaml, change the kind and delete replicas/strategy.
A DaemonSet has no replicas: one pod per eligible node. It scales only as nodes come and go.
Why it was 1: the control plane carries the taint node-role.kubernetes.io/control-plane:NoSchedule. Without a toleration the DS only lands on the worker. Add it and DESIRED goes 1 → 2.
Non esiste k create daemonset. Trucco: k create deploy tmp --image=busybox $do > ds.yaml, cambia il kind e togli replicas/strategy.
Un DaemonSet non ha replicas: un pod per nodo eleggibile. Scala solo quando aggiungi o togli nodi.
Perché era 1: il control plane ha il taint node-role.kubernetes.io/control-plane:NoSchedule. Senza toleration il DS finisce solo sul worker. Con la toleration, DESIRED passa da 1 a 2.
E3
StatefulSet + headless service — identidad estable
StatefulSet + headless service — stable identity
StatefulSet + headless service — identità stabile
~7 min
Creá un headless Service nginx-h y un StatefulSet web-sts (nginx, 3 réplicas) que lo use como serviceName. Verificá los nombres ordinales, que se crean en orden, y que el DNS por pod resuelve.
Create a headless Service nginx-h and a StatefulSet web-sts (nginx, 3 replicas) using it as serviceName. Verify the ordinal names, that they are created in order, and that per-pod DNS resolves.
Crea un headless Service nginx-h e uno StatefulSet web-sts (nginx, 3 repliche) che lo usi come serviceName. Verifica i nomi ordinali, che vengano creati in ordine, e che il DNS per pod risolva.
Ver soluciónShow solutionMostra soluzione
# el Service headless se puede generar imperativo# the headless Service can be generated imperatively# il Service headless si può generare in modo imperativok create service clusterip nginx-h --clusterip=None -n m4 $do > sts.yaml
# OJO: el generador pone selector app=nginx-h → cambialo a app=web-sts# CAREFUL: the generator sets selector app=nginx-h → change it to app=web-sts# ATTENZIONE: il generatore mette selector app=nginx-h → cambialo in app=web-stsapiVersion: apps/v1
kind: StatefulSet
metadata:
name: web-sts
namespace: m4
spec:
serviceName: nginx-h
replicas: 3
selector:
matchLabels: { app: web-sts }
template:
metadata:
labels: { app: web-sts }
spec:
containers:
- name: nginx
image: nginx
k get pods -n m4 -w # -0, después -1, después -2# -0, then -1, then -2# -0, poi -1, poi -2k get endpoints nginx-h -n m4 # si dice <none>, el selector no matchea# if it says <none>, the selector does not match# se dice <none>, il selector non corrispondek run t --rm -it --image=busybox -n m4 -- \
nslookup web-sts-0.nginx-h.m4.svc.cluster.local
Claves
Key points
Punti chiave
clusterIP: None = headless: no hay IP virtual, hay DNS por pod. Eso es lo que da identidad de red estable.
El bug que vas a cometer: el generador de Service pone selector: app=nginx-h, pero las labels del template son app=web-sts → ENDPOINTS <none> → NXDOMAIN. Las labels del template mandan.
Nombres ordinales estables, creación 0→1→2 y borrado al revés: eso lo distingue de un Deployment.
clusterIP: None = headless: no virtual IP, but per-pod DNS. That is what grants stable network identity.
The bug you will hit: the Service generator writes selector: app=nginx-h, but the template labels are app=web-sts → ENDPOINTS <none> → NXDOMAIN. Template labels rule.
Stable ordinal names, creation 0→1→2 and deletion in reverse: that is what sets it apart from a Deployment.
clusterIP: None = headless: nessun IP virtuale, ma DNS per pod. È questo che dà identità di rete stabile.
Il bug che farai: il generatore del Service scrive selector: app=nginx-h, ma le label del template sono app=web-sts → ENDPOINTS <none> → NXDOMAIN. Comandano le label del template.
Nomi ordinali stabili, creazione 0→1→2 e cancellazione al contrario: è ciò che lo distingue da un Deployment.
E4
ConfigMap + Secret — las 4 formas de inyectar
ConfigMap + Secret — the 4 ways to inject
ConfigMap + Secret — i 4 modi di iniettare
~7 min
ConfigMap app-cfg con COLOR=blue y MODE=prod; Secret db-pass con password=s3cr3t.
Pod demo (nginx) que: (a) traiga todoapp-cfg con envFrom; (b) inyecte db-pass/password renombrada a DB_PASSWORD; (c) monte app-cfg como archivos en /etc/config.
Verificá las env vars y los archivos.
ConfigMap app-cfg with COLOR=blue and MODE=prod; Secret db-pass with password=s3cr3t.
Pod demo (nginx) that: (a) pulls all of app-cfg via envFrom; (b) injects db-pass/password renamed to DB_PASSWORD; (c) mounts app-cfg as files in /etc/config.
Verify the env vars and the files.
ConfigMap app-cfg con COLOR=blue e MODE=prod; Secret db-pass con password=s3cr3t.
Pod demo (nginx) che: (a) porti tuttoapp-cfg con envFrom; (b) inietti db-pass/password rinominata in DB_PASSWORD; (c) monti app-cfg come file in /etc/config.
Verifica le env var e i file.
Ver soluciónShow solutionMostra soluzione
k create configmap app-cfg --from-literal=COLOR=blue --from-literal=MODE=prod -n m4
k create secret generic db-pass --from-literal=password=s3cr3t -n m4
# el manifiesto completo está arriba, en la sección 4.3# the complete manifest is above, in section 4.3# il manifest completo è sopra, nella sezione 4.3# verificar: printenv, NUNCA echo $VAR# verify: printenv, NEVER echo $VAR# verificare: printenv, MAI echo $VARk exec demo -n m4 -- printenv COLOR MODE DB_PASSWORD
k exec demo -n m4 -- ls /etc/config # COLOR MODE (un archivo por key)# COLOR MODE (one file per key)# COLOR MODE (un file per key)k exec demo -n m4 -- cat /etc/config/COLOR # blue# blue# blue
Claves
Key points
Punti chiave
echo $COLOR devuelve vacío porque lo expande tu shell del host antes de llegar al container. Usá printenv, env | grep, o sh -c 'echo $COLOR' con comillas simples.
En volumes: ConfigMap → name:; Secret → secretName:.
Env = foto del arranque. Volumen = se actualiza solo al tiempo.
echo $COLOR comes back empty because your host shell expands it before it ever reaches the container. Use printenv, env | grep, or sh -c 'echo $COLOR' with single quotes.
Under volumes: ConfigMap → name:; Secret → secretName:.
Env = boot snapshot. Volume = refreshes on its own after a while.
echo $COLOR torna vuoto perché lo espande la tua shell dell'host prima ancora di arrivare al container. Usa printenv, env | grep, o sh -c 'echo $COLOR' con apici singoli.
Sotto volumes: ConfigMap → name:; Secret → secretName:.
Env = istantanea all'avvio. Volume = si aggiorna da solo dopo un po'.
E5
HPA — crear y diagnosticar el <unknown>
HPA — create it and diagnose the <unknown>
HPA — crearlo e diagnosticare l'<unknown>
~7 min
Creá un Deployment hpa-web (nginx) con requests.cpu=100m y un HPA (min 1, max 5, target 50% CPU). Vas a ver TARGETS <unknown>/50%. Diagnosticá por qué y dejalo funcionando.
Create a Deployment hpa-web (nginx) with requests.cpu=100m and an HPA (min 1, max 5, target 50% CPU). You will see TARGETS <unknown>/50%. Diagnose why and get it working.
Crea un Deployment hpa-web (nginx) con requests.cpu=100m e un HPA (min 1, max 5, target 50% CPU). Vedrai TARGETS <unknown>/50%. Diagnostica il perché e fallo funzionare.
Ver soluciónShow solutionMostra soluzione
k create deploy hpa-web --image=nginx -n m4
k set resources deploy hpa-web -n m4 --requests=cpu=100m
k autoscale deploy hpa-web -n m4 --min=1 --max=5 --cpu=50%
k get hpa -n m4 # TARGETS <unknown>/50% ← ¿por qué?# TARGETS <unknown>/50% ← why?# TARGETS <unknown>/50% ← perché?k top pods -n m4 # error: Metrics API not available# error: Metrics API not available# error: Metrics API not availablek apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
k patch deploy metrics-server -n kube-system --type=json \
-p='[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]'k rollout status deploy metrics-server -n kube-system
k get hpa -n m4 # TARGETS 0%/50%# TARGETS 0%/50%# TARGETS 0%/50%
Claves
Key points
Punti chiave
<unknown> casi siempre = no hay métricas. k top es el test de 3 segundos: si falla, el HPA no tiene datos.
Si el HPA ya existía de un intento anterior, autoscale falla con "already exists / incompatible with autoscaling/v1". Borralo y recrealo.
--kubelet-insecure-tls es solo para labs kubeadm (certs self-signed). En el examen metrics-server ya está; lo que importa es reconocer el diagnóstico.
<unknown> almost always means no metrics. k top is the 3-second test: if it fails, the HPA has no data.
If an HPA already existed from a previous attempt, autoscale fails with "already exists / incompatible with autoscaling/v1". Delete and recreate it.
--kubelet-insecure-tls is only for kubeadm labs (self-signed certs). In the exam metrics-server is already there; what matters is recognising the diagnosis.
<unknown> quasi sempre significa niente metriche. k top è il test da 3 secondi: se fallisce, l'HPA non ha dati.
Se un HPA esisteva già da un tentativo precedente, autoscale fallisce con "already exists / incompatible with autoscaling/v1". Cancellalo e ricrealo.
--kubelet-insecure-tls serve solo nei lab kubeadm (cert self-signed). All'esame metrics-server c'è già; conta riconoscere la diagnosi.
T1
Troubleshooting — el rollout que no avanza
Troubleshooting — the rollout that never lands
Troubleshooting — il rollout che non avanza
~5 min
El Deployment broken-rollout tiene pods en ImagePullBackOff tras el último cambio de imagen. Diagnosticá la causa y dejalo sano.
Para plantarlo vos mismo:k create deploy broken-rollout --image=nginx:1.26 -n m4 && k set image deploy/broken-rollout nginx=nginx:9.99-noexiste -n m4
Deployment broken-rollout has pods in ImagePullBackOff after the last image change. Diagnose the cause and get it healthy.
To plant it yourself:k create deploy broken-rollout --image=nginx:1.26 -n m4 && k set image deploy/broken-rollout nginx=nginx:9.99-noexiste -n m4
Il Deployment broken-rollout ha pod in ImagePullBackOff dopo l'ultimo cambio di immagine. Diagnostica la causa e rimettilo in salute.
Per prepararlo da solo:k create deploy broken-rollout --image=nginx:1.26 -n m4 && k set image deploy/broken-rollout nginx=nginx:9.99-noexiste -n m4
Ver soluciónShow solutionMostra soluzione
k rollout status deploy/broken-rollout -n m4 # no progresa# does not progress# non avanzak describe pod <pod> -n m4 | grep -A6 Events
# Failed to pull image "...": tag inexistente# Failed to pull image "...": tag does not exist# Failed to pull image "...": tag inesistente# A · corregir la imagen# A · fix the image# A · correggere l'immaginek set image deploy/broken-rollout nginx=nginx:1.26 -n m4
# B · o deshacer si la revisión anterior era buena# B · or undo if the previous revision was good# B · o annullare se la revisione precedente era buonak rollout undo deploy/broken-rollout -n m4
Claves
Key points
Punti chiave
ImagePullBackOff / ErrImagePull = el nodo no pudo bajar la imagen (tag mal escrito, repo privado, typo). Está en los Events del describe pod.
Un rollout malo no tira la app: el RS viejo sigue sirviendo porque el rolling update espera a que el nuevo esté Ready. Por eso el undo es seguro.
Reflejo: rollout status (¿está trabado?) → describe pod (¿por qué?) → set image o rollout undo.
ImagePullBackOff / ErrImagePull = the node could not pull the image (wrong tag, private repo, typo). It is in the describe pod Events.
A bad rollout does not take the app down: the old RS keeps serving because the rolling update waits for the new pod to be Ready. That is why undo is safe.
Reflex: rollout status (stuck?) → describe pod (why?) → set image or rollout undo.
ImagePullBackOff / ErrImagePull = il nodo non è riuscito a scaricare l'immagine (tag sbagliato, repo privato, refuso). Sta negli Events del describe pod.
Un rollout sbagliato non butta giù l'app: il vecchio RS continua a servire perché il rolling update aspetta che il nuovo sia Ready. Per questo l'undo è sicuro.
Riflesso: rollout status (è bloccato?) → describe pod (perché?) → set image o rollout undo.
T2
Troubleshooting — CreateContainerConfigError
Troubleshooting — CreateContainerConfigError
Troubleshooting — CreateContainerConfigError
~5 min
El Pod cfg-broken no llega a arrancar: queda en CreateContainerConfigError. Diagnosticá y hacelo correr.
Para plantarlo vos mismo: un ConfigMap app-settings con LOG_LEVEL y TIMEOUT, y un pod que pida por configMapKeyRef la key SECRET_TOKEN, que no existe.
Pod cfg-broken never starts: it sits in CreateContainerConfigError. Diagnose it and get it running.
To plant it yourself: a ConfigMap app-settings holding LOG_LEVEL and TIMEOUT, and a pod asking via configMapKeyRef for the key SECRET_TOKEN, which does not exist.
Il Pod cfg-broken non parte: resta in CreateContainerConfigError. Diagnostica e fallo partire.
Per prepararlo da solo: un ConfigMap app-settings con LOG_LEVEL e TIMEOUT, e un pod che chiede via configMapKeyRef la key SECRET_TOKEN, che non esiste.
Ver soluciónShow solutionMostra soluzione
k get pod cfg-broken -n m4 # CreateContainerConfigError# CreateContainerConfigError# CreateContainerConfigErrork describe pod cfg-broken -n m4 | grep -A6 Events
# couldn't find key SECRET_TOKEN in ConfigMap m4/app-settings# couldn't find key SECRET_TOKEN in ConfigMap m4/app-settings# couldn't find key SECRET_TOKEN in ConfigMap m4/app-settings# agregar la key que falta (o corregir la referencia del pod)# add the missing key (or fix the pod's reference)# aggiungere la key mancante (o correggere il riferimento del pod)k edit cm app-settings -n m4
k get pod cfg-broken -n m4 # Running, sin borrar el pod# Running, without deleting the pod# Running, senza cancellare il pod
Claves
Key points
Punti chiave
CreateContainerConfigError = el kubelet no pudo armar la config del container: casi siempre un configMapKeyRef/secretKeyRef hacia un objeto o key inexistente.
El estado te dice en qué etapa falló: ImagePullBackOff (imagen) → CreateContainerConfigError (config) → CrashLoopBackOff (el proceso arranca y se muere).
Detalle lindo: el pod se recupera solo al arreglar el CM, sin borrarlo — el container nunca llegó a arrancar, así que el kubelet sigue reintentando.
CreateContainerConfigError = the kubelet could not assemble the container config: nearly always a configMapKeyRef/secretKeyRef pointing at a missing object or key.
The status tells you which stage failed: ImagePullBackOff (image) → CreateContainerConfigError (config) → CrashLoopBackOff (the process starts and dies).
Nice detail: the pod recovers by itself once you fix the CM, no delete needed — the container never started, so the kubelet keeps retrying.
CreateContainerConfigError = il kubelet non è riuscito a comporre la config del container: quasi sempre un configMapKeyRef/secretKeyRef che punta a un oggetto o a una key inesistente.
Lo stato ti dice in quale fase è fallito: ImagePullBackOff (immagine) → CreateContainerConfigError (config) → CrashLoopBackOff (il processo parte e muore).
Dettaglio carino: il pod si riprende da solo una volta corretto il CM, senza cancellarlo — il container non è mai partito, quindi il kubelet continua a riprovare.
✕
Limpieza
Cleanup
Pulizia
~1 min
Todo lo de M4 es namespaced, así que alcanza con el namespace. El metrics-server, si lo instalaste, dejalo: te sirve para M5 y para troubleshooting.
Everything in M4 is namespaced, so the namespace is enough. Leave metrics-server installed if you added it: it is useful for M5 and for troubleshooting.
Tutto in M4 è namespaced, quindi basta il namespace. Lascia installato metrics-server se l'hai aggiunto: serve per M5 e per il troubleshooting.
k delete ns m4
Autoevaluación — antes de marcar M4 como ★ dominado
Self-check — before marking M4 as ★ mastered
Autovalutazione — prima di segnare M4 come ★ padroneggiato
Ciclo completo de Deployment: create → scale → set image → rollout status → history → undo.
Crear un DaemonSet y explicar por qué cae en 1 o 2 nodos.
Crear un StatefulSet + headless service y reconocer la identidad ordinal estable.
Inyectar config de las 4 formas y verificar con printenv.
Crear un HPA y diagnosticar el <unknown>.
Diagnosticar ImagePullBackOff y arreglarlo con set image o rollout undo.
Reconocer CreateContainerConfigError como CM/Secret/key faltante.
Full Deployment cycle: create → scale → set image → rollout status → history → undo.
Create a DaemonSet and explain why it lands on 1 or 2 nodes.
Create a StatefulSet + headless service and recognise the stable ordinal identity.
Inject config in all 4 forms and verify with printenv.
Create an HPA and diagnose the <unknown>.
Diagnose ImagePullBackOff and fix it with set image or rollout undo.
Recognise CreateContainerConfigError as a missing CM/Secret/key.
Ciclo completo di Deployment: create → scale → set image → rollout status → history → undo.
Creare un DaemonSet e spiegare perché finisce su 1 o 2 nodi.
Creare uno StatefulSet + headless service e riconoscere l'identità ordinale stabile.
Iniettare la config in tutte e 4 le forme e verificare con printenv.
Creare un HPA e diagnosticare l'<unknown>.
Diagnosticare ImagePullBackOff e correggerlo con set image o rollout undo.
Riconoscere CreateContainerConfigError come CM/Secret/key mancante.
Módulo 4 completado · Los workloads y su configuración · Siguiente: Scheduling
Module 4 complete · Workloads and their configuration · Next: Scheduling
Modulo 4 completato · I workload e la loro configurazione · Prossimo: Scheduling