Cómo Automatizar un Clúster de Kubernetes en Hyper-V con PowerShell

Cómo Automatizar un Clúster de Kubernetes en Hyper-V con PowerShell

por Raúl Unzué

Kubernetes sobre Hyper-V

La virtualización se ha convertido en un estándar en entornos empresariales, y Kubernetes es el orquestador por excelencia para gestionar contenedores a gran escala. Si combinas ambas tecnologías en una infraestructura de Hyper-V, puedes lograr un entorno flexible, escalable y altamente automatizado.

Pero ¿por qué hacerlo manualmente si podemos automatizarlo? PowerShell nos permite desplegar un clúster de Kubernetes en Hyper-V de forma rápida y eficiente, asegurando una configuración homogénea y minimizando errores humanos.

En esta guía, te mostraremos paso a paso cómo automatizar la creación de máquinas virtuales mediante una plantilla de Debian, la configuración de redes, la instalación de Kubernetes y la validación del clúster, todo a través de PowerShell. Además, incluiremos pruebas de conectividad y monitoreo para garantizar que todo funcione correctamente dentro de tu red LAN.

Al final de esta guía, tendrás un clúster de Kubernetes funcional en Hyper-V, listo para desplegar aplicaciones de manera eficiente y sin intervención manual.

Requisitos previos

Antes de ejecutar el script del Powershell (si queréis saber como construir vuestro primer script, os dejamos una entrada), asegúrate de contar con lo siguiente:

  • Mínimo Windows Server 2022 o Windows 10/11 Pro/Enterprise con Hyper-V activado. Lo podéis instalar con el siguiente comando:
    • Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All
  • Mínimo 16 GB de RAM.
  • Procesador con virtualización habilitada (VT-x o AMD-V).
  • PowerShell con permisos de administrador.
  • En nuestro caso, usaremos una plantilla de Debian Cloud para generar todas las máquinas virtuales. 
  • Acceso a internet en la máquina host para descargar paquetes.
  • Instalar paquete en plantilla "hv_kvp":

sudo apt update && sudo apt install linux-cloud-tools-common linux-cloud-tools-generic linux-cloud-tools-$(uname -r)

sudo systemctl enable hv-kvp-daemon

sudo systemctl start hv-kvp-daemon

  • Para instalar "cloud-init", que es una herramienta utilizada para la configuración automática de instancias en la nube o máquinas virtuales en su primer arranque. Permite personalizar servidores con configuraciones específicas como usuarios, claves SSH, paquetes, scripts de inicialización y más, sin intervención manual:

sudo apt update && sudo apt install -y cloud-init

Para sellar la máquina virtual utilizar el siguiente comando:

sudo cloud-init clean --logs

  • Instalar Kubernetes en plantilla Debian:

apt install -y apt-transport-https ca-certificates curl gnupg2 software-properties-common

mkdir -p /etc/apt/keyrings

curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key | sudo tee /etc/apt/keyrings/kubernetes-apt-keyring.asc > /dev/null

echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.asc] https://pkgs.k8s.io/core:/stable:/v1.29/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list

apt update

apt install -y kubelet kubeadm kubectl

apt-mark hold kubelet kubeadm kubectl

  • Paquete ADK instalado en el host de Hyper-V:

Geeknetic Cómo Automatizar un Clúster de Kubernetes en Hyper-V con PowerShell 1

Crear una Plantilla de Debian en Hyper-V

Si utilizamos una plantilla pre-creada de Debian en Hyper-V, podemos clonar y personalizar las máquinas virtuales en el momento del arranque usando PowerShell y Cloud-Init.

Esta estrategia optimiza el despliegue, ya que evita reinstalar el sistema operativo desde cero y permite modificar cada nodo (master o worker) en función de su rol.

Os explicamos como lo podemos hacer:

  1. Descargamos la imagen oficial de Debian Cloud (Qcow2 o Raw), lo podéis hacer vía comando o directamente con la URL:
    • wget https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-amd64.qcow2
  2. Convierte la imagen a formato VHDX (para Hyper-V) con qemu-img:
    • qemu-img convert -f qcow2 -O vhdx debian-12-genericcloud-amd64.qcow2 debian-template.vhdx
  3. Crea una VM en Hyper-V con el disco debian-template.vhdx y Cloud-Init activado.
  4. Configura SSH y Cloud-Init en la plantilla:
    • apt update && apt install -y cloud-init

      systemctl enable cloud-init

    • cloud-init clean
    • Crea el archivo /etc/cloud/cloud.cfg.d/99-hyperv.cfg y añade:

      datasource_list: [NoCloud, None]
  5. Apaga la máquina y conviértela en una plantilla de solo lectura:
    • Set-VM -Name "Debian-Template" -CheckpointType Disabled

Script Powershell para generar plantilla de VM en Hyper-V

  • Opcionalmente, podéis usar un script de powershell para generarla una vez parametrizada:

Geeknetic Cómo Automatizar un Clúster de Kubernetes en Hyper-V con PowerShell 2

PowerShell: Script para Crear la Infraestructura

El siguiente script, automatiza la creación del clúster Kubernetes generando las máquinas virtuales (1 Master y 2 Workers), configurando redes y preparando los nodos para Kubernetes:

 

# ========================

# CONFIGURACIÓN DEL SCRIPT

# Definimos variables de configuración

# ========================

# Variables de configuración

$VMSwitchName = "K8S-External-Network"

$VMPath = "D:\Hyper-V"

$CloudInitPath = "$VMPath\CloudInit"

$TemplateVHD = "$VMPath\Templates\debian-template.vhdx"

$OscdimgPath = "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg\oscdimg.exe"

# Validar si oscdimg.exe existe

if (!(Test-Path $OscdimgPath)) {

    Write-Host "Error: oscdimg.exe no encontrado en $OscdimgPath. Instala el Windows ADK."

    exit

}

# Crear directorio de Cloud-Init si no existe

if (!(Test-Path $CloudInitPath)) {

    Write-Host "Creando directorio de Cloud-Init..."

    New-Item -ItemType Directory -Path $CloudInitPath | Out-Null

}

Geeknetic Cómo Automatizar un Clúster de Kubernetes en Hyper-V con PowerShell 3

# ========================

# SOLICITAR DATOS AL USUARIO

# Pide un usuario y contraseña para las VMs

# ========================

$Username = Read-Host "Introduce el nombre de usuario para los nodos"

$Password = Read-Host "Introduce la contraseña para los nodos" -AsSecureString

$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)

$PlainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)

# Generar clave SSH si no existe

$SSHKeyPath = "$env:USERPROFILE\.ssh\id_rsa"

if (!(Test-Path $SSHKeyPath)) {

    Write-Host "Generando clave SSH..."

    ssh-keygen -t rsa -b 4096 -N "" -f $SSHKeyPath

}

$SSHKeyPub = Get-Content "$SSHKeyPath.pub"

Geeknetic Cómo Automatizar un Clúster de Kubernetes en Hyper-V con PowerShell 4

# ========================

# CREAR SWITCH VIRTUAL EXTERNO SI NO EXISTE

# Creamos la red para nuestras VMs

# ========================

if (!(Get-VMSwitch -Name $VMSwitchName -ErrorAction SilentlyContinue)) {

    $NetAdapter = (Get-NetAdapter | Where-Object { $_.Status -eq 'Up' } | Select-Object -ExpandProperty Name -First 1)

    if ($NetAdapter) {

        Write-Host "Creando switch virtual externo: $VMSwitchName en $NetAdapter"

        New-VMSwitch -Name $VMSwitchName -NetAdapterName $NetAdapter -AllowManagementOS $true

    } else {

        Write-Host "Error: No se encontró un adaptador de red activo."

        exit

    }

}

Geeknetic Cómo Automatizar un Clúster de Kubernetes en Hyper-V con PowerShell 5

# ========================

# CREAR LAS VMs Y CONFIGURAR CLOUD-INIT

# Definimos las características de las VMs y los ficheros para Cloud-Init

# ========================

$VMs = @(

    @{ Name = "K8S-Master"; RAM = 4GB; CPU = 2; Role = "master"; IP = "192.168.2.120" },

    @{ Name = "K8S-Worker1"; RAM = 3GB; CPU = 2; Role = "worker"; IP = "192.168.2.121" },

    @{ Name = "K8S-Worker2"; RAM = 3GB; CPU = 2; Role = "worker"; IP = "192.168.2.122" }

)

foreach ($VM in $VMs) {

    $VHDPath = "$VMPath\$($VM.Name).vhdx"

    $CloudISO = "$CloudInitPath\$($VM.Name)-Config.iso"

    if (Get-VM -Name $VM.Name -ErrorAction SilentlyContinue) {

        Write-Host "La máquina virtual $($VM.Name) ya existe. Omitiendo..."

        continue

    }

    Write-Host "Creando VM: $($VM.Name)"

    Copy-Item -Path $TemplateVHD -Destination $VHDPath -Force

Geeknetic Cómo Automatizar un Clúster de Kubernetes en Hyper-V con PowerShell 6

    # ========================

    # GENERAR ARCHIVOS DE CLOUD-INIT

    # ========================

    Write-Host "Generando archivos de Cloud-Init para $($VM.Name)..."

    # Meta-Data

    $MetaData = @"

instance-id: $($VM.Name)

local-hostname: $($VM.Name)

"@

    $MetaData | Set-Content -Path "$CloudInitPath\meta-data" -Encoding UTF8

    # User-Data

    $UserData = @"

#cloud-config

users:

  - default

  - name: ${Username}

    sudo: ALL=(ALL) NOPASSWD:ALL

    shell: /bin/bash

    ssh_authorized_keys:

      - ${SSHKeyPub}

    ssh_import_id:

      - gh:${Username}

    lock_passwd: false

    passwd: "${PlainPassword}"

    chpasswd: { expire: false }

    groups: sudo, users

    home: /home/${Username}

chpasswd:

  list: |

    root:${PlainPassword}

    ${Username}:${PlainPassword}

  expire: false

ssh_pwauth: true

disable_root: false

runcmd:

  - sudo apt-get update

  - sudo apt-get install -y qemu-guest-agent curl openssh-server net-tools

  - sudo systemctl enable --now qemu-guest-agent

  - sudo mkdir -p /home/${Username}/.ssh

  - echo "${SSHKeyPub}" | sudo tee /home/${Username}/.ssh/authorized_keys

  - sudo chown -R ${Username}:${Username} /home/${Username}/.ssh

  - sudo chmod 700 /home/${Username}/.ssh

  - sudo chmod 600 /home/${Username}/.ssh/authorized_keys

  - echo "PermitRootLogin yes" | sudo tee -a /etc/ssh/sshd_config

  - echo "PasswordAuthentication yes" | sudo tee -a /etc/ssh/sshd_config

  - echo "AllowUsers ${Username}" | sudo tee -a /etc/ssh/sshd_config

  - sudo systemctl restart sshd

  - sudo cloud-init clean

"@

    $UserData | Set-Content -Path "$CloudInitPath\user-data" -Encoding UTF8

    # Configuración de IP estática en la LAN

    $NetworkConfig = @"

version: 2

ethernets:

  eth0:

    addresses:

      - $($VM.IP)/24

    gateway4: 192.168.2.69

    nameservers:

      addresses:

        - 8.8.8.8

        - 1.1.1.1

"@

    $NetworkConfig | Set-Content -Path "$CloudInitPath\network-config" -Encoding UTF8

Geeknetic Cómo Automatizar un Clúster de Kubernetes en Hyper-V con PowerShell 7

Geeknetic Cómo Automatizar un Clúster de Kubernetes en Hyper-V con PowerShell 8

    # ========================

    # GENERAR ISO DE CLOUD-INIT

    # ========================

    Write-Host "Generando ISO de Cloud-Init para $($VM.Name)..."

    Start-Process -FilePath $OscdimgPath `

        -ArgumentList "-d -m `"$CloudInitPath`" `"$CloudISO`"" `

        -NoNewWindow -Wait

    if (!(Test-Path $CloudISO)) {

        Write-Host "ERROR: No se pudo generar el archivo Cloud-Init ISO en $CloudISO"

        exit

    }

Geeknetic Cómo Automatizar un Clúster de Kubernetes en Hyper-V con PowerShell 9

    # ========================

    # CREAR VM

    # ========================

    New-VM -Name $VM.Name -MemoryStartupBytes $VM.RAM -Generation 2 `

           -VHDPath $VHDPath -SwitchName $VMSwitchName

    Set-VMProcessor -VMName $VM.Name -Count $VM.CPU

    Set-VMMemory -VMName $VM.Name -DynamicMemoryEnabled $true `

                 -MinimumBytes 512MB -MaximumBytes 8GB

    Add-VMDvdDrive -VMName $VM.Name

    Set-VMDvdDrive -VMName $VM.Name -Path $CloudISO

    # Configurar firmware

    Set-VMFirmware -VMName $VM.Name -EnableSecureBoot Off

    $HardDrive = Get-VMHardDiskDrive -VMName $VM.Name

    Set-VMFirmware -VMName $VM.Name -BootOrder $HardDrive

    # Iniciar VM

    Start-VM -Name $VM.Name

    Start-Sleep -Seconds 10

}

Geeknetic Cómo Automatizar un Clúster de Kubernetes en Hyper-V con PowerShell 10

 

# ========================

# VALIDACIÓN DE RED

# Espera 60 segundos para obtener IP

# ========================

Write-Host "Esperando que las VMs obtengan IP..."

Start-Sleep -Seconds 60

Write-Host "Comprobando IPs de las VMs..."

foreach ($VM in $VMs) {

    $VMIP = (Get-VMNetworkAdapter -VMName $VM.Name).IPAddresses

    if ($VMIP) {

        Write-Host "$($VM.Name) tiene la IP: $VMIP"

    } else {

        Write-Host "ERROR: $($VM.Name) sigue sin IP."

    }

}

Geeknetic Cómo Automatizar un Clúster de Kubernetes en Hyper-V con PowerShell 11

 

     # ========================

    # VALIDACIÓN DE CLOUD-INIT Y SSH

    # ========================

    Write-Host "Esperando que Cloud-Init termine en $($VM.Name)..."

    Start-Sleep -Seconds 120  # Espera inicial antes de validar

    

    Write-Host "Verificando conectividad con ${VM.IP}..."

    $pingTest = Test-Connection -ComputerName $VM.IP -Count 2 -Quiet

    if (-not $pingTest) {

        Write-Host "No se pudo hacer ping a ${VM.IP}. Revisa la configuración de red."

        continue

    }

    Write-Host "Intentando acceso SSH a $($VM.Name) en ${VM.IP}..."

    for ($i=1; $i -le 5; $i++) {

        $SSHTest = ssh -o "StrictHostKeyChecking=no" -o "ConnectTimeout=5" "$Username@${VM.IP}" "echo 'SSH funcionando'"

        if ($SSHTest -match "SSH funcionando") {

            Write-Host "SSH funcionando en $($VM.Name)."

            break

        } else {

            Write-Host "Intento $i No se pudo acceder por SSH a $($VM.Name). Reintentando..."

            Start-Sleep -Seconds 10

        }

    }

}

Geeknetic Cómo Automatizar un Clúster de Kubernetes en Hyper-V con PowerShell 12

# ========================

# VALIDACIÓN DE CLUSTER KUBERNETES

# Validamos que el cluster Kubernetes está bien creado

# ========================

Write-Host "Validando el clúster Kubernetes..."

$MasterVM = "K8S-Master"

$K8SStatus = Invoke-Command -VMName $MasterVM -ScriptBlock {

    if (Test-Path "/etc/kubernetes/admin.conf") {

        $Status = kubectl get nodes --no-headers | ForEach-Object { $_ -match ' Ready ' }

        if ($Status) {

            return "OK"

        } else {

            return "ERROR"

        }

    } else {

        return "ERROR"

    }

}

if ($K8SStatus -eq "OK") {

    Write-Host "Kubernetes está funcionando correctamente en el nodo master."

} else {

    Write-Host "ERROR: Kubernetes no está correctamente configurado en el nodo master."

}

Write-Host "¡Clúster Kubernetes desplegado exitosamente!"

Geeknetic Cómo Automatizar un Clúster de Kubernetes en Hyper-V con PowerShell 13

Ejecución Script Powershell

Ejecuta PowerShell como administrador y lanza el script de la siguiente forma:

Set-ExecutionPolicy Bypass -Scope Process -Force

O lanzamos la aplicación Powershell_ISE o la consola de Powershell como administrador:

Geeknetic Cómo Automatizar un Clúster de Kubernetes en Hyper-V con PowerShell 14

Ejecutamos script, que irá haciendo varias validaciones:

.\Deploy-KubernetesCluster.ps1

Geeknetic Cómo Automatizar un Clúster de Kubernetes en Hyper-V con PowerShell 15

Geeknetic Cómo Automatizar un Clúster de Kubernetes en Hyper-V con PowerShell 16

Veremos como se van generando cada fichero de cloud-init:

Geeknetic Cómo Automatizar un Clúster de Kubernetes en Hyper-V con PowerShell 17

Si todo ha ido correctamente, podréis ver las máquinas que irán arrancando una a una y el conmutador virtual creados:

Geeknetic Cómo Automatizar un Clúster de Kubernetes en Hyper-V con PowerShell 18

Podremos acceder a cada máquina, ya sea vía SSH como vía consola:

Geeknetic Cómo Automatizar un Clúster de Kubernetes en Hyper-V con PowerShell 19

Y comprobar el estado de los nodos:

kubernetes@K8S-Master:~$ kubectl get node
 NAME STATUS ROLES AGE VERSION
 K8S-Master Ready master 6d v1.32.115
 K8S-Worker1 Ready 7m7s v1.32.115
 K8S-Worker2 Ready 6d v1.32.115

 

Conclusión: La automatización de procesos ahorra trabajo y fallos

La automatización de procesos permite optimizar el tiempo y reducir la posibilidad de errores humanos. Al implementar soluciones automatizadas, se mejora la eficiencia, se minimizan fallos y se garantiza una mayor precisión en las tareas repetitivas. Esto no solo ahorra trabajo, sino que también facilita la gestión y el mantenimiento de sistemas complejos.

Fin del Artículo. ¡Cuéntanos algo en los Comentarios!

Redactor del Artículo: Raúl Unzué

Raúl Unzué

Soy un apasionado de la virtualización con más de 20 años de experiencia, especializado en soluciones como VMware(premio vExpert y vExpert Pro desde 2013), Proxmox e Hyper-V. Durante mi carrera, he ayudado a empresas a optimizar sus infraestructuras TI mientras comparto mis conocimientos como redactor IT. Mi objetivo es traducir lo complejo en algo práctico y accesible, combinando teoría con experiencia real. Si te interesa la virtualización, las herramientas TI o simplemente aprender algo nuevo, espero ayudarte con mis artículos.