Files
kubernetes/cluster_init.md
2025-08-09 00:58:01 +02:00

525 lines
16 KiB
Markdown

# 0. Ejemplo de configuración de red en SUSE con NetworkManager
Aquí defines cómo se conectará tu servidor físicamente a la red en openSUSE/SLES: enlaces redundantes (bonding), VLANs para segmentar el tráfico, y bridges para conectar máquinas virtuales y pods a distintas redes. Esta configuración es la base para un clúster flexible y segmentado.
> **Pre-requisitos:**
>
> * openSUSE/SLES con NetworkManager activo.
> * Interfaces físicas: `em1` y `em2` (ajusta según tu hardware).
---
## 1. Crear el bond (LACP 802.3ad, rápido, hash layer3+4)
```bash
nmcli con add type bond ifname bond0 mode 802.3ad con-name bond0
nmcli con mod bond0 bond.options "mode=802.3ad,miimon=100,updelay=200,downdelay=200,lacp_rate=fast,xmit_hash_policy=layer3+4"
nmcli con mod bond0 ipv4.method disabled ipv6.method ignore
```
## 2. Añadir interfaces físicas al bond
```bash
nmcli con add type ethernet ifname em1 master bond0 con-name em1
nmcli con add type ethernet ifname em2 master bond0 con-name em2
nmcli con up em1
nmcli con up em2
nmcli con up bond0
```
## 3. Crear bridges de administración y servicios
```bash
# Bridge de administración (br-admin)
nmcli con add type bridge ifname br-admin con-name br-admin
nmcli con mod br-admin ipv4.addresses 192.168.0.42/24
nmcli con mod br-admin ipv4.gateway 192.168.0.1
nmcli con mod br-admin ipv4.dns "192.168.0.1 1.1.1.1 8.8.8.8"
nmcli con mod br-admin ipv4.method manual
nmcli con up br-admin
# Bridge de servicios (br-srv)
nmcli con add type bridge ifname br-srv con-name br-srv
nmcli con mod br-srv ipv4.method disabled ipv6.method ignore
nmcli con up br-srv
```
## 4. Crear VLANs sobre el bond y unirlas a los bridges
```bash
# VLAN 10 para administración
nmcli con add type vlan ifname vlan10 dev bond0 id 10 con-name vlan10
nmcli con mod vlan10 ipv4.method disabled ipv6.method ignore
nmcli con mod vlan10 master br-admin connection.slave-type bridge
nmcli con up vlan10
# VLAN 20 para servicios
nmcli con add type vlan ifname vlan20 dev bond0 id 20 con-name vlan20
nmcli con mod vlan20 ipv4.method disabled ipv6.method ignore
nmcli con mod vlan20 master br-srv connection.slave-type bridge
nmcli con up vlan20
# VLANs 30 y 40 con IP directa
nmcli con add type vlan ifname vlan30 dev bond0 id 30 con-name vlan30
nmcli con mod vlan30 ipv4.addresses 192.168.3.2/24
nmcli con mod vlan30 ipv4.method manual
nmcli con up vlan30
nmcli con add type vlan ifname vlan40 dev bond0 id 40 con-name vlan40
nmcli con mod vlan40 ipv4.addresses 192.168.4.2/24
nmcli con mod vlan40 ipv4.method manual
nmcli con up vlan40
```
---
# Ahora si: Guía definitiva de despliegue Kubernetes (openSUSE/SLES)
> **Revisión y correcciones basadas en el history real de despliegue**
## 1. Prerrequisitos del sistema (SUSE)
Este paso parte de una instalación limpia de openSUSE/SLES actualizada y con permisos de administrador. Instala utilidades básicas, configura el repositorio oficial de Kubernetes y desactiva SWAP, igual que harías en Ubuntu, pero con comandos adaptados a zypper y la gestión de repositorios en SUSE.
### a) Actualiza el sistema y paquetes básicos
```bash
sudo zypper refresh
sudo zypper update
sudo zypper install -y curl ca-certificates keepalived chrony
```
### b) Añade el repositorio oficial de Kubernetes
Crea el archivo de repositorio para Kubernetes (v1.33):
```bash
cat <<EOF | sudo tee /etc/zypp/repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.33/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.33/rpm/repodata/repomd.xml.key
EOF
```
Actualiza la caché de repositorios y acepta la clave GPG cuando se te pida:
```bash
sudo zypper refresh
sudo zypper update
```
> Cuando veas el aviso sobre la clave GPG, pulsa 'a' para aceptar siempre.
### c) Configuración de Keepalived
En SRVFKVM01 (MASTER):
```bash
cat <<EOF | sudo tee /etc/keepalived/keepalived.conf
vrrp_instance VI_1 {
state MASTER
interface br-admin
virtual_router_id 51
priority 150
advert_int 1
authentication {
auth_type PASS
auth_pass 42manabo42
}
virtual_ipaddress {
192.168.0.20/24
}
}
EOF
```
En los demás (BACKUP):
```bash
cat <<EOF | sudo tee /etc/keepalived/keepalived.conf
vrrp_instance VI_1 {
state BACKUP
interface br-admin
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 42manabo42
}
virtual_ipaddress {
192.168.0.20/24
}
}
EOF
```
Después en todos:
```
sudo systemctl enable keepalived
sudo systemctl start keepalived
```
### d) Sincronización horaria
En todos los servidores del cluster:
```bash
sudo systemctl enable chronyd
sudo systemctl start chronyd
sudo chronyc makestep # Fuerza la sincronización inicial
```
---
## 2. Instala containerd (runtime recomendado)
`containerd` es el motor que gestiona los contenedores en el clúster. Kubernetes necesita un “runtime” para crear y controlar los pods, y containerd es la opción oficial y más estable.
```bash
sudo zypper install -y containerd
sudo mkdir -p /etc/containerd
sudo containerd config default | sudo tee /etc/containerd/config.toml
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sudo systemctl restart containerd
sudo systemctl enable containerd
```
---
## 3. Desactiva SWAP (requisito para Kubernetes)
Kubernetes requiere que el intercambio de memoria (swap) esté desactivado. Esto evita problemas de rendimiento y estabilidad.
```bash
sudo swapoff -a
sudo sed -i '/ swap / s/^/#/' /etc/fstab
```
---
## 4. Prepara el kernel y sysctl y abre puertos
En este paso se habilitan módulos y parámetros de red necesarios para que Kubernetes gestione correctamente el tráfico entre pods y nodos.
```bash
sudo modprobe overlay
sudo modprobe br_netfilter
cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
sudo sysctl --system
```
---
> **En SUSE, la carga de los modulos no es persistente.** Para que sea persistente hay que poner:
>```bash
>echo -e "br_netfilter\noverlay" | sudo tee /etc/modules-load.d/k8s.conf
>```
---
el trafico básico que se debe permitir es:
```bash
# Al nabo el firewall (gracias SUSE):
sudo systemctl disable --now firewalld
```
---
## 5. Instala los componentes de Kubernetes (kubectl, kubelet, kubeadm)
Instala en un solo paso las utilidades principales:
```bash
sudo zypper install -y kubectl kubelet kubeadm
```
Edita `/etc/sysconfig/kubelet` para poner la dirección IP que tendrá el nodo:
```bash
KUBELET_EXTRA_ARGS=--node-ip=192.168.4.1 # <-- Dirección ip de cada nodo en la Vlan interna del cluster
```
Activa kubelet para que se inicie automáticamente:
```bash
sudo systemctl enable kubelet
sudo systemctl start kubelet
```
> Es **normal** que el servicio kubelet falle en bucle hasta que inicialices el clúster con `kubeadm init`.
> El error más frecuente es:
>
> * "failed to load Kubelet config file, path: /var/lib/kubelet/config.yaml"
>
> Tras ejecutar `kubeadm init`, kubelet arrancará correctamente.
---
## 5b. (Opcional) Habilita cgroup v2 (solo SLES si necesario)(Si no te funciona, SI lo necesitas)
Si necesitas cgroup v2 en SLES, añade esto al arranque del kernel (edita `/etc/default/grub`):
```
GRUB_CMDLINE_LINUX_DEFAULT="systemd.unified_cgroup_hierarchy=1 ..."
```
Y regenera el grub:
```bash
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
```
Reinicia para aplicar los cambios.
---
# 6. Inicializa el clúster (openSUSE/SLES)
Este paso crea el clúster de Kubernetes en el nodo principal (control-plane) sobre openSUSE/SLES. Aquí defines la red interna para los pods y la interfaz/VLAN física para el tráfico overlay del clúster, según tu diseño.
---
## a) Inicializa el clúster especificando red de pods, la IP interna y la VIP
> **Importante:**
>
> * Usa la opción `--apiserver-advertise-address` para forzar que el nodo control-plane escuche en la IP de la VLAN interna de clúster (ejemplo: `192.168.4.x` en tu VLAN 40).
> * Usa `--control-plane-endpoint` para indicar la IP virtual compartida (VIP) gestionada por Keepalived. Debe ser una IP accesible por todos los nodos control-plane (ejemplo: `192.168.0.20`).
> * Usa `--apiserver-cert-extra-sans` para añadir la VIP (y/o el FQDN) como SAN en el certificado TLS del API server, así todos los nodos confían en esa IP/nombre.
> * Usa `--pod-network-cidr=10.244.0.0/16` si vas a usar Flannel como CNI (ajusta si usas otro CNI).
```bash
sudo kubeadm init \
--apiserver-advertise-address=192.168.4.1 \
--control-plane-endpoint="192.168.0.20:6443" \
--apiserver-cert-extra-sans="192.168.0.20" \
--pod-network-cidr=10.244.0.0/16 \
--upload-certs
```
Cambia `192.168.4.1` por la IP interna del nodo donde ejecutas el comando (en la VLAN de clúster) y `192.168.0.20` por la IP VIP gestionada por Keepalived.
---
## c) Configura kubectl para tu usuario
Permite usar el comando `kubectl` como usuario normal copiando la configuración de administración del clúster a tu carpeta personal.
En el nodo master (SRVFKVM01)
```bash
mkdir -p $HOME/.kube
cd /etc/kubernetes
sudo cp -i admin.conf $HOME/.kube/config
sudo scp config admin.c3s@192.168.0.4X:/home/admin.c3s/admin.conf #a todos los nodos
sudo chown $(id -u):$(id -g) $HOME/.kube/config
```
### Añadir un nodo fuera de plazo.
Para añadir un nodo con posterioridad y con intención de que se convierta en controller, debemos limparlo, en los archivos donde se almacena datos del cluster y el nodo, parar el servicio y reset de kubelet reset -f
En el nodo principal ejecutar:
```bash
kubeadm token create --print-join-command --description "ALgo significativo"
```
Con esto generaremos un nuevo token podemos lmitarlo con TTL 5 h (horas). Pero solo nos vale para unir un worker.
Si queremos unir un controller hay que añadir el certificado de la CA, seconsigue con:
```bash
kubeadm init phase upload-certs --upload-certs
```
Si copiamos ambos resultados y lo unimos en un solo comando join conseguiremos el objetivo. Explicado más abajo.
# d) Instala la red de pods (Flannel) usando la VLAN interna del clúster
Kubernetes solo define la infraestructura; necesitas un complemento de red (CNI) para que los pods puedan comunicarse entre sí. **Flannel** es la opción más sencilla y compatible, y puedes configurarla para usar una interfaz/VLAN específica para el tráfico overlay (muy recomendable si segmentas redes en tu clúster).
---
## ¡ATENCIÓN! CNI Y PLUGINS
Antes de aplicar Flannel, **asegúrate de tener los plugins CNI instalados en `/opt/cni/bin/`** (en SUSE esto NO siempre lo hace el paquete de Flannel):
```bash
CNI_VERSION="v1.4.1"
ARCH="amd64"
sudo curl -Lo cni-plugins.tgz https://github.com/containernetworking/plugins/releases/download/${CNI_VERSION}/cni-plugins-linux-${ARCH}-${CNI_VERSION}.tgz
sudo mkdir -p /opt/cni/bin
sudo tar -C /opt/cni/bin -xzf cni-plugins.tgz
sudo chmod +x /opt/cni/bin/*
sudo chown root:root /opt/cni/bin/*
```
Verifica que existen al menos:
* `/opt/cni/bin/loopback`
* `/opt/cni/bin/flannel`
* `/opt/cni/bin/bridge` y otros
---
## Instalación de Flannel especificando la interfaz de la VLAN de clúster
**Descarga el manifiesto de Flannel:**
```bash
wget https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
```
**Edita el manifiesto para forzar la interfaz de red correcta:**
* Abre `kube-flannel.yml`
* Busca el bloque `args:` bajo el contenedor principal.
* Añade la línea siguiente (ajusta el nombre según tu interfaz real, por ejemplo, `vlan40`, `bond0.40`, etc.):
```yaml
- --iface=vlan40 # <--- Pon aquí el nombre de la interfaz con IP 192.168.4.x
```
### Ejemplo del bloque completo:
```yaml
containers:
- args:
- --ip-masq
- --kube-subnet-mgr
- --iface=vlan40 # <--- Nueva línea
command:
- /opt/bin/flanneld
...
```
> **TIP:** Puedes comprobar el nombre con `ip a` en el host, buscando la interfaz con la IP `192.168.4.x` (VLAN 40).
**Aplica el manifiesto editado:**
```bash
kubectl apply -f kube-flannel.yml
```
---
## Verifica el despliegue y que Flannel usa la interfaz correcta
* Comprueba que todos los pods de Flannel están en estado **Running**:
```bash
kubectl -n kube-flannel get pods -o wide
```
* Consulta los logs de Flannel en cada nodo:
```bash
kubectl -n kube-flannel logs <nombre-pod-flannel-en-cada-nodo> | grep Using
```
Debes ver una línea como:
```text
Using interface with name vlan40 and address 192.168.4.x
```
Si todo es correcto, ya puedes comprobar conectividad pod-to-pod entre nodos.
---
## e) Une el resto de nodos control-plane
En los demás nodos control-plane (tras configurar Keepalived y tener la VIP activa):
```bash
sudo kubeadm join 192.168.0.20:6443 \
--token <TOKEN> \
--discovery-token-ca-cert-hash <HASH> \
--control-plane \
--certificate-key <CERTIFICATE_KEY> \
--apiserver-advertise-address=192.168.4.2
```
> **Importante:** Cambia la IP `192.168.4.2` por la correspondiente a cada servidor control-plane que estés uniendo.
Recuerda usar los valores correctos de token, hash y certificate-key que te dará el comando `kubeadm init` o puedes volver a consultar desde el nodo principal:
```bash
kubeadm token create --print-join-command --control-plane
```
Credenciales para todos (lo que le gusta al jefe):
```bash
mkdir -p $HOME/.kube
cd
sudo cp -i admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
```
---
## EXTRA: Si te ha caducado el TOKEN, o no lo guardaste
Cuando el token de unión (`kubeadm join`) ha caducado, sigue estos pasos en el **nodo principal (control-plane)** para generar un nuevo token y el comando actualizado:
```sh
# 1. Sube los certificados y obtén la nueva clave de certificado (certificate-key)
sudo kubeadm init phase upload-certs --upload-certs
```
> La salida mostrará la nueva `certificate key`, necesaria para añadir un nuevo nodo de control-plane.
```sh
# 2. Genera un nuevo token y muestra el comando kubeadm join listo para usar
sudo kubeadm token create --print-join-command
```
> La salida mostrará el comando `kubeadm join` con el nuevo token y el hash actual del CA.
### Ejemplo de salidas:
```
[upload-certs] Using certificate key:
588ee9d0441c0aea36b2a2a638beae4cfa81dd3498eb61205c8496f344f6c55d
kubeadm join 192.168.0.20:6443 --token s9nlsp.gasv66tkc43zpiok --discovery-token-ca-cert-hash sha256:d41f0edb90c66c0555bdf4feca55f1e69019764be0fcd649a254e99ff124568f
```
---
## Comando completo para unir un nodo **como control-plane**
Añade los parámetros `--control-plane --certificate-key <certificate-key> --apiserver-advertise-address=192.168.4.2` al final del comando `kubeadm join` generado. Usando el ejemplo anterior, el comando final sería:
```sh
sudo kubeadm join 192.168.0.20:6443 \
--token s9nlsp.gasv66tkc43zpiok \
--discovery-token-ca-cert-hash sha256:d41f0edb90c66c0555bdf4feca55f1e69019764be0fcd649a254e99ff124568f \
--control-plane \
--certificate-key 588ee9d0441c0aea36b2a2a638beae4cfa81dd3498eb61205c8496f344f6c55d \
--apiserver-advertise-address=192.168.4.2
```
> **Recuerda**: Cambia `192.168.4.2` por la IP real del nodo que se está uniendo.
---
Con esto podrás unir cualquier nodo extra como nuevo control-plane, incluso cuando el token original haya caducado.
---
## **Troubleshooting y buenas prácticas extra**
* Si ves errores con el loopback CNI (`exec format error`, `permission denied`, etc.), **borra el contenido de `/opt/cni/bin/` y vuelve a instalar los plugins**.
* Siempre revisa que el módulo `br_netfilter` está cargado y los sysctl activos (`lsmod | grep br_netfilter`).
* Si el nodo aparece como NotReady, revisa `/etc/cni/net.d/`, los logs de kubelet, y repite la reinstalación del CNI.
* **Si limpias todo y reinicias, repite estos pasos:**
* Reinstala CNI plugins
* Aplica Flannel
* Reinicia kubelet