Problema
En clústers de Azure Kubernetes Service (AKS) que ejecutan workloads con imágenes de contenedor grandes o numerosas, el proceso de node provisioning suele convertirse en un cuello de botella. Cada nuevo nodo descarga las imágenes desde un registro remoto durante su arranque, lo que genera latencias de varios minutos y, en entornos con escalado automático, puede provocar picos de tiempo de respuesta inaceptables. El problema se repite en pipelines CI/CD que crean nodos temporales para pruebas de integración o en despliegues de batch jobs que requieren cientos de nodos en pocos minutos.
Causa
Los factores que disparan este comportamiento son:
- Descarga síncrona de imágenes – Por defecto, los nodos AKS obtienen las imágenes al iniciar los pods. Si el registro está en otra región o el ancho de banda es limitado, la descarga se vuelve lenta.
- Ausencia de pre‑caching – Sin una estrategia de pre‑carga, cada nodo repite la misma descarga, duplicando el tráfico de red y la carga del registro.
- Scripts de configuración post‑provisionamiento – Cuando los nodos necesitan ejecutar scripts de init (instalación de agentes, certificados, etc.) después de arrancar, el tiempo total de disponibilidad aumenta.
- Escalado rápido – En escenarios de burst scaling, la creación simultánea de varios nodos multiplica el efecto anterior.
Solución
Azure introdujo la Prepared Image Specification (PIS) para AKS. La idea es crear una imagen de nodo personalizada que ya incluye:
- Todas las capas de las imágenes de contenedor requeridas.
- Scripts de inicialización que se ejecutan al primer arranque.
- Configuraciones de agente de monitorización, políticas de seguridad y cualquier otro binario necesario.
Al usar PIS, el nodo arranca con todo listo; solo necesita registrarse en el clúster. El proceso de aprovisionamiento se reduce de minutos a decenas de segundos.
Pasos generales
- Inventariar imágenes – Lista las imágenes que tus workloads usan con sus tags exactos. Incluye versiones de base y cualquier side‑car.
- Crear un archivo de especificación – Un JSON o YAML que describe los contenidos y los scripts de init. Cada entrada indica la URL del registro y la ruta de destino en la imagen.
- Construir la imagen preparada – Usa Azure CLI o Azure PowerShell para lanzar una VM temporal que actúe como builder. Dentro, ejecuta
docker pullpara cada imagen y copia los artefactos al sistema de archivos de la VM. Luego, crea una imagen de disco administrada. - Registrar la PIS en AKS – Asocia la imagen preparada a un node pool mediante la propiedad
nodeImageVersiono el recursoMicrosoft.ContainerService/managedClusters/agentPools/preparedImageSpecifications. - Actualizar el clúster – Aplica la nueva configuración. AKS usará la imagen preparada para cualquier nodo nuevo que se cree en ese pool.
Detalles de la especificación
apiVersion: "2023-09-01"
kind: PreparedImageSpecification
metadata:
name: my-aks-prepared-image
spec:
baseImage: "Canonical:UbuntuServer:20_04-lts-gen2:latest"
containerImages:
- registry: myregistry.azurecr.io
repository: backend/api
tag: v2.4.1
- registry: myregistry.azurecr.io
repository: frontend/web
tag: v1.9.0
initScripts:
- name: install-azure-monitor
path: /opt/scripts/install-azure-monitor.sh
content: |
#!/bin/bash
curl -sL https://aka.ms/InstallAzureMonitorAgent | bash
- name: configure-ssh
path: /etc/ssh/sshd_config
content: |
PermitRootLogin no
PasswordAuthentication no
En la práctica, el bloque containerImages permite a AKS pre‑cargar cada capa, mientras que initScripts se ejecuta una sola vez al arranque del nodo.
Cuándo aplicar esta solución
Aplica PIS cuando:
- El clúster tiene workloads con imágenes > 200 MB o más de 5 imágenes distintas por pod.
- Se utiliza cluster autoscaler con escalado rápido (más de 10 nodos en menos de 5 min).
- Los nodos deben cumplir políticas de configuración (agentes de monitorización, certificados) antes de ejecutar pods.
- El registro de contenedores está en una región distinta o tiene limitaciones de ancho de banda.
No es necesario si:
- Los workloads usan imágenes ligeras (< 50 MB) y el registro está en la misma región.
- El clúster es estático y no escala frecuentemente.
- El proceso de despliegue tolera varios minutos de tiempo de arranque.
Código
# 1. Crear grupo de recursos temporal para el builder
az group create --name aks-prep-builder-rg --location eastus
# 2. Lanzar VM de builder (Ubuntu 20.04 LTS)
az vm create \
--resource-group aks-prep-builder-rg \
--name prep-builder \
--image UbuntuLTS \
--size Standard_D4s_v3 \
--admin-username azureuser \
--generate-ssh-keys
# 3. Copiar la especificación al builder
scp prepared-image-spec.yaml azureuser@$(az vm show -g aks-prep-builder-rg -n prep-builder -d --query publicIps -o tsv):~/prepared-image-spec.yaml
# 4. Ejecutar script de construcción (asume que tienes un script build-prepared-image.sh)
ssh azureuser@$(az vm show -g aks-prep-builder-rg -n prep-builder -d --query publicIps -o tsv) \
'bash ~/build-prepared-image.sh ~/prepared-image-spec.yaml'
# 5. Registrar la imagen preparada en AKS (suponiendo que el script sube la imagen a una Managed Disk)
az aks nodepool update \
--resource-group myAksRg \
--cluster-name myAksCluster \
--name nodepool1 \
--node-image-version my-prepared-image-v1
Verificación
-
Inspeccionar el nodo recién creado
kubectl get nodes -o wide | grep <node-name>Verifica que el campo
OS Imagemuestra el nombre de la imagen preparada. -
Comprobar que las imágenes están presentes
ssh azureuser@<node-ip> "docker images | grep backend/api"La salida debe listar la capa de la imagen sin necesidad de descargarla.
-
Ejecutar un pod de prueba
apiVersion: v1 kind: Pod metadata: name: test-pod spec: containers: - name: api image: myregistry.azurecr.io/backend/api:v2.4.1Aplica el manifiesto y observa que el pod pasa a
Runningen menos de 10 s. -
Revisar logs de init scripts
kubectl logs <node-name> -n kube-system -l component=azure-monitorConfirma que los scripts de inicialización se ejecutaron sin errores.
Notas adicionales
- Actualizaciones de imágenes – Cuando una imagen de contenedor se actualiza, recrea la PIS. Automatiza el proceso con un pipeline que detecte cambios de tag y regenere la especificación.
- Tamaño de la imagen preparada – Cada capa adicional incrementa el tamaño del VHD. Monitorea el uso de almacenamiento para evitar costos inesperados.
- Seguridad – Los scripts de init se ejecutan con privilegios de root. Asegúrate de validar su contenido y de firmar los archivos antes de incluirlos en la especificación.
- Compatibilidad con zonas – Si tu clúster está distribuido en varias zonas, crea una PIS por zona o usa una imagen que sea compatible con todas ellas.
- Rollback rápido – Mantén una versión anterior de la PIS disponible. En caso de que una actualización cause problemas, puedes volver a asignar la versión anterior al node pool sin recrear el clúster.