A la lliçó anterior vam aixecar clústers llencables al portàtil i vam descobrir, gairebé de passada, que kind fa servir kubeadm per dins: aquell camp kubeadmConfigPatches del fitxer de configuració no era casualitat. Ara anem a l'eina directament.
kubeadm és l'eina oficial del projecte Kubernetes per arrencar un clúster conforme sobre màquines que tu controles. És la base sobre la qual estan construïdes gairebé totes les distribucions, i entendre-la et dona una cosa que cap altra via et dona: veure amb els teus propis ulls on són els certificats, on viuen els pods estàtics del pla de control i què passa exactament quan un node s'uneix al clúster. Encara que Rutas Norte S.L. acabi triant un clúster gestionat (10-06), aquest coneixement és el que et permetrà depurar un pla de control trencat i aprovar la certificació CKA (12-01).
Contingut
- Què és kubeadm i què no és
- Autogestionat davant de gestionat: quan té sentit
- Preparació de les màquines
- Instal·lació de containerd
- Instal·lació de kubeadm, kubelet i kubectl
kubeadm initamb fitxer de configuració- Què crea exactament kubeadm al node
- Instal·lar el CNI i per què els nodes estan NotReady
- Unir nodes de treball
- Pla de control en alta disponibilitat
- Gestió de certificats
- Actualització de versió
- Còpia de seguretat i restauració d'etcd
kubeadm reseti neteja- Errors comuns i consells
- Exercicis
- Conclusió
- Què és kubeadm i què no és
kubeadm fa una sola cosa bé: donades unes màquines ja preparades, hi arrenca un pla de control i uneix nodes de treball, produint un clúster que passa les proves de conformitat de Kubernetes.
| kubeadm SÍ que fa | kubeadm NO fa |
|---|---|
| Generar tota la jerarquia de certificats (CA, apiserver, etcd, kubelet) | Aprovisionar màquines virtuals o físiques |
| Escriure els manifestos dels pods estàtics del pla de control | Instal·lar el runtime de contenidors |
| Arrencar etcd (apilat) o connectar-se a un d'extern | Instal·lar el complement de xarxa (CNI) |
| Configurar el kubelet i generar els seus kubeconfig | Configurar el sistema operatiu (swap, sysctl, tallafocs) |
| Emetre tokens d'unió i unir nodes | Instal·lar Ingress, monitoratge, emmagatzematge |
| Actualitzar el pla de control de versió | Gestionar còpies de seguretat d'etcd |
| Renovar certificats | Oferir alta disponibilitat del balancejador de l'API |
Aquesta llista de la dreta és la clau. Molta gent executa kubeadm init, veu el missatge d'èxit, i després se sorprèn que kubectl get nodes digui NotReady. No hi ha cap error: falta el CNI, i aquesta feina no és de kubeadm.
flowchart TB
subgraph teva["Responsabilitat teva"]
A[Màquines i xarxa]
B[Sistema operatiu:<br/>swap, sysctl, tallafocs]
C[containerd]
E[CNI: Calico, Cilium...]
F[Complements: Ingress,<br/>emmagatzematge, monitoratge]
G[Còpies d'etcd, pedaços,<br/>rotació de nodes]
end
subgraph kubeadm["Responsabilitat de kubeadm"]
D[Certificats, pla de control,<br/>tokens, unió de nodes,<br/>actualitzacions]
end
A --> B --> C --> D --> E --> F --> G
style kubeadm fill:#e8f4ff
style teva fill:#fff4e8
- Autogestionat davant de gestionat: quan té sentit
Abans d'escriure una sola ordre, la pregunta honesta: hauria Rutas Norte S.L. d'operar el seu propi clúster?
| Criteri | kubeadm (autogestionat) | Gestionat (10-06) |
|---|---|---|
| Cost del pla de control | Les teves màquines (3 nodes de control mínim per a HA) | 0-75 €/mes per clúster, segons proveïdor |
| Qui arregla un etcd corrupte a les 3 de la matinada | El teu equip | El proveïdor |
| Actualitzacions de versió | Manuals, node a node, amb finestra de manteniment | Un botó, tot i que continua exigint planificació |
| Control sobre banderes de l'apiserver | Total | Limitat |
| Executar en màquines pròpies o en un centre de dades privat | Sí | No (llevat de variants híbrides) |
| Requisits normatius de sobirania de la dada | Complibles | Depèn del proveïdor i la regió |
| Personal necessari | Almenys 2 persones amb coneixement profund i guàrdia | Una persona a temps parcial |
| Temps fins al primer clúster productiu | Setmanes | Hores |
Advertiment seriós: operar un clúster propi en producció exigeix un equip dedicat. No és una tasca que es pugui afegir a la llista d'un altre lloc de treball. Necessites cobertura per a incidents fora d'horari, un procediment provat de restauració d'etcd, una política de pedaços del sistema operatiu, i algú que entengui els certificats quan caduquin. Si la teva organització no pot sostenir això, un clúster gestionat no és una comoditat: és una decisió de gestió de risc.
Quan kubeadm sí que és la resposta correcta: centre de dades propi o maquinari específic (GPU, baixa latència, compliment normatiu); necessitat de configuracions del pla de control que cap gestionat permet; estalvi de cost amb molts nodes; i aprenentatge i certificació, perquè el CKA (12-01) avalua exactament això.
Per a Rutas Norte muntarem un clúster amb kubeadm en un laboratori per aprendre i practicar, amb la conclusió raonada de producció reservada per a 10-06.
- Preparació de les màquines
Partim de tres màquines Ubuntu 24.04 LTS al laboratori de Rutas Norte:
| Nom | Funció | vCPU | RAM | IP |
|---|---|---|---|---|
rn-control-1 |
Pla de control | 2 | 4 GB | 10.10.0.11 |
rn-worker-1 |
Node de treball | 2 | 4 GB | 10.10.0.21 |
rn-worker-2 |
Node de treball | 2 | 4 GB | 10.10.0.22 |
Requisits mínims oficials: 2 CPU i 2 GB de RAM per node de control, nom de host únic, adreça MAC única i product_uuid únic (sudo cat /sys/class/dmi/id/product_uuid). Si dues màquines clonades comparteixen product_uuid, el clúster pot confondre-les: regenera'l des de l'hipervisor.
3.1 Desactivar el swap
Tots els passos següents s'executen a les tres màquines.
sudo swapoff -a # ara
sudo sed -i '/ swap / s/^/#/' /etc/fstab # i de forma permanent
free -h # comprovar que Swap està a 0Per què cal desactivar el swap? Perquè trenca el model de recursos que vam estudiar a 03-04 i 03-05. El planificador decideix on va un pod segons la memòria sol·licitada i disponible; el kubelet expulsa pods quan el node té pressió de memòria, seguint les classes de QoS. Si hi ha swap, un pod que supera el seu límit de memòria no mor: comença a paginar a disc, es torna mil vegades més lent, les seves sondes de liveness comencen a fallar de forma erràtica i el node sencer es degrada sense que cap mètrica ho expliqui. És una fallada molt pitjor que un OOMKilled net.
Kubernetes 1.30 té suport experimental de swap (NodeSwap), però està en beta amb molts advertiments. Per a un clúster de producció, swap desactivat.
3.2 Mòduls del kernel
# Declarar els mòduls que han de carregar-se a cada arrencada
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
# Carregar-los ara sense reiniciar
sudo modprobe overlay
sudo modprobe br_netfilter
# Verificar
lsmod | grep -E 'overlay|br_netfilter'Què fa cadascun:
overlay: el sistema de fitxers per capes que fa servir containerd per muntar les imatges de contenidor. Sense ell, el runtime no pot crear contenidors.br_netfilter: permet que el trànsit que travessa un pont de xarxa de Linux (el que connecta els contenidors del node) sigui visible per aiptables. Sense ell, kube-proxy escriu regles que mai s'apliquen al trànsit entre pods, i els Services simplement no funcionen.
3.3 Paràmetres sysctl
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sudo sysctl --system # aplicar
sysctl net.ipv4.ip_forward net.bridge.bridge-nf-call-iptables # verificarip_forward = 1: el node ha de reenviar paquets entre interfícies. Sense això, un pod dern-worker-1no pot parlar amb un dern-worker-2.bridge-nf-call-iptables = 1: activa el quebr_netfilterfa possible.
Si sysctl et diu que el paràmetre no existeix, és que br_netfilter no està carregat. L'ordre importa.
3.4 Tallafocs i ports
| Node | Port/rang | Protocol | Component | Qui hi accedeix |
|---|---|---|---|---|
| Control | 6443 | TCP | kube-apiserver | Tots els nodes, kubectl, balancejador |
| Control | 2379-2380 | TCP | etcd (client i parell) | Només nodes de control |
| Control | 10250 | TCP | kubelet API | Pla de control (logs, exec) |
| Control | 10257 | TCP | kube-controller-manager | Local |
| Control | 10259 | TCP | kube-scheduler | Local |
| Treball | 10250 | TCP | kubelet API | Pla de control |
| Treball | 10256 | TCP | kube-proxy (health) | Balancejadors |
| Tots dos | 30000-32767 | TCP | Rang de NodePort | Segons necessitat |
| Tots dos | Segons CNI | UDP/TCP | Xarxa de pods | Tots els nodes |
Sobre l'últim: cada CNI fa servir el seu. Calico amb VXLAN necessita UDP 4789; amb IP-in-IP necessita el protocol IP 4; Cilium amb VXLAN, UDP 8472. Consulta la documentació del CNI que triïs.
Per al laboratori n'hi ha prou amb obrir aquests ports amb ufw i permetre tot el trànsit de la xarxa interna: sudo ufw allow from 10.10.0.0/24. Verifica des d'un altre node amb nc -zv 10.10.0.11 6443.
Consell de laboratori: si estàs aprenent i alguna cosa no connecta, desactiva temporalment el tallafocs (sudo ufw disable) per descartar que sigui el culpable. En producció, mai; allà es documenta cada regla.
- Instal·lació de containerd
Kubernetes no executa contenidors directament: parla amb un runtime a través de la interfície CRI. Des de 1.24, Docker no és un runtime vàlid de forma directa; containerd és l'opció estàndard.
# 1. Repositori de Docker (containerd es distribueix des d'allà)
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 2. Instal·lar NOMÉS containerd (no el motor de Docker)
sudo apt-get update && sudo apt-get install -y containerd.io4.1 SystemdCgroup: l'error més habitual
Aquí hi ha la fallada número u dels clústers amb kubeadm. containerd porta per defecte una configuració amb SystemdCgroup = false, mentre que el kubelet de Kubernetes 1.30 fa servir el controlador de cgroups systemd. Si no coincideixen, el clúster arrenca aparentment bé i després els pods es reinicien de forma aleatòria sota pressió de memòria, perquè hi ha dos gestors de cgroups barallant-se pel mateix node.
# 1. Generar la configuració per defecte (containerd ve sense config.toml complet)
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml > /dev/null
# 2. Canviar SystemdCgroup de false a true
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
# 3. VERIFICAR que el canvi s'ha aplicat (no te'n fiïs) i reiniciar
grep SystemdCgroup /etc/containerd/config.toml # ha de dir: SystemdCgroup = true
sudo systemctl restart containerd && sudo systemctl enable containerdSi el grep no retorna res o retorna false, la ruta de l'opció ha canviat a la teva versió. Edita el fitxer a mà i busca la secció [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options].
4.2 Comprovar que containerd respon a CRI
sudo apt-get install -y cri-tools
printf 'runtime-endpoint: unix:///run/containerd/containerd.sock\n' | sudo tee /etc/crictl.yaml
sudo crictl info | head -20Si això respon, el runtime està llest. crictl és la teva eina de depuració a nivell de node: crictl ps, crictl images, crictl logs. Quan l'apiserver està caigut, kubectl no serveix de res i crictl és l'únic que tens.
- Instal·lació de kubeadm, kubelet i kubectl
Tots tres s'instal·len des del repositori oficial de Kubernetes, que des de 1.28 està segmentat per versió menor. Això és important: el repositori de v1.30 només conté pedaços de 1.30, cosa que evita salts accidentals de versió menor.
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | \
sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] \
https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | \
sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
# Instal·lar una versió de pedaç CONCRETA, no l'última
sudo apt-get install -y kubelet=1.30.4-1.1 kubeadm=1.30.4-1.1 kubectl=1.30.4-1.15.1 Fixar les versions amb apt-mark hold
sudo apt-mark hold kubelet kubeadm kubectl
apt-mark showhold # comprovar
# Habilitar el kubelet (encara fallarà i reintentarà: és normal, no hi ha
# configuració fins que s'executi kubeadm init o join)
sudo systemctl enable --now kubeletPer què el hold és imprescindible: sense ell, un apt upgrade rutinari de manteniment del sistema actualitzaria el kubelet en un node qualsevol. Aquell kubelet nou podria ser incompatible amb el pla de control, o simplement reiniciar-se enmig del dia i expulsar tots els pods d'aquell node. Les actualitzacions de Kubernetes són un procediment planificat (apartat 12), mai un efecte secundari.
kubeadm init amb fitxer de configuració
kubeadm init amb fitxer de configuracióPodries arrencar el clúster amb una tirallonga de banderes (kubeadm init --pod-network-cidr=... --control-plane-endpoint=... --apiserver-cert-extra-sans=...), i funcionaria. Però el problema és evident després de tot el que portem de curs: no està versionat, ningú recorda quines banderes es van fer servir fa un any, i en afegir un node de control cal repetir-les exactament. La forma professional és un fitxer de configuració, desat al costat dels manifestos.
# kubeadm/rn-cluster.yaml
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint: # com anuncia AQUEST node l'apiserver
advertiseAddress: "10.10.0.11"
bindPort: 6443
nodeRegistration:
name: "rn-control-1"
criSocket: "unix:///run/containerd/containerd.sock"
taints: # taint estàndard del pla de control (06-05)
- { key: "node-role.kubernetes.io/control-plane", effect: "NoSchedule" }
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: "v1.30.4"
clusterName: "rutas-norte-lab"
# Punt d'entrada ESTABLE. Es declara des del primer moment encara que
# avui només hi hagi un node: canviar-lo després obliga a regenerar certificats.
controlPlaneEndpoint: "api-k8s.rutasnorte.example:6443"
networking:
# HA DE coincidir amb el que configuris a Calico/Cilium, i NO pot
# solapar-se amb la xarxa física (10.10.0.0/24) ni amb serviceSubnet.
podSubnet: "10.244.0.0/16"
serviceSubnet: "10.96.0.0/12"
dnsDomain: "cluster.local"
apiServer:
# Noms i IP vàlids del certificat de l'apiserver. Accedir per un
# nom no llistat dona "certificate is valid for ..., not ...".
certSANs: ["api-k8s.rutasnorte.example", "10.10.0.10", "10.10.0.11",
"localhost", "127.0.0.1"]
extraArgs: # registre d'auditoria (08-06)
audit-log-path: "/var/log/kubernetes/audit.log"
audit-log-maxage: "30"
etcd:
local: { dataDir: "/var/lib/etcd" } # etcd apilat, pod estàtic aquí
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: "systemd" # HA DE coincidir amb SystemdCgroup=true
# Recursos reservats al sistema i al kubelet, que NO s'ofereixen al
# planificador. Sense això, un node saturat es queda sense memòria per a sshd.
systemReserved: { cpu: "200m", memory: "256Mi" }
kubeReserved: { cpu: "200m", memory: "256Mi" }
evictionHard: { memory.available: "200Mi", nodefs.available: "10%" }
serverTLSBootstrap: trueExecutem:
# Primer, descarregar les imatges per endavant (evita timeouts
# durant l'init si la xarxa és lenta)
sudo kubeadm config images pull --config kubeadm/rn-cluster.yaml
# Arrencar
sudo kubeadm init --config kubeadm/rn-cluster.yaml --upload-certs--upload-certs puja els certificats del pla de control a un Secret temporal del clúster, xifrat, perquè altres nodes de control s'hi puguin unir sense copiar-los a mà. Caduca a les 2 hores.
Sortida (molt abreujada):
[certs] Generating "ca" certificate and key
[certs] apiserver serving cert is signed for DNS names [api-k8s.rutasnorte.example
kubernetes kubernetes.default rn-control-1] and IPs [10.96.0.1 10.10.0.11 10.10.0.10]
[control-plane] Creating static Pod manifest for "kube-apiserver"
[etcd] Creating static Pod manifest for local etcd
[apiclient] All control plane components are healthy after 12.503 seconds
Your Kubernetes control-plane has initialized successfully!
You should now deploy a pod network to the cluster.
You can now join any number of control-plane nodes:
kubeadm join api-k8s.rutasnorte.example:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:1a2b3c... \
--control-plane --certificate-key 8f3c1a...
Then you can join any number of worker nodes:
kubeadm join api-k8s.rutasnorte.example:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:1a2b3c...Desa aquesta sortida. Les dues ordres join del final són les que necessites als apartats 9 i 10.
# Configurar kubectl per al teu usuari
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
kubectl get nodesNotReady. És correcte, i ho expliquem a l'apartat 8.
6.1 Camps que més importen
| Camp | Què fa | Què passa si el poses malament |
|---|---|---|
podSubnet |
Rang d'IP dels pods | Si se solapa amb la xarxa física o amb serviceSubnet, l'encaminament es trenca de formes molt difícils de depurar |
serviceSubnet |
Rang de les IP virtuals dels Services | Igual; a més la IP .1 d'aquest rang és la del Service kubernetes |
controlPlaneEndpoint |
Nom estable del pla de control | Sense ell, no pots afegir nodes de control després sense regenerar certificats |
certSANs |
Noms vàlids del certificat de l'apiserver | Accedir per un nom no llistat dona error de certificat |
kubernetesVersion |
Versió a instal·lar | Si no coincideix amb els binaris instal·lats, init avisa |
cgroupDriver |
Gestor de cgroups del kubelet | Si no coincideix amb containerd, pods inestables sota pressió |
criSocket |
Socket del runtime | Amb diversos runtimes instal·lats, kubeadm no sap quin fer servir |
Sobre controlPlaneEndpoint: encara que avui només tinguis un node de control i no un balancejador, declara'l amb un nom DNS des del principi. Pots fer que aquest nom apunti avui a 10.10.0.11 i demà a la IP virtual del balancejador. Si no ho fas, el certificat i tots els kubeconfig apuntaran a la IP del node, i muntar HA més tard exigeix regenerar certificats a tot el clúster.
- Què crea exactament kubeadm al node
Aquest apartat connecta directament amb l'arquitectura que vam veure a 01-02. Ara la veurem al disc.
7.1 Pods estàtics del pla de control
-rw------- 1 root root 2405 Sep 12 10:02 etcd.yaml
-rw------- 1 root root 3891 Sep 12 10:02 kube-apiserver.yaml
-rw------- 1 root root 3320 Sep 12 10:02 kube-controller-manager.yaml
-rw------- 1 root root 1463 Sep 12 10:02 kube-scheduler.yamlAixò és un pod estàtic: el kubelet vigila aquest directori i arrenca qualsevol pod que hi trobi, sense passar per l'apiserver. És la solució al problema de l'ou i la gallina: com arrenca l'apiserver, si per crear un pod cal un apiserver? Resposta: no es crea com un pod normal, el llegeix el kubelet directament del disc.
Conseqüències pràctiques molt importants:
- Si edites
/etc/kubernetes/manifests/kube-apiserver.yaml, el kubelet detecta el canvi i reinicia l'apiserver automàticament en segons. És la manera d'afegir una bandera a mà. - Si esborres aquest fitxer, l'apiserver desapareix i perds el clúster. Còpia de seguretat abans de tocar res.
kubectl delete pod kube-apiserver-rn-control-1 -n kube-systemno l'elimina de debò: el kubelet el recrea, perquè la font de veritat és el fitxer.- Si l'apiserver no arrenca,
kubectlno funciona. Depura'l ambcrictl ps -aicrictl logs, o ambjournalctl -u kubelet.
# Els pods estàtics apareixen com a objectes "mirall" a l'API,
# amb el nom del node com a sufix: aquesta és la seva marca distintiva.
kubectl get pods -n kube-system -l tier=control-planeetcd-rn-control-1 1/1 Running 0 3m
kube-apiserver-rn-control-1 1/1 Running 0 3m
kube-controller-manager-rn-control-1 1/1 Running 0 3m
kube-scheduler-rn-control-1 1/1 Running 0 3m7.2 Certificats
apiserver.crt apiserver.key apiserver-etcd-client.crt apiserver-etcd-client.key
apiserver-kubelet-client.crt apiserver-kubelet-client.key ca.crt ca.key etcd/
front-proxy-ca.crt front-proxy-ca.key front-proxy-client.crt front-proxy-client.key
sa.key sa.pub| Fitxer | Funció |
|---|---|
ca.crt / ca.key |
Autoritat certificadora arrel del clúster. És el secret més valuós: qui la té pot emetre credencials d'administrador |
apiserver.crt |
Certificat de servidor de l'apiserver, amb els certSANs |
apiserver-kubelet-client.* |
Amb què s'identifica l'apiserver en parlar amb els kubelets (kubectl logs, exec) |
apiserver-etcd-client.* |
Amb què s'identifica l'apiserver davant d'etcd |
etcd/ |
CA i certificats propis d'etcd (servidor, parell, sanitat) |
front-proxy-* |
Per a l'agregador d'API (mètriques personalitzades de 09-01) |
sa.key / sa.pub |
Parell de claus amb què se signen els tokens de les ServiceAccounts (03-06) |
Per inspeccionar els noms vàlids d'un certificat: sudo openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -text | grep -A2 'Subject Alternative Name'.
7.3 Fitxers kubeconfig
A /etc/kubernetes/*.conf n'hi ha un per component: controller-manager.conf, scheduler.conf, kubelet.conf (credencials d'aquest node, amb rotació automàtica) i dos d'administració:
admin.conf: el que vas copiar a~/.kube/config. Des de 1.29 pertany al grupkubeadm:cluster-admins, subjecte a RBAC (08-01).super-admin.conf: salta el RBAC completament (system:masters). És el trenca-vidres quan has trencat el RBAC i no el pots ni arreglar. No el reparteixis.
7.4 Dades d'etcd
A /var/lib/etcd/member/ (amb els seus directoris snap i wal) viu l'estat complet del teu clúster: tots els objectes, tots els Secrets, tot. És el que cal copiar (apartat 13).
- Instal·lar el CNI i per què els nodes estan NotReady
Type Status Reason Message
Ready False KubeletNotReady container runtime network not
ready: NetworkReady=false
reason:NetworkPluginNotReady
message:Network plugin returns
error: cni plugin not initializedEl missatge és explícit. El kubelet es nega a declarar-se Ready mentre no existeixi un complement de xarxa que sàpiga assignar IP als pods. Recorda de 04-01: Kubernetes defineix el contracte (tot pod té una IP, tots els pods es veuen sense NAT) però no l'implementa. Això és feina del CNI.
També veuràs CoreDNS a Pending, i és normal: CoreDNS és un pod i necessita xarxa per arrencar.
Instal·lem Calico (el detall dels CNI és a 04-01; aquí només el necessari):
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.1/manifests/tigera-operator.yaml
cat <<EOF | kubectl apply -f -
apiVersion: operator.tigera.io/v1
kind: Installation
metadata: { name: default }
spec:
calicoNetwork:
ipPools:
# HA DE coincidir amb networking.podSubnet del fitxer de kubeadm
- { cidr: 10.244.0.0/16, encapsulation: VXLANCrossSubnet, natOutgoing: Enabled }
EOF
kubectl get nodes -w # NotReady -> Ready en menys d'un minutI CoreDNS arrenca sol. La seqüència completa és:
sequenceDiagram
participant K as kubeadm init
participant Kl as kubelet
participant A as apiserver
participant C as CNI (Calico)
K->>Kl: escriu pods estàtics + config
Kl->>A: arrenca apiserver, etcd, scheduler, cm
Kl->>A: registra el node (NotReady: sense xarxa)
Note over A: CoreDNS queda Pending
K-->>C: (tu apliques els manifestos del CNI)
C->>Kl: instal·la el binari CNI a /opt/cni/bin
Kl->>A: NetworkReady=true → node Ready
A->>A: CoreDNS es planifica i arrenca
- Unir nodes de treball
A rn-worker-1 i rn-worker-2, ja preparats amb els apartats 3, 4 i 5:
sudo kubeadm join api-k8s.rutasnorte.example:6443 \
--token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:1a2b3c4d5e6f...[preflight] Running pre-flight checks
[preflight] Reading configuration from the cluster...
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...
This node has joined the cluster.Què signifiquen els dos paràmetres:
--token: una credencial temporal (caduca a les 24 hores) que autoritza el node a demanar el seu certificat. És un Secret de tipusbootstrap.kubernetes.io/tokenakube-system.--discovery-token-ca-cert-hash: el hash SHA-256 de la clau pública de la CA del clúster. Serveix perquè el node verifiqui l'apiserver, no a l'inrevés. Sense ell, un atacant podria suplantar el pla de control i capturar el token. No facis servir mai--discovery-token-unsafe-skip-ca-verificationfora d'un laboratori.
9.1 Generar un token nou quan caduca
És la situació més habitual: vols afegir un node tres setmanes després i el token original ja no val.
# En un node de control: una sola ordre que imprimeix tot el necessari
sudo kubeadm token create --print-join-commandkubeadm join api-k8s.rutasnorte.example:6443 --token 7t8u9i.qwertyuiopasdfgh \
--discovery-token-ca-cert-hash sha256:1a2b3c4d5e6f...Ordres relacionades:
sudo kubeadm token list # tokens vius i caducitat
sudo kubeadm token create --ttl 2h --print-join-command
sudo kubeadm token delete 7t8u9i.qwertyuiopasdfgh
# Recalcular el hash de la CA a mà, si has perdut la sortida de l'init
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | \
openssl rsa -pubin -outform der 2>/dev/null | \
openssl dgst -sha256 -hex | sed 's/^.* //'9.2 Etiquetar els nodes
kubeadm no posa l'etiqueta de rol als nodes de treball per seguretat (un kubelet no pot autoassignar-se etiquetes de rol). Es fa des del pla de control:
kubectl label node rn-worker-1 node-role.kubernetes.io/worker=
kubectl label node rn-worker-2 node-role.kubernetes.io/worker=
# I les etiquetes de topologia de Rutas Norte (09-05)
kubectl label node rn-worker-1 topology.kubernetes.io/zone=lab-a
kubectl label node rn-worker-2 topology.kubernetes.io/zone=lab-b
kubectl get nodes # els tres Ready, amb els seus rols
- Pla de control en alta disponibilitat
Amb un sol node de control, si rn-control-1 cau, el clúster continua servint trànsit (els pods continuen corrent, kube-proxy continua encaminant) però perds tota capacitat de gestió: no hi ha reprogramació de pods, ni escalat, ni desplegaments, ni HPA. I si el disc d'etcd es perd, perds el clúster sencer.
10.1 El punt d'entrada estable
Tots els nodes de control publiquen el mateix port 6443. Necessites alguna cosa al davant que reparteixi:
flowchart TB
K[kubectl / kubelets<br/>dels nodes] --> LB["api-k8s.rutasnorte.example:6443<br/>(IP virtual 10.10.0.10)"]
LB --> C1[rn-control-1<br/>:6443]
LB --> C2[rn-control-2<br/>:6443]
LB --> C3[rn-control-3<br/>:6443]
C1 -.-> E[(etcd apilat<br/>quòrum de 3)]
C2 -.-> E
C3 -.-> E
Opcions: HAProxy + keepalived amb una IP virtual flotant (el més comú en centre de dades propi), el balancejador de capa 4 del núvol si estàs en màquines virtuals, o kube-vip com a pod estàtic si no vols infraestructura externa. El que no val és un DNS amb diversos registres A: el client fa memòria cau i no detecta caigudes.
Configuració mínima d'HAProxy:
# /etc/haproxy/haproxy.cfg
frontend k8s-api
bind *:6443
mode tcp
default_backend k8s-control-plane
backend k8s-control-plane
mode tcp
option tcp-check
balance roundrobin
server rn-control-1 10.10.0.11:6443 check fall 3 rise 2
server rn-control-2 10.10.0.12:6443 check fall 3 rise 2
server rn-control-3 10.10.0.13:6443 check fall 3 rise 2És TCP pur (mode tcp), no HTTP: la connexió a l'apiserver és TLS d'extrem a extrem i el balancejador no l'ha de terminar. Amb check, si un node deixa de respondre al 6443, HAProxy deixa d'enviar-li trànsit automàticament.
10.2 etcd apilat davant d'etcd extern
| Aspecte | etcd apilat | etcd extern |
|---|---|---|
| On corre | Com a pod estàtic a cada node de control | En màquines dedicades |
| Màquines necessàries | 3 (control + etcd junts) | 3 de control + 3 d'etcd = 6 |
| Configuració | Automàtica amb kubeadm | Manual: certificats, unitats systemd |
| Aïllament de fallades | Perdre un node perd un control i un membre d'etcd | Independents |
| Rendiment sota càrrega | etcd competeix amb l'apiserver per E/S i CPU | etcd té el seu disc per a ell |
| Recomanació | Per defecte, per a la majoria | Clústers molt grans o amb requisits estrictes |
etcd necessita quòrum: 1 membre tolera 0 fallades, 2 membres també en toleren 0 (pitjor que 1!), 3 en toleren 1, 4 en toleren 1, i 5 en toleren 2. Per això el nombre de nodes de control és sempre senar: 1 (laboratori), 3 (producció normal) o 5 (clústers grans).
Per a etcd extern, es declara al fitxer de kubeadm:
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
etcd:
external:
endpoints:
- https://10.10.0.31:2379
- https://10.10.0.32:2379
- https://10.10.0.33:2379
caFile: /etc/kubernetes/pki/etcd/ca.crt
certFile: /etc/kubernetes/pki/apiserver-etcd-client.crt
keyFile: /etc/kubernetes/pki/apiserver-etcd-client.key10.3 Unir nodes de control addicionals
# A rn-control-2 i rn-control-3 (ja preparats amb 3, 4 i 5)
sudo kubeadm join api-k8s.rutasnorte.example:6443 \
--token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:1a2b3c... \
--control-plane \
--certificate-key 8f3c1a...La --certificate-key ve de --upload-certs. Si han passat més de 2 hores, es regenera:
[upload-certs] Using certificate key:
f0e1d2c3b4a5968778695a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4dPer verificar la salut del clúster d'etcd, kubectl -n kube-system exec etcd-rn-control-1 -- etcdctl ... endpoint status --cluster -w table ha de mostrar els tres membres, amb la mateixa versió, mida de base de dades semblant i exactament un amb IS LEADER = true.
- Gestió de certificats
Aquí hi ha el parany que sorprèn més equips: els certificats que genera kubeadm caduquen a l'any. Un clúster muntat al març deixa de funcionar al març de l'any següent, sense previ avís, amb un missatge així:
Kubernetes renova automàticament els certificats durant kubeadm upgrade. Com que molts equips actualitzen almenys un cop l'any, mai ho veuen. Qui no actualitza, s'emporta el sobresalt.
11.1 Comprovar la caducitat
CERTIFICATE EXPIRES RESIDUAL TIME
admin.conf Sep 12, 2026 10:02 UTC 364d
apiserver Sep 12, 2026 10:02 UTC 364d
apiserver-etcd-client Sep 12, 2026 10:02 UTC 364d
apiserver-kubelet-client Sep 12, 2026 10:02 UTC 364d
etcd-server, etcd-peer, scheduler.conf, controller-manager.conf ... 364d
CERTIFICATE AUTHORITY EXPIRES RESIDUAL TIME
ca, etcd-ca, front-proxy-ca Sep 10, 2035 10:02 UTC 9yLes CA duren 10 anys; els certificats que signen, 1 any.
Recomanació d'operació: no ho deixis al calendari humà. L'apiserver exposa apiserver_client_certificate_expiration_seconds_bucket, sobre la qual es pot muntar una alerta a Alertmanager (07-04). Més simple i més fiable encara: un CronJob (06-03) o una tasca del sistema que executi kubeadm certs check-expiration setmanalment i avisi si queda menys d'un mes.
11.2 Renovar
# A CADA NODE DE CONTROL
sudo cp -r /etc/kubernetes/pki /root/pki-copia-$(date +%F) # còpia primer
sudo kubeadm certs renew all # o només un: kubeadm certs renew apiserver
# Reiniciar els pods estàtics: n'hi ha prou amb treure'ls i tornar-los
sudo mkdir -p /tmp/manifests-aturats
sudo mv /etc/kubernetes/manifests/*.yaml /tmp/manifests-aturats/
sleep 20
sudo mv /tmp/manifests-aturats/*.yaml /etc/kubernetes/manifests/
# Actualitzar el teu kubeconfig personal, que també s'ha renovat
sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
sudo kubeadm certs check-expiration && kubectl get nodesNota sobre el kubelet: el seu certificat es rota sol, automàticament, si rotateCertificates: true (per defecte). Els certificats que cal renovar a mà són els del pla de control.
- Actualització de versió
12.1 La regla del salt d'una versió menor
Només pots saltar una versió menor cada vegada. De 1.28 a 1.30 no es pot anar directe: cal fer 1.28 → 1.29 → 1.30. Cada salt és un procediment complet.
A més, la política de desfasament (version skew) exigeix:
| Component | Desfasament permès respecte a l'apiserver |
|---|---|
| kube-controller-manager, kube-scheduler | Fins a 1 menor per sota |
| kubelet | Fins a 3 menors per sota |
| kube-proxy | Fins a 3 menors per sota |
| kubectl | 1 per sobre o 1 per sota |
D'aquí l'ordre obligatori: primer el pla de control, després els nodes de treball. Mai a l'inrevés.
12.2 Abans de començar
Tres coses, per aquest ordre: còpia de seguretat d'etcd (apartat 13, no negociable), llegir les notes de la versió, i comprovar que res faci servir APIs que desapareixen.
apiserver_requested_deprecated_apis{group="flowcontrol.apiserver.k8s.io",
removed_release="1.32",resource="flowschemas",version="v1beta3"} 1Qualsevol línia aquí és feina que cal fer abans d'actualitzar. Eines com kubent (kube-no-trouble) o pluto escanegen els teus manifestos buscant el mateix.
12.3 Primer node de control
# --- A rn-control-1 ---
# 1. Alliberar el hold i actualitzar NOMÉS kubeadm
sudo apt-mark unhold kubeadm
sudo apt-get update
# Canviar el repositori a la nova versió menor
sudo sed -i 's|v1.30|v1.31|' /etc/apt/sources.list.d/kubernetes.list
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.31/deb/Release.key | \
sudo gpg --dearmor --yes -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
sudo apt-get update
sudo apt-get install -y kubeadm=1.31.1-1.1
sudo apt-mark hold kubeadm
kubeadm versionCOMPONENT CURRENT TARGET
kube-apiserver v1.30.4 v1.31.1
kube-controller-manager v1.30.4 v1.31.1
kube-scheduler v1.30.4 v1.31.1
kube-proxy v1.30.4 v1.31.1
CoreDNS v1.11.1 v1.11.3
etcd 3.5.14 3.5.15
Components that must be upgraded manually: kubelet als 3 nodes.
You can now apply the upgrade by executing: kubeadm upgrade apply v1.31.1# 3. Aplicar. Actualitza els manifestos dels pods estàtics i
# RENOVA ELS CERTIFICATS de passada.
sudo kubeadm upgrade apply v1.31.1# 4. Drenar el node: moure els seus pods a un altre lloc i no acceptar-ne de nous.
# Respecta els PodDisruptionBudgets de 09-05.
kubectl drain rn-control-1 --ignore-daemonsets --delete-emptydir-data
# 5. Actualitzar kubelet i kubectl
sudo apt-mark unhold kubelet kubectl
sudo apt-get install -y kubelet=1.31.1-1.1 kubectl=1.31.1-1.1
sudo apt-mark hold kubelet kubectl
sudo systemctl daemon-reload
sudo systemctl restart kubelet
# 6. Tornar el node al servei
kubectl uncordon rn-control-1
kubectl get nodesNAME STATUS ROLES AGE VERSION
rn-control-1 Ready control-plane 3d v1.31.1
rn-worker-1 Ready worker 3d v1.30.4
rn-worker-2 Ready worker 3d v1.30.412.4 Resta de nodes, un a un
Per als altres nodes de control i per als de treball, el procediment és el mateix de l'apartat anterior amb una sola diferència: es fa servir sudo kubeadm upgrade node en comptes d'upgrade apply.
# A cada node restant, d'un en un:
sudo apt-mark unhold kubeadm && sudo apt-get install -y kubeadm=1.31.1-1.1 && sudo apt-mark hold kubeadm
sudo kubeadm upgrade node # <-- la diferència
kubectl drain <node> --ignore-daemonsets --delete-emptydir-data --timeout=300s
sudo apt-mark unhold kubelet kubectl
sudo apt-get install -y kubelet=1.31.1-1.1 kubectl=1.31.1-1.1
sudo apt-mark hold kubelet kubectl
sudo systemctl daemon-reload && sudo systemctl restart kubelet
kubectl uncordon <node>
kubectl get nodes # confirmar Ready i v1.31.1 ABANS de passar al següentUn a un, verificant pel mig. Si drain es bloqueja, és un PodDisruptionBudget fent la seva feina: postgres-reserves no es pot quedar sense rèpliques. Investiga amb kubectl get pdb -A abans de forçar res.
- Còpia de seguretat i restauració d'etcd
A 05-06 vam fer còpies de les dades de les aplicacions amb Velero. Això és una altra cosa: és la còpia de la definició del clúster. Tots els Deployments, Secrets, ConfigMaps, RBAC, CRDs... tot viu a etcd.
Sense còpia d'etcd, una fallada del disc del node de control t'obliga a recrear el clúster des de zero i tornar a aplicar tots els manifestos. Amb GitOps (10-05) això seria recuperable, però perdries tot el que no sigui a Git.
13.1 Fer la còpia
sudo apt-get install -y etcd-client
# En un node de control
sudo ETCDCTL_API=3 etcdctl snapshot save /var/copies/etcd-$(date +%F-%H%M).db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
# Verificar (una còpia no verificada no és una còpia!)
sudo etcdutl --write-out=table snapshot status /var/copies/etcd-2026-09-12-1042.db+----------+----------+------------+------------+
| HASH | REVISION | TOTAL KEYS | TOTAL SIZE |
+----------+----------+------------+------------+
| 4f2a91bc | 184920 | 1847 | 28 MB |
+----------+----------+------------+------------+Aquesta mateixa ordre a /etc/cron.d/copia-etcd, a les 03:15 diàries i encadenada amb un find /var/copies -name 'etcd-*.db' -mtime +14 -delete, cobreix l'automatització amb retenció de dues setmanes.
Tres coses imprescindibles: copia també /etc/kubernetes/pki/ (el snapshot sense la CA és inútil), treu-les del node (una còpia al disc que s'espatllarà no és una còpia) i xifra-les, perquè contenen tots els Secrets de rutas-norte-pro, incloses les credencials de postgres-reserves i les de la passarel·la de pagaments: recorda de 03-02 que els Secrets estan en base64, no xifrats.
13.2 Restaurar
Procediment d'emergència, per quan el pla de control és irrecuperable:
# 1. Aturar el pla de control traient els pods estàtics
sudo mkdir -p /tmp/manifests-aturats
sudo mv /etc/kubernetes/manifests/*.yaml /tmp/manifests-aturats/
sudo crictl ps # esperar que no quedi res
# 2. Apartar les dades actuals (NO esborrar-les: per si de cas)
sudo mv /var/lib/etcd /var/lib/etcd-trencat-$(date +%F)
# 3. Restaurar el snapshot en un directori nou
sudo etcdutl snapshot restore /var/copies/etcd-2026-09-12-1042.db \
--data-dir=/var/lib/etcd --name=rn-control-1 \
--initial-cluster=rn-control-1=https://10.10.0.11:2380 \
--initial-advertise-peer-urls=https://10.10.0.11:2380
# 4. Tornar els pods estàtics i verificar
sudo mv /tmp/manifests-aturats/*.yaml /etc/kubernetes/manifests/
sleep 60 && kubectl get nodes && kubectl get pods -APunts crítics:
- En un clúster HA, cal restaurar als tres nodes de control, amb el snapshot idèntic i cadascun amb el seu
--namei les seves URL. Si les dades difereixen, etcd no formarà quòrum. - L'estat torna al moment de la còpia. Tot el creat després es perd.
- Els pods que estaven corrent continuen corrent (el kubelet no se n'ha assabentat), però poden aparèixer objectes "fantasma": pods que existeixen al node però no a etcd, o a l'inrevés. Després de restaurar, revisa
kubectl get pods -Acontracrictl psa cada node.
Assaja la restauració. Una còpia de seguretat que mai s'ha restaurat no és una còpia de seguretat: és un fitxer. Fes-ho al laboratori, cronometra't, i escriu el procediment en un runbook (11-06).
kubeadm reset i neteja
kubeadm reset i netejaQuan alguna cosa surt malament i vols tornar a començar, o retirar un node:
# 1. Des del pla de control: drenar i treure el node del clúster
kubectl drain rn-worker-2 --ignore-daemonsets --delete-emptydir-data
kubectl delete node rn-worker-2
# 2. Al mateix node: desfer el que va fer kubeadm
sudo kubeadm reset -f[reset] Deleting contents of directories: [/etc/kubernetes/manifests
/var/lib/kubelet /etc/kubernetes/pki]
The reset process does not clean CNI configuration. To do so, you must
remove /etc/cni/net.d
The reset process does not reset or clean up iptables rules.reset és honest sobre el que no neteja. Cal rematar-ho a mà:
sudo rm -rf /etc/cni/net.d /opt/cni/bin/calico* # configuració del CNI
sudo iptables -F && sudo iptables -t nat -F # regles de kube-proxy
sudo iptables -t mangle -F && sudo iptables -X
sudo ipvsadm -C 2>/dev/null || true # si feia servir mode IPVS
for i in cni0 flannel.1 vxlan.calico; do # interfícies virtuals
sudo ip link delete "$i" 2>/dev/null || true
done
rm -rf $HOME/.kubeSi et saltes els passos 3, 4 i 5, el següent kubeadm init o join en aquella màquina pot semblar que funciona i després donar fallades de xarxa inexplicables: regles velles d'iptables encaminant a IP de pods que ja no existeixen. És una de les causes més freqüents de «vaig reinstal·lar i continua fallant».
Errors Comuns i Consells
1. SystemdCgroup = false a containerd. És l'error número u. El clúster arrenca, tot sembla bé, i dies després els pods es reinicien sota pressió de memòria sense explicació. Verifica sempre amb grep SystemdCgroup /etc/containerd/config.toml i reinicia containerd després de canviar-ho.
2. Oblidar swapoff -a a /etc/fstab. El desactives, funciona, reinicies la màquina un mes després i el kubelet no arrenca. Comenta la línia a /etc/fstab sempre.
3. podSubnet que se solapa amb la xarxa física. Si el teu laboratori fa servir 10.10.0.0/24 i declares podSubnet: 10.0.0.0/8, l'encaminament es trenca de formes que semblen màgia negra. Tria rangs que no col·lisionin amb res: ni amb la xarxa de nodes, ni amb serviceSubnet, ni amb la xarxa corporativa.
4. El rang del CNI diferent de podSubnet. Declares 10.244.0.0/16 a kubeadm i instal·les Calico amb el seu valor per defecte 192.168.0.0/16. Els pods obtenen IP del rang del CNI, però el controller-manager assigna blocs de l'altre. Han de coincidir.
5. No declarar controlPlaneEndpoint des del principi. Afegir alta disponibilitat després obliga a regenerar certificats a tot el clúster. Declara un nom DNS des del primer dia, encara que apunti a una sola IP.
6. Certificats caducats a l'any. Real i molt comú. Alerta al calendari, o millor, al monitoratge.
7. Saltar dues versions menors, o actualitzar els nodes abans que el pla de control. kubeadm upgrade apply v1.32.0 des de 1.30 és rebutjat; i un kubelet 1.31 contra un apiserver 1.30 està fora de la política de desfasament. Una menor cada vegada, pla de control primer.
8. kubectl drain bloquejat i forçar-lo amb --force. El que et bloqueja sol ser un PDB (09-05) protegint postgres-reserves o redis-cache. Forçar-ho pot provocar pèrdua de dades. Investiga abans amb kubectl get pdb -A.
9. Còpies d'etcd sense /etc/kubernetes/pki. El snapshot sense la CA no et torna un clúster funcional. Copia tots dos, junts, xifrats i fora del node.
10. kubeadm reset sense netejar iptables i CNI. Restes que provoquen fallades de xarxa a la reinstal·lació. Executa la neteja completa de l'apartat 14.
11. No fixar apt-mark hold. Un apt upgrade rutinari que actualitzi el kubelet en producció és un incident esperant a passar.
Exercicis
Exercici 1: script de preparació de node
Escriu un script preparar-node.sh idempotent (que es pugui executar dues vegades sense trencar res) que deixi una màquina Ubuntu llesta per a kubeadm join: swap desactivat de forma permanent, mòduls i sysctl, containerd amb SystemdCgroup=true verificat, i kubeadm/kubelet/kubectl 1.30.4 fixats. L'script ha de fallar amb un missatge clar si alguna verificació no passa.
Exercici 2: fitxer de configuració per a HA
Escriu el fitxer de configuració de kubeadm per al clúster rutas-norte-lab amb aquests requisits: tres nodes de control darrere d'api-k8s.rutasnorte.example (IP virtual 10.10.0.10), podSubnet 172.16.0.0/16, etcd apilat, auditoria activada, i el kubelet reservant 500m de CPU i 512Mi de memòria per al sistema. Explica per què vas triar 172.16.0.0/16 i què comprovaries abans.
Exercici 3: pla d'actualització i recuperació
Redacta el procediment complet, en ordre i amb les ordres exactes, per actualitzar el clúster de 1.30.4 a 1.31.1 amb un node de control i dos de treball, incloent-hi la còpia de seguretat prèvia. Afegeix el criteri de "punt sense retorn" i què faries si l'apiserver no arrenca després d'upgrade apply.
Solucions
Solució 1
#!/usr/bin/env bash
# preparar-node.sh — idempotent
set -euo pipefail
VER="1.30.4-1.1"
sudo swapoff -a
sudo sed -i '/\sswap\s/ s/^\([^#]\)/#\1/' /etc/fstab # no recomenta el ja comentat
[[ $(swapon --show | wc -l) -eq 0 ]] || { echo "ERROR: swap actiu"; exit 1; }
printf 'overlay\nbr_netfilter\n' | sudo tee /etc/modules-load.d/k8s.conf >/dev/null
sudo modprobe overlay; sudo modprobe br_netfilter
printf 'net.bridge.bridge-nf-call-iptables=1\nnet.bridge.bridge-nf-call-ip6tables=1\nnet.ipv4.ip_forward=1\n' \
| sudo tee /etc/sysctl.d/k8s.conf >/dev/null
sudo sysctl --system >/dev/null
[[ $(sysctl -n net.ipv4.ip_forward) == 1 ]] || { echo "ERROR: ip_forward"; exit 1; }
command -v containerd >/dev/null || sudo apt-get install -y containerd.io
sudo mkdir -p /etc/containerd
[[ -s /etc/containerd/config.toml ]] || \
containerd config default | sudo tee /etc/containerd/config.toml >/dev/null
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
grep -q 'SystemdCgroup = true' /etc/containerd/config.toml || { echo "ERROR: cgroup"; exit 1; }
sudo systemctl restart containerd && sudo systemctl enable containerd
sudo apt-mark unhold kubelet kubeadm kubectl 2>/dev/null || true
sudo apt-get install -y kubelet="$VER" kubeadm="$VER" kubectl="$VER"
sudo apt-mark hold kubelet kubeadm kubectl
sudo systemctl enable --now kubeletClaus d'idempotència: el sed que no recomenta línies ja comentades, el [[ -s ]] abans de regenerar la configuració de containerd, i l'unhold abans d'instal·lar.
Solució 2
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: "v1.30.4"
clusterName: "rutas-norte-lab"
controlPlaneEndpoint: "api-k8s.rutasnorte.example:6443"
networking:
podSubnet: "172.16.0.0/16"
serviceSubnet: "10.96.0.0/12"
apiServer:
certSANs: ["api-k8s.rutasnorte.example", "10.10.0.10",
"10.10.0.11", "10.10.0.12", "10.10.0.13"]
extraArgs:
audit-log-path: "/var/log/kubernetes/audit.log"
audit-policy-file: "/etc/kubernetes/audit-policy.yaml"
audit-log-maxage: "30"
extraVolumes: # muntar la política al pod estàtic
- { name: audit-policy, hostPath: /etc/kubernetes/audit-policy.yaml,
mountPath: /etc/kubernetes/audit-policy.yaml, readOnly: true, pathType: File }
etcd:
local: { dataDir: "/var/lib/etcd" }
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: "systemd"
systemReserved: { cpu: "500m", memory: "512Mi" }
kubeReserved: { cpu: "200m", memory: "256Mi" }
evictionHard: { memory.available: "200Mi", nodefs.available: "10%" }Per què 172.16.0.0/16: és un rang privat (RFC 1918) que no col·lisiona amb la xarxa del laboratori (10.10.0.0/24) ni amb serviceSubnet (10.96.0.0/12), i dona 65 536 IP, suficients. Comprovacions prèvies: que 172.16/16 no es faci servir a la xarxa corporativa ni a la VPN, i configurar el CNI amb aquest mateix CIDR.
Solució 3
# --- FASE 0: còpia prèvia (punt de retorn) ---
sudo etcdctl snapshot save /var/copies/pre-131.db --endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
sudo tar czf /var/copies/pki-pre-131.tgz /etc/kubernetes/pki
sudo etcdutl --write-out=table snapshot status /var/copies/pre-131.db # verificar
kubectl get --raw /metrics | grep apiserver_requested_deprecated_apis # APIs obsoletes
# --- FASE 1: rn-control-1 ---
sudo apt-mark unhold kubeadm
sudo sed -i 's|v1.30|v1.31|' /etc/apt/sources.list.d/kubernetes.list
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.31/deb/Release.key | \
sudo gpg --dearmor --yes -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
sudo apt-get update && sudo apt-get install -y kubeadm=1.31.1-1.1 && sudo apt-mark hold kubeadm
sudo kubeadm upgrade plan
sudo kubeadm upgrade apply v1.31.1 # <-- PUNT SENSE RETORN
kubectl drain rn-control-1 --ignore-daemonsets --delete-emptydir-data
sudo apt-mark unhold kubelet kubectl && sudo apt-get install -y kubelet=1.31.1-1.1 kubectl=1.31.1-1.1
sudo apt-mark hold kubelet kubectl
sudo systemctl daemon-reload && sudo systemctl restart kubelet
kubectl uncordon rn-control-1 && kubectl get nodes
# --- FASE 2 i 3: rn-worker-1, després rn-worker-2 (un a un) ---
# repositori + kubeadm + `sudo kubeadm upgrade node` + drain + kubelet + uncordonPunt sense retorn: kubeadm upgrade apply, perquè migra l'esquema d'etcd. Abans, n'hi ha prou amb revertir els paquets; després, la marxa enrere exigeix restaurar el snapshot.
Si l'apiserver no arrenca: sudo crictl ps -a | grep apiserver, sudo crictl logs <id> i journalctl -u kubelet -f. Causes típiques: una bandera nova no suportada o un certificat mal generat. Si no es resol dins la finestra de manteniment, restaurar pre-131.db i pki-pre-131.tgz amb el procediment de l'apartat 13.2 i revertir els paquets a 1.30.4.
Conclusió
Ja saps muntar un clúster de Kubernetes des de zero sobre màquines pròpies. L'essencial:
- kubeadm arrenca un clúster conforme; no aprovisiona màquines ni instal·la el CNI. Aquesta frontera explica el 90 % dels dubtes inicials, inclòs el node
NotReady. - La preparació de les màquines —swap,
overlayibr_netfilter,ip_forward, ports, i sobretotSystemdCgroup = truea containerd— és on neixen les fallades més difícils de diagnosticar. - Un fitxer de configuració versionat (
ClusterConfiguration,InitConfiguration,KubeletConfiguration) és infinitament millor que una tirallonga de banderes;controlPlaneEndpointicertSANsben posats des del primer dia t'estalvien regenerar certificats més tard. - kubeadm deixa al node pods estàtics a
/etc/kubernetes/manifests, els certificats a/etc/kubernetes/pkii els kubeconfig: l'arquitectura de 01-02, feta fitxers. - Els nodes s'uneixen amb token i hash de la CA; el token caduca a les 24 hores i es regenera amb
kubeadm token create --print-join-command. L'alta disponibilitat exigeix un punt d'entrada estable i un nombre senar de membres d'etcd, normalment 3 apilats. - Els certificats caduquen a l'any, les actualitzacions van una versió menor cada vegada amb el pla de control abans que els nodes de treball, i les còpies d'etcd (snapshot +
pki, xifrades, fora del node, amb restauració assajada) són la diferència entre un mal dia i la fi de l'empresa.
I l'advertiment que cal repetir: operar això en producció exigeix un equip dedicat amb guàrdia. A 10-06 veurem què t'estalvia un clúster gestionat i a quin preu.
Però abans hem de resoldre el problema amb què va començar aquest mòdul. Ja sabem crear clústers, locals i propis; el que continua sense resoldre's són els 120 fitxers YAML duplicats de Rutas Norte. A la lliçó següent, Helm, coneixerem el gestor de paquets de Kubernetes: charts, valors, plantilles i releases. És l'eina amb què ja vam instal·lar cert-manager (04-05) i kube-prometheus-stack (07-03) sense explicar-la; toca entendre-la de debò i fer-la servir per empaquetar la plataforma Rutas Norte en un únic chart amb un fitxer de valors per entorn.
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
