# 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 nmcli con mod bond0 bond.options "mode=802.3ad,miimon=100,updelay=200,downdelay=200,lacp_rate=fast,xmit_hash_policy=layer3+4" ``` ## 2. Añadir interfaces físicas al bond ```bash nmcli con add type ethernet ifname em1 master bond0 nmcli con add type ethernet ifname em2 master bond0 ``` ## 3. Crear VLANs sobre el bond ```bash nmcli con add type vlan ifname vlan10 dev bond0 id 10 nmcli con add type vlan ifname vlan20 dev bond0 id 20 nmcli con add type vlan ifname vlan30 dev bond0 id 30 ip4 192.168.3.2/24 nmcli con add type vlan ifname vlan40 dev bond0 id 40 ip4 192.168.4.2/24 ``` ## 4. Crear bridges y unirlos a las VLANs ```bash # Bridge de administración (br-admin) sobre vlan10 nmcli con add type bridge ifname br-admin nmcli con add type bridge-slave ifname vlan10 master br-admin nmcli con mod br-admin ipv4.addresses 192.168.0.42/24 nmcli con mod br-admin ipv4.method manual 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" # Bridge de servicios (br-srv) sobre vlan20 nmcli con add type bridge ifname br-srv nmcli con add type bridge-slave ifname vlan20 master br-srv nmcli con mod br-srv ipv4.addresses 192.168.200.2/22 nmcli con mod br-srv ipv4.method manual ``` ## 5. Sube todas las conexiones (en orden: bond, VLANs, bridges) ```bash nmcli con up bond0 nmcli con up vlan10 nmcli con up vlan20 nmcli con up vlan30 nmcli con up vlan40 nmcli con up br-admin nmcli con up br-srv ``` --- # Guía rápida: Instalar Kubernetes en openSUSE/SLES Esta guía cubre todos los pasos necesarios para instalar Kubernetes en openSUSE Leap, Tumbleweed o SLES, usando containerd como runtime y gestionando todo con zypper. Sigue el orden de los pasos para evitar problemas. # 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 < Cuando veas el aviso sobre la clave GPG, pulsa 'a' para aceptar siempre. ### c) Configuración de Keepalived En SRVFKVM01 (MASTER): ```bash cat < 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 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 ``` ## 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" 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 ``` Verifica que existen al menos: * `/opt/cni/bin/loopback` * `/opt/cni/bin/flannel` * `/opt/cni/bin/bridge` y otros Corrige permisos si hace falta: ```bash sudo chmod +x /opt/cni/bin/* sudo chown root:root /opt/cni/bin/* ``` **Luego sí aplica Flannel:** ```bash kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml ``` --- ## e) Comprueba que Flannel funciona ```bash kubectl -n kube-flannel get pods -o wide ``` > Todos los pods deben estar en estado `Running`. Si no levanta, **verifica logs y revisa `/opt/cni/bin/`**: * Los binarios deben ser para la arquitectura correcta (x86\_64/amd64). * Deben tener permisos de ejecución y ser propiedad de root. --- ## f) 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 \ --discovery-token-ca-cert-hash \ --control-plane \ --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 --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 # 8. Instala Multus (opcional, para múltiples redes) Multus permite que un pod tenga más de una interfaz de red (multi-homed), útil para appliances, firewalls, balanceadores, gateways, etc. Instálalo si necesitas conectar pods a varias redes físicas o VLANs (por ejemplo, mediante bridges y NADs). **Instalación:** ```bash kubectl apply -f https://raw.githubusercontent.com/k8snetworkplumbingwg/multus-cni/master/deployments/multus-daemonset.yml ``` **Verifica:** ```bash kubectl get pods -n kube-system | grep multus ``` --- # 9. (Opcional) Quita el taint del nodo master para poder programar pods en él Por defecto, Kubernetes no programa pods de usuario en el nodo principal (control-plane). Elimina este bloqueo para poder desplegar aplicaciones ahí. ```bash kubectl taint nodes --all node-role.kubernetes.io/control-plane- kubectl taint nodes --all node-role.kubernetes.io/master- ``` ## Nota: Uso de taints en nodos control-plane (alta disponibilidad y ejecución de cargas) ### ¿Qué es un taint? * Un **taint** en Kubernetes es una marca especial que se pone a un nodo para **evitar que los pods se programen ahí**, salvo que declaren una “toleration” explícita. * Se usa para reservar nodos solo para tareas especiales (por ejemplo, el control-plane). * Por defecto, los nodos control-plane llevan un taint: * `node-role.kubernetes.io/control-plane:NoSchedule` ### ¿Por qué quitar el taint? * Si quieres que **los nodos control-plane puedan ejecutar pods de usuario** (además del plano de control), necesitas **quitar el taint**. * Esto es común en clústeres pequeños o medianos, donde **todos los nodos cumplen doble función** (alta disponibilidad y ejecución de cargas). --- ### **Comandos para quitar el taint de todos los nodos control-plane:** ```bash kubectl taint nodes --all node-role.kubernetes.io/control-plane- kubectl taint nodes --all node-role.kubernetes.io/master- ``` * El `-` final indica “quitar”. * Ejecuta ambos para máxima compatibilidad entre versiones. ### **Comando para añadir el taint (dejar el nodo solo como control-plane):** ```bash kubectl taint nodes NOMBRE_DEL_NODO node-role.kubernetes.io/control-plane=:NoSchedule ``` * Así, ese nodo **solo ejecuta el plano de control** (salvo pods con toleration específica). --- # 10. Test rápido de Multus (NAD + pod con 2 interfaces) Puedes comprobar que Multus funciona creando una red secundaria y un pod de prueba con dos interfaces (una por defecto, una secundaria). En la carpeta `multus/` de tu repositorio, debes tener: * `multus/nad-br-servicios.yaml` (NetworkAttachmentDefinition) * `multus/test-multus-pod.yaml` (pod Alpine multi-homed) **Despliega la NAD:** ```bash kubectl apply -f multus/nad-br-servicios.yaml ``` **Despliega el pod de test:** ```bash kubectl apply -f multus/test-multus-pod.yaml ``` **Comprueba las interfaces:** ```bash kubectl exec -it multus-test -- sh ip a ``` * El pod debe mostrar una interfaz extra (además de la de Flannel), conectada a tu red secundaria (`br-servicios`, etc.). **Para limpiar:** ```bash kubectl delete pod multus-test ``` --- > **Nota:** Puedes crear tantas NADs (NetworkAttachmentDefinition) como bridges/VLANs quieras conectar a pods específicos (con Multus), ideal para appliances de red, gateways, SDN, pruebas de seguridad, etc. --- # 11. Instalación y configuración de MetalLB (LoadBalancer local) MetalLB permite asignar IPs flotantes de tu red LAN a servicios `LoadBalancer`, igual que hacen los clústeres en la nube. Es fundamental si quieres exponer servicios como ingress, dashboards, etc., accesibles desde tu red local. --- ## a) Instala MetalLB ```bash kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.5/config/manifests/metallb-native.yaml ``` Esto crea el namespace `metallb-system` y los pods necesarios. --- ## b) Declara múltiples pools de IP Puedes crear varios pools (por ejemplo, uno para producción y otro para test, o para diferentes VLANs/segmentos). Los pools se definen en el objeto `IPAddressPool`. **Ejemplo: `metallb/ipaddresspool.yaml`** ```yaml apiVersion: metallb.io/v1beta1 kind: IPAddressPool metadata: name: pool-produccion namespace: metallb-system spec: addresses: - 192.168.1.100-192.168.1.110 --- apiVersion: metallb.io/v1beta1 kind: IPAddressPool metadata: name: pool-lab namespace: metallb-system spec: addresses: - 192.168.2.100-192.168.2.110 ``` **Ejemplo: `metallb/l2advertisement.yaml`** ```yaml apiVersion: metallb.io/v1beta1 kind: L2Advertisement metadata: name: advert-all namespace: metallb-system spec: {} ``` **Kustomization:** ```yaml resources: - ipaddresspool.yaml - l2advertisement.yaml ``` Para aplicar: ```bash kubectl apply -k metallb/ ``` --- ## c) Asigna un pool concreto a un Service (anotaciones) Por defecto, los Services `LoadBalancer` usan cualquier pool disponible. Para forzar el uso de un pool específico, **añade esta anotación al Service**: ```yaml apiVersion: v1 kind: Service metadata: name: ejemplo-prod annotations: metallb.universe.tf/address-pool: pool-produccion spec: selector: app: ejemplo ports: - port: 80 targetPort: 80 type: LoadBalancer ``` * Cambia `pool-produccion` por el nombre de pool que quieras usar. Al crear el Service, MetalLB le asignará una IP **solo de ese pool**. --- ## d) Comprobar el resultado ```bash kubectl get svc ``` Verás la IP asignada en la columna `EXTERNAL-IP`. --- > **Notas:** > > * Puedes definir tantos pools como necesites, uno por segmento/VLAN/uso. > * Puedes versionar los manifiestos de MetalLB en una carpeta específica del repositorio (`metallb/`). ---