Terraform Azure AKS: Guía Completa de Kubernetes 2025

Terraform Azure AKS - Gestión de clústeres Kubernetes en Microsoft Azure con infraestructura como código

Terraform Azure AKS es la solución definitiva para desplegar y gestionar clústeres de Kubernetes en Microsoft Azure mediante infraestructura como código. En esta guía completa aprenderás a provisionar Azure Kubernetes Service (AKS) de forma automatizada, escalable y reproducible, siguiendo las mejores prácticas de DevOps e Infrastructure as Code en 2025.

Azure Kubernetes Service es el servicio de Kubernetes completamente gestionado de Microsoft Azure, y combinarlo con Terraform te permite versionar tu infraestructura cloud, replicar entornos consistentemente, y mantener un control total sobre tu stack de contenedores. Si también trabajas con otros servicios autohospedados, te recomendamos explorar nuestra guía de Docker Compose para complementar tu arquitectura.

¿Qué es Terraform?

Terraform es la herramienta líder de Infrastructure as Code (IaC) desarrollada por HashiCorp que permite definir, provisionar y gestionar recursos cloud mediante archivos de configuración declarativos. A diferencia de scripts imperativos, con esta herramienta describes el estado final deseado y el motor se encarga de alcanzarlo automáticamente.

Las principales ventajas son:

  • Multi-cloud: Funciona con AWS, Azure, GCP, y más de 3000 providers
  • Declarativo: Defines qué quieres, no cómo conseguirlo
  • Versionable: El código IaC se almacena en Git
  • Idempotente: Ejecutas múltiples veces con el mismo resultado
  • Plan de ejecución: Previsualizas cambios antes de aplicarlos
  • State management: Mantiene seguimiento del estado de tu infraestructura

En 2025, el provider azurerm tiene más de 1.8 mil millones de descargas, siendo el segundo más popular después de AWS. El 90% de empresas enterprise usan 3 o más cloud providers simultáneamente, y esta solución IaC facilita la gestión multi-cloud.

¿Qué es Azure Kubernetes Service (AKS)?

Azure Kubernetes Service (AKS) es el servicio administrado de Kubernetes en Microsoft Azure que simplifica el despliegue, gestión y operaciones de clústeres Kubernetes. Microsoft se encarga del control plane (API server, scheduler, etcd), mientras tú gestionas los nodos worker.

Características principales de AKS:

  • Control plane gratuito: Solo pagas por los nodos worker (VMs)
  • Actualizaciones automáticas: Microsoft gestiona parches de seguridad de Kubernetes
  • Escalado automático: Cluster autoscaler y horizontal pod autoscaler integrados
  • Integración Azure: Azure Active Directory, Azure Monitor, Azure Policy
  • Networking avanzado: Azure CNI, Kubenet, load balancers integrados
  • Node pools múltiples: Diferentes tipos de VMs para workloads especializados
  • Windows y Linux: Soporte para contenedores Windows y Linux

Terraform Azure AKS: Fundamentos

Cuando utilizas Terraform Azure AKS, trabajas principalmente con dos recursos fundamentales del provider azurerm:

  • azurerm_kubernetes_cluster: Crea el clúster AKS con su configuración base
  • azurerm_kubernetes_cluster_node_pool: Añade node pools adicionales para workloads específicos

El flujo de trabajo típico incluye:

  1. Configurar provider azurerm: Autenticación y versión
  2. Crear Resource Group: Contenedor lógico de recursos
  3. Definir networking: VNet, subnets, NSG (opcional pero recomendado)
  4. Provisionar clúster AKS: Con node pool por defecto
  5. Configurar node pools adicionales: Para diferentes cargas de trabajo
  6. Obtener credenciales: Para kubectl mediante outputs

Requisitos Previos

Antes de comenzar con Terraform Azure AKS, necesitas:

  • Terraform instalado: Versión 1.5 o superior (verifica con terraform version)
  • Azure CLI: Para autenticación (az login)
  • Suscripción Azure activa: Con permisos para crear recursos AKS
  • kubectl instalado: Para interactuar con el clúster
  • Service Principal o Managed Identity: Para autenticación del clúster
  • Editor de código: VS Code con extensión HashiCorp Terraform recomendada

Para configurar Azure CLI:

# Autenticarse en Azure
az login

# Verificar suscripción activa
az account show

# Cambiar suscripción si es necesario
az account set --subscription "NOMBRE_O_ID"

# Crear service principal para Terraform
az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/SUBSCRIPTION_ID"

Guarda las credenciales del service principal (appId, password, tenant) para usarlas en tu configuración.

Configurar Provider AzureRM para Terraform Azure AKS

El primer paso es configurar el provider azurerm. En 2025, la versión más reciente es la 4.54.0, parte de la serie 4.x que incluye mejoras de rendimiento y soporte para las últimas APIs de Azure.

Crea un archivo versions.tf:

terraform {
  required_version = ">= 1.5.0"

  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 4.0"
    }
  }
}

provider "azurerm" {
  features {
    resource_group {
      prevent_deletion_if_contains_resources = false
    }

    key_vault {
      purge_soft_delete_on_destroy    = true
      recover_soft_deleted_key_vaults = true
    }
  }

  # Opcional: usar service principal
  # client_id       = var.client_id
  # client_secret   = var.client_secret
  # tenant_id       = var.tenant_id
  # subscription_id = var.subscription_id
}

El bloque features es obligatorio y permite personalizar comportamientos del provider. Si trabajas con secretos y certificados, también puedes integrar Vaultwarden como gestor de contraseñas seguro.

Crear Clúster Terraform Azure AKS Básico

Vamos a crear un clúster AKS funcional paso a paso siguiendo las mejores prácticas.

Paso 1: Definir Variables

Crea variables.tf:

variable "resource_group_name" {
  description = "Nombre del Resource Group"
  type        = string
  default     = "rg-aks-terraform"
}

variable "location" {
  description = "Región de Azure"
  type        = string
  default     = "East US"
}

variable "cluster_name" {
  description = "Nombre del clúster AKS"
  type        = string
  default     = "aks-cluster-terraform"
}

variable "kubernetes_version" {
  description = "Versión de Kubernetes"
  type        = string
  default     = "1.28.3"
}

variable "node_count" {
  description = "Número de nodos en el default node pool"
  type        = number
  default     = 2
}

variable "vm_size" {
  description = "Tamaño de VM para nodos"
  type        = string
  default     = "Standard_D2s_v3"
}

variable "environment" {
  description = "Entorno (dev, staging, prod)"
  type        = string
  default     = "production"
}

Paso 2: Resource Group

En main.tf, comienza con el resource group:

resource "azurerm_resource_group" "aks" {
  name     = var.resource_group_name
  location = var.location

  tags = {
    Environment = var.environment
    ManagedBy   = "Terraform"
    Project     = "AKS-Demo"
  }
}

Paso 3: Clúster AKS Básico

Ahora el recurso principal para Terraform Azure AKS:

resource "azurerm_kubernetes_cluster" "aks" {
  name                = var.cluster_name
  location            = azurerm_resource_group.aks.location
  resource_group_name = azurerm_resource_group.aks.name
  dns_prefix          = var.cluster_name
  kubernetes_version  = var.kubernetes_version

  # Node pool por defecto (system)
  default_node_pool {
    name                = "system"
    node_count          = var.node_count
    vm_size             = var.vm_size
    os_disk_size_gb     = 30
    os_disk_type        = "Managed"
    type                = "VirtualMachineScaleSets"
    enable_auto_scaling = true
    min_count           = 2
    max_count           = 5

    # Etiquetas para nodos
    node_labels = {
      "nodepool-type" = "system"
      "environment"   = var.environment
      "nodepoolos"    = "linux"
    }

    tags = {
      "nodepool-type" = "system"
    }
  }

  # Managed Identity (recomendado sobre service principal)
  identity {
    type = "SystemAssigned"
  }

  # Configuración de red (kubenet básico)
  network_profile {
    network_plugin    = "kubenet"
    load_balancer_sku = "standard"
    network_policy    = "calico"
  }

  # Azure AD Integration (RBAC)
  azure_active_directory_role_based_access_control {
    managed                = true
    azure_rbac_enabled     = true
  }

  tags = {
    Environment = var.environment
    ManagedBy   = "Terraform"
  }
}

Paso 4: Outputs

Crea outputs.tf para obtener información del clúster:

output "resource_group_name" {
  description = "Nombre del Resource Group"
  value       = azurerm_resource_group.aks.name
}

output "kubernetes_cluster_name" {
  description = "Nombre del clúster AKS"
  value       = azurerm_kubernetes_cluster.aks.name
}

output "cluster_id" {
  description = "ID del clúster AKS"
  value       = azurerm_kubernetes_cluster.aks.id
}

output "kube_config" {
  description = "Configuración kubectl (sensible)"
  value       = azurerm_kubernetes_cluster.aks.kube_config_raw
  sensitive   = true
}

output "client_certificate" {
  description = "Certificado cliente"
  value       = azurerm_kubernetes_cluster.aks.kube_config[0].client_certificate
  sensitive   = true
}

output "host" {
  description = "Endpoint del API server"
  value       = azurerm_kubernetes_cluster.aks.kube_config[0].host
}

output "get_credentials_command" {
  description = "Comando para obtener credenciales kubectl"
  value       = "az aks get-credentials --resource-group ${azurerm_resource_group.aks.name} --name ${azurerm_kubernetes_cluster.aks.name}"
}

Paso 5: Desplegar la Infraestructura

# Inicializar Terraform
terraform init

# Validar sintaxis
terraform validate

# Formatear código
terraform fmt

# Previsualizar cambios
terraform plan

# Aplicar cambios (tiempo estimado: 5-10 minutos)
terraform apply

# Confirmar con 'yes'

El despliegue del clúster tarda aproximadamente 5-10 minutos. Una vez completado, configura kubectl:

# Obtener credenciales
az aks get-credentials --resource-group rg-aks-terraform --name aks-cluster-terraform

# Verificar conectividad
kubectl cluster-info

# Ver nodos
kubectl get nodes

# Ver namespaces
kubectl get namespaces

Node Pools Avanzados en Terraform Azure AKS

Los node pools permiten tener diferentes tipos de VMs para workloads específicos. Por ejemplo, un pool para aplicaciones generales y otro con GPUs para machine learning.

User Node Pool para Aplicaciones

resource "azurerm_kubernetes_cluster_node_pool" "user" {
  name                  = "userpool"
  kubernetes_cluster_id = azurerm_kubernetes_cluster.aks.id
  vm_size              = "Standard_D4s_v3"

  # Auto-scaling
  enable_auto_scaling = true
  min_count          = 1
  max_count          = 10
  node_count         = 3

  # Disk
  os_disk_size_gb = 100
  os_disk_type    = "Managed"

  # Taints para dedicar a workloads específicos
  node_taints = [
    "workload=user:NoSchedule"
  ]

  node_labels = {
    "nodepool-type" = "user"
    "environment"   = var.environment
    "workload"      = "applications"
  }

  tags = {
    "nodepool-type" = "user"
    "purpose"       = "applications"
  }
}

Node Pool con Spot Instances (Ahorro de Costos)

resource "azurerm_kubernetes_cluster_node_pool" "spot" {
  name                  = "spot"
  kubernetes_cluster_id = azurerm_kubernetes_cluster.aks.id
  vm_size              = "Standard_D2s_v3"

  # Spot instances para cargas interrumpibles
  priority        = "Spot"
  eviction_policy = "Delete"
  spot_max_price  = -1  # Precio máximo del mercado

  enable_auto_scaling = true
  min_count          = 0
  max_count          = 5

  # Taint para que solo pods tolerantes se ejecuten aquí
  node_taints = [
    "kubernetes.azure.com/scalesetpriority=spot:NoSchedule"
  ]

  node_labels = {
    "kubernetes.azure.com/scalesetpriority" = "spot"
    "nodepool-type"                         = "spot"
  }
}

Los Spot Instances pueden ahorrar hasta 80% en costos para cargas de trabajo tolerantes a interrupciones como batch processing o CI/CD.

Networking Avanzado con Terraform Azure AKS

Para entornos de producción, Azure CNI con networking personalizado es recomendado.

VNet y Subnets Dedicadas

resource "azurerm_virtual_network" "aks" {
  name                = "vnet-aks-terraform"
  location            = azurerm_resource_group.aks.location
  resource_group_name = azurerm_resource_group.aks.name
  address_space       = ["10.1.0.0/16"]

  tags = {
    Environment = var.environment
  }
}

resource "azurerm_subnet" "aks_nodes" {
  name                 = "subnet-aks-nodes"
  resource_group_name  = azurerm_resource_group.aks.name
  virtual_network_name = azurerm_virtual_network.aks.name
  address_prefixes     = ["10.1.0.0/20"]
}

resource "azurerm_subnet" "aks_pods" {
  name                 = "subnet-aks-pods"
  resource_group_name  = azurerm_resource_group.aks.name
  virtual_network_name = azurerm_virtual_network.aks.name
  address_prefixes     = ["10.1.16.0/20"]
}

Clúster AKS con Azure CNI

resource "azurerm_kubernetes_cluster" "aks_advanced" {
  name                = var.cluster_name
  location            = azurerm_resource_group.aks.location
  resource_group_name = azurerm_resource_group.aks.name
  dns_prefix          = var.cluster_name
  kubernetes_version  = var.kubernetes_version

  default_node_pool {
    name                = "system"
    node_count          = var.node_count
    vm_size             = var.vm_size
    vnet_subnet_id      = azurerm_subnet.aks_nodes.id
    enable_auto_scaling = true
    min_count           = 2
    max_count           = 5

    # Pod subnet para Azure CNI Overlay
    pod_subnet_id = azurerm_subnet.aks_pods.id
  }

  identity {
    type = "SystemAssigned"
  }

  network_profile {
    network_plugin    = "azure"
    network_policy    = "azure"
    load_balancer_sku = "standard"

    # Rangos de IPs
    service_cidr       = "10.2.0.0/16"
    dns_service_ip     = "10.2.0.10"
  }

  # Integración con Azure Monitor
  oms_agent {
    log_analytics_workspace_id = azurerm_log_analytics_workspace.aks.id
  }
}

Monitoreo y Observabilidad

Integra Azure Monitor para observabilidad completa:

resource "azurerm_log_analytics_workspace" "aks" {
  name                = "log-aks-terraform"
  location            = azurerm_resource_group.aks.location
  resource_group_name = azurerm_resource_group.aks.name
  sku                 = "PerGB2018"
  retention_in_days   = 30

  tags = {
    Environment = var.environment
  }
}

resource "azurerm_log_analytics_solution" "aks" {
  solution_name         = "ContainerInsights"
  location              = azurerm_resource_group.aks.location
  resource_group_name   = azurerm_resource_group.aks.name
  workspace_resource_id = azurerm_log_analytics_workspace.aks.id
  workspace_name        = azurerm_log_analytics_workspace.aks.name

  plan {
    publisher = "Microsoft"
    product   = "OMSGallery/ContainerInsights"
  }
}

Para monitoreo externo de disponibilidad de servicios, también puedes complementar con Uptime Kuma como herramienta de monitoreo adicional.

Seguridad en Terraform Azure AKS

Network Security Group (NSG)

resource "azurerm_network_security_group" "aks" {
  name                = "nsg-aks-terraform"
  location            = azurerm_resource_group.aks.location
  resource_group_name = azurerm_resource_group.aks.name

  security_rule {
    name                       = "AllowKubernetesAPI"
    priority                   = 100
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = "443"
    source_address_prefix      = "YOUR_IP/32"  # Restringir a tu IP
    destination_address_prefix = "*"
  }
}

resource "azurerm_subnet_network_security_group_association" "aks" {
  subnet_id                 = azurerm_subnet.aks_nodes.id
  network_security_group_id = azurerm_network_security_group.aks.id
}

Azure Policy para AKS

resource "azurerm_kubernetes_cluster" "aks_secure" {
  # ... configuración anterior ...

  # Azure Policy Add-on
  azure_policy_enabled = true

  # Pod Security Policy (deprecated en K8s 1.25+, usar Pod Security Standards)
  # Usar Azure Policy en su lugar

  # Key Vault Secrets Provider
  key_vault_secrets_provider {
    secret_rotation_enabled  = true
    secret_rotation_interval = "2m"
  }
}

Private Cluster

Para máxima seguridad, habilita private cluster:

resource "azurerm_kubernetes_cluster" "aks_private" {
  # ... configuración anterior ...

  private_cluster_enabled = true

  # Private DNS Zone personalizada (opcional)
  private_dns_zone_id = azurerm_private_dns_zone.aks.id
}

Módulo Oficial de Terraform Azure AKS

Para simplificar, usa el módulo oficial de Azure:

module "aks" {
  source  = "Azure/aks/azurerm"
  version = "~> 9.0"

  resource_group_name = azurerm_resource_group.aks.name
  location            = azurerm_resource_group.aks.location
  cluster_name        = var.cluster_name
  kubernetes_version  = var.kubernetes_version

  # Node pool por defecto
  agents_count        = 2
  agents_size         = "Standard_D2s_v3"
  agents_pool_name    = "system"

  # Networking
  network_plugin     = "azure"
  vnet_subnet_id     = azurerm_subnet.aks_nodes.id

  # Identity
  identity_type = "SystemAssigned"

  # RBAC
  rbac_aad                          = true
  rbac_aad_managed                  = true
  rbac_aad_azure_rbac_enabled       = true

  # Monitoreo
  log_analytics_workspace_enabled = true

  tags = {
    Environment = var.environment
    ManagedBy   = "Terraform"
  }
}

Este módulo encapsula mejores prácticas y reduce significativamente el código boilerplate.

CI/CD con Terraform Azure AKS

Integra con Azure DevOps o GitHub Actions para despliegues automatizados:

GitHub Actions Workflow

name: 'Terraform AKS Deploy'

on:
  push:
    branches:
      - main
  pull_request:

jobs:
  terraform:
    runs-on: ubuntu-latest

    env:
      ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
      ARM_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
      ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
      ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: 1.6.0

      - name: Terraform Init
        run: terraform init

      - name: Terraform Plan
        run: terraform plan -out=tfplan

      - name: Terraform Apply
        if: github.ref == 'refs/heads/main'
        run: terraform apply -auto-approve tfplan

State Management Remoto

Para equipos, almacena el state en Azure Storage:

terraform {
  backend "azurerm" {
    resource_group_name  = "rg-terraform-state"
    storage_account_name = "sttfstateaks123"  # Debe ser único globalmente
    container_name       = "tfstate"
    key                  = "aks.terraform.tfstate"

    # State locking automático con Azure Storage
  }
}

Crear la infraestructura de backend:

# Crear resource group
az group create --name rg-terraform-state --location eastus

# Crear storage account
az storage account create \
  --name sttfstateaks123 \
  --resource-group rg-terraform-state \
  --location eastus \
  --sku Standard_LRS \
  --encryption-services blob

# Crear container
az storage container create \
  --name tfstate \
  --account-name sttfstateaks123

Optimización de Costos

  • Spot Instances: Ahorro de hasta 80% para workloads tolerantes a interrupciones
  • Auto-scaling: Escala a cero nodos user cuando no hay carga
  • Reserved Instances: Descuentos de hasta 72% con compromiso de 1-3 años
  • Azure Hybrid Benefit: Usa licencias Windows/SQL existentes
  • Tamaños VM apropiados: B-series para dev/test, D-series para producción
  • Shut down dev clusters: Detén clústeres fuera de horario laboral
  • Monitoreo de costos: Azure Cost Management + Alerts

Ejemplo de auto-scaling agresivo para dev:

default_node_pool {
  name                = "system"
  enable_auto_scaling = true
  min_count           = 1  # Mínimo permitido para system pool
  max_count           = 3
  vm_size             = "Standard_B2s"  # Burstable para dev
}

Troubleshooting Común

Error: «Insufficient Regional Quota»

Causa: Tu suscripción no tiene suficiente cuota de vCPUs en la región.

Solución:

# Ver cuotas actuales
az vm list-usage --location eastus --output table

# Solicitar aumento en Azure Portal: Support → New Support Request

Error: «AuthorizationFailed»

Causa: El service principal o managed identity no tiene permisos.

Solución:

# Asignar rol Contributor
az role assignment create \
  --assignee APP_ID \
  --role Contributor \
  --scope /subscriptions/SUBSCRIPTION_ID

Error: «PodSubnetIDNotDelegated»

Causa: La subnet de pods requiere delegación específica.

Solución:

resource "azurerm_subnet" "aks_pods" {
  name                 = "subnet-aks-pods"
  resource_group_name  = azurerm_resource_group.aks.name
  virtual_network_name = azurerm_virtual_network.aks.name
  address_prefixes     = ["10.1.16.0/20"]

  delegation {
    name = "aks-delegation"

    service_delegation {
      name = "Microsoft.ContainerService/managedClusters"
      actions = [
        "Microsoft.Network/virtualNetworks/subnets/join/action"
      ]
    }
  }
}

Debugging con TF_LOG

export TF_LOG=DEBUG
export TF_LOG_PATH=./terraform-debug.log
terraform apply

FAQ sobre Terraform Azure AKS

¿Cuánto cuesta un clúster AKS con Terraform?

El control plane de AKS es gratuito. Solo pagas por las VMs de los nodos. Un clúster básico con 2 nodos Standard_D2s_v3 (2 vCPU, 8GB RAM) cuesta aproximadamente $140/mes en región East US. Los Spot Instances pueden reducir esto hasta $28/mes.

¿Terraform Azure AKS vs Azure Portal vs Azure CLI?

El código de esta herramienta IaC es versionable, reproducible, y permite peer reviews. Azure Portal es útil para exploración inicial, pero no escala para múltiples entornos. Azure CLI es scriptable pero imperativo y no mantiene state. Para producción, siempre usa Infrastructure as Code.

¿Cómo actualizo la versión de Kubernetes?

Cambia kubernetes_version en tu configuración y ejecuta terraform apply. AKS realizará un rolling update sin downtime. Siempre verifica versiones soportadas con az aks get-versions --location eastus.

¿Puedo usar Terraform para desplegar aplicaciones en AKS?

Sí, usando el provider de Kubernetes puedes gestionar deployments, services, configmaps, etc. Sin embargo, para aplicaciones complejas, considera Helm o ArgoCD para GitOps. Si trabajas con aplicaciones de automatización del hogar, también puedes integrar Home Assistant en tu cluster.

¿Debo usar kubenet o Azure CNI?

Kubenet es más simple y consume menos IPs (NAT para pods). Azure CNI asigna IPs de la VNet directamente a pods, necesario para integración con Azure Firewall, Private Link, o comunicación directa pod-to-VM. Para producción enterprise, Azure CNI es recomendado.

Conclusión

Dominar Terraform Azure AKS te permite gestionar clústeres Kubernetes en Azure de forma automatizada, escalable y reproducible. Con Infrastructure as Code, mantienes consistencia entre entornos, facilitas colaboración mediante Git, y reduces errores humanos en configuraciones complejas.

Los próximos pasos recomendados incluyen:

Recuerda siempre ejecutar terraform plan antes de apply, usar backends remotos para state management, y documentar tus decisiones arquitectónicas. Para proyectos de IA local que puedan ejecutarse en tu cluster, también considera explorar Ollama con Docker Compose.

Recursos Adicionales

Avatar

Por Mid

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x