Saltar al contenido principal

Provisión Automatizada de Nodos

Este estándar técnico define el proceso de creación de infraestructura base para un clúster de Kubernetes v1.35 utilizando Infraestructura como Código (IaC) ligera sobre un hipervisor Linux (KVM).

1. Arquitectura de Despliegue

Utilizamos un modelo de "Imágenes Doradas" mediante archivos .qcow2 diferenciales y personalización dinámica en el primer arranque via Cloud-Init.

2. Definición de la Topología (nodes.csv)

La matriz de nodos define el estado deseado de recursos y direccionamiento IP estático.

HostnameRAMvCPUsIP (Static)Role
cluster1-master12048210.2.3.4Control Plane
cluster1-worker1-32048210.2.3.4XWorker Nodes

3. Lógica de Aprovisionamiento (Scripting)

El script vms_provision.sh orquesta el ciclo de vida de la creación de VMs, gestionando discos diferenciales para optimizar el almacenamiento y utilizando virt-customize para inyectar configuraciones de red antes del arranque.

vms_provision.sh
export default "#!/bin/bash\n\n# 1. PATHS ABSOLUTOS\nreadonly SCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" &> /dev/null && pwd)\"\nreadonly FILE_NODES=\"${SCRIPT_DIR}/nodes.csv\"\nreadonly USER_DATA=\"${SCRIPT_DIR}/user-data.yaml\"\n\n# 2. VARIABLES KVM\nreadonly POOL_NAME='kvm-images'\nreadonly BASE_IMAGE='noble-server-cloudimg-amd64.img'\nreadonly GW='172.17.17.17'\nreadonly DNS1='172.17.17.17'\n\n# --- Function: Metadata Generation (Efímero) ---\nfunction generate_temp_metadata() {\n local hostname=$1\n local temp_file=$(mktemp /tmp/metadata.${hostname}.XXXXXX.yaml)\n echo -e \"instance-id: ${hostname}\\nlocal-hostname: ${hostname}\" > \"$temp_file\"\n echo \"$temp_file\"\n}\n\n# --- Main Provisioning Loop ---\ntail -n +2 \"${FILE_NODES}\" | while IFS=',' read -r hostname ram vcpus ip; do\n echo \"--- Aprovisionando: ${hostname} (${ip}) ---\"\n\n current_metadata=$(generate_temp_metadata \"$hostname\")\n\n # 1. Crear disco diferencial\n virsh vol-create-as ${POOL_NAME} ${hostname}.qcow2 20G \\\n --format qcow2 --backing-vol ${BASE_IMAGE} --backing-vol-format qcow2 > /dev/null\n\n DISK_PATH=$(virsh vol-path --pool ${POOL_NAME} ${hostname}.qcow2)\n\n # 2. INYECCIÓN DIRECTA (Network & Fixes)\n sudo virt-customize -a \"$DISK_PATH\" \\\n --hostname \"$hostname\" \\\n --write \"/etc/netplan/01-netcfg.yaml:\nnetwork:\n version: 2\n ethernets:\n enp1s0:\n dhcp4: false\n addresses: [$ip/24]\n routes: [{to: default, via: $GW}]\n nameservers: {addresses: [$DNS1, 8.8.8.8]}\" \\\n --run-command \"rm -f /etc/netplan/50-cloud-init.yaml\" \\\n --write \"/etc/cloud/cloud.cfg.d/99-disable-network-config.cfg:network: {config: disabled}\"\n\n # 3. LANZAMIENTO\n virt-install \\\n --name \"${hostname}\" --ram \"${ram}\" --vcpus \"${vcpus}\" \\\n --os-variant ubuntu24.04 --disk path=\"$DISK_PATH\" \\\n --network bridge=br0 --graphics none --import \\\n --cloud-init user-data=\"${USER_DATA}\",meta-data=\"${current_metadata}\" \\\n --noautoconsole\n\n rm -f \"$current_metadata\"\ndone\n";

4. Configuración del Runtime vía Cloud-Init

Para garantizar la inmutabilidad, el archivo user-data.yaml automatiza el Hardening del OS, la instalación del runtime containerd y la optimización de parámetros del Kernel (sysctl) necesarios para Kubernetes.

:::caution Gestión de Secretos En este ejemplo, la contraseña se inyecta mediante un hash SHA-512. En entornos productivos, se recomienda el uso de SSH Keys exclusivamente y la inyección de secretos vía Vault. :::

user-data.yaml.example
#cloud-config
users:
- name: candidate
# Conf. de sudo sin passwd
sudo: ALL=(ALL) NOPASSWD:ALL
groups: sudo
shell: /bin/bash
lock_passwd: false
passwd: "...PASSWORD_HASH..."
ssh_authorized_keys:
- ssh-rsa ...MY_CLAVE_PUBLICA...
- ...
# 1. INSTALACIÓN DE PAQUETES (Base + Runtime)
package_update: true
packages:
- curl
- gnupg
- vim
- apt-transport-https
- ca-certificates
- socat # Instalación automática del runtime (Requisito Kubeadm)
- conntrack # (Requisito Kubeadm)
- containerd # El Runtime (Requisitor de Kubeadm)
- nfs-common # Útil para volúmenes persistentes futuros

# 2. CONFIGURACIÓN DE ARCHIVOS (Módulos y Sysctl)
write_files:
- path: /etc/modules-load.d/k8s.conf
content: |
overlay
br_netfilter
- path: /etc/sysctl.d/k8s.conf
content: |
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1

# 3. EJECUCIÓN DE COMANDOS (El Ritual de Containerd)
runcmd:
# Desactivar Swap permanentemente
- [ swapoff, -a ]
- [ sed, -i, '/swap/d', /etc/fstab ]

# sysctl - Cargar módulos y aplicar red
- [ modprobe, overlay ]
- [ modprobe, br_netfilter ]
# Aplicar cambios de red sin reiniciar
- [ sysctl, --system ]

# Configuración de Containerd (Driver Systemd)
- mkdir -p /etc/containerd
- sh -c "containerd config default > /etc/containerd/config.toml"
- sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
# Configuración inicial de containerd (se completará manualmente para practicar)
- [ systemctl, enable, --now, containerd ]
# Configurar el socket de containerd para crictl
- [ crictl, config, runtime-endpoint, unix:///run/containerd/containerd.sock ]
# Reiniciar para aplicar cambios
- systemctl restart containerd
- systemctl enable containerd

Documentación Relacionada: