Cargando...

Bicep: Crear máquinas virtuales en un conjunto de disponibilidad

En este artículo quiero compartir una plantilla ARM para crear múltiples máquinas virtuales Azure en un conjunto de disponibilidad (availability set). Sí, así como lees, múltiples máquinas, y lo mejor, sin escribir mucho código. Para ello, utilizaremos loops (bucles) en Bicep. Los bucles en Bicep son útiles para definir varias copias de un recurso y evitar repetir la sintaxis en la plantilla. Con esta plantilla, solo debes indicar en un parámetro el número de máquinas que deseas desplegar, y dinámicamente se creará la cantidad de máquinas indicadas, distribuidas en dos subredes diferentes. También, puedes elegir el sistema operativo de forma dinámica, Ubuntu o Windows.

En la siguiente ilustración, puedes ver la topología resultante de la implementación de 4 máquinas virtuales. Usando la plantilla, esto lo tendrás en cuestión de segundos.

Topología de recursos en Azure

Antes de pasar a ver el código, es importante conocer que es availability set o conjunto de disponibilidad.

¿Qué es un conjunto de disponibilidad en Azure?

Al momento de diseñar una arquitectura en la nube, tenemos que pensar en alta disponibilidad, la infraestructura tiene que ser resistente. Un Availability set o conjunto de disponibilidad es una agrupación de máquinas virtuales para proporcionar redundancia a la aplicación. Azure recomienda agregar dos o más máquinas a un availability set. Esto garantiza que, durante un evento de mantenimiento planeado o no planeado, tendremos como mínimo una máquina virtual disponible y en funcionamiento. De esta forma garantizamos la alta disponibilidad, además, de cumplir con el SLA de Azure. El conjunto de disponibilidad indica a Azure Fabric Controller (componente que gestiona los recursos hardware) que las máquinas virtuales que contiene deben distribuirse en diferentes hosts y hardware, evitando así, tener punto de falla único que pueda hacer caer todos los servidores.

Automatizar el aprovisionamiento de máquinas virtuales en Azure con plantillas ARM

Lo primero, crear el archivo con la extensión .bicep. Para este ejemplo, lo he nombrado availavility-set.bicep

Definición de parámetros

En este primer bloque he definido los parámetros que considero necesarios. Puedes ver en la descripción una breve explicación. En el parámetro numberVM se define la cantidad de máquinas a desplegar. Puedes modificar el valor o eliminarlo y hacer que lo solicite al momento de ejecutar la implementación desde la CLI. Con el parámetro sistemaOperativo se le indica que sistema operativo utilizar, en este caso he dejado Ubuntu de forma predeterminada, pero la plantilla está preparada para usar Windows Server 2019 o Ubuntu 21.04 como podrás comprobar en el apartado de las variables.

@description('Nombre de la aplicación o proyecto - Prefijo para el nombre de los recursos')
param resourceName string = 'crashell'

@description('Región para crear los recursos')
param location string = resourceGroup().location

@description('Cantidad de máquinas virtuales a crear')
param numberVM int = 4

@description('Sistema Operativo (Windows o Ubuntu)')
param sistemaOperativo string = 'Ubuntu'

@description('Nombre de usuario para las máquinas virtuales')
param adminUsername string

@description('Contraseña para las máquinas virtuales')
param adminPassword string

Definición de variables

A continuación, la definición de las propiedades de la imagen de referencia para la máquina, tenemos opción de usar Ubuntu 21.04 y Windows Server 2016. Si requieres otro sistema operativo o una imagen personalizada, puedes agregar o modificar los valores correspondientes. También, he definido variables para los nombres de los recursos y demás propiedades que serán reutilizadas dentro de la plantilla.

var imageReference = {
  Ubuntu: {
    publisher: 'Canonical'
    offer: '0001-com-ubuntu-server-hirsute'
    sku: '21_04-gen2'
    version: 'latest'
  }
  Windows: {
    publisher: 'MicrosoftWindowsServer'
    offer: 'WindowsServer'
    sku: '2019-Datacenter'
    version: 'latest'
  }
}

var avSetName       = '${resourceName}-avset'
var vnetName        = '${resourceName}-vnet'
var vnetAddress     = '10.0.0.0/16'
var subnet1Name     = 'subnet1'
var subnet2Name     = 'subnet2'
var subnet1Address  = '10.0.1.0/24'
var subnet2Adress   = '10.0.2.0/24'
var subnet1Ref      = resourceId('Microsoft.Network/virtualNetworks/subnets', vnetName, subnet1Name)
var subnet2Ref      = resourceId('Microsoft.Network/virtualNetworks/subnets', vnetName, subnet2Name)
var vmName          = '${resourceName}-vm'
var vmSize          = 'Standard_B1s'
var nicName         = '${resourceName}-nic'
var envTag          = 'dev'

Cómo crear un conjunto de disponibilidad en Azure con Bicep

El siguiente bloque crea un conjunto de disponibilidad (availability set) con 2 dominios de error y 5 dominios de actualización. Dado que las máquinas virtuales de este grupo tendrán discos administrados, el valor de es sku es Aligned.

resource availavilitySet 'Microsoft.Compute/availabilitySets@2021-07-01' = {
  name: avSetName
  location: location
  properties: {
    platformFaultDomainCount: 2
    platformUpdateDomainCount: 5
  }
  sku: {
    name: 'Aligned'
  }
  tags: {
    Name: resourceName
    env: envTag
  }
}

Crear red virtual en Azure con Bicep

El siguiente bloque crea una red virtual y dos subredes. Todas las propiedades se han definido previamente en variables.

resource vnet 'Microsoft.Network/virtualNetworks@2021-03-01' = {
  name: vnetName
  location: location
  properties: {
    addressSpace: {
      addressPrefixes: [
        vnetAddress
      ]
    }
    subnets: [
      {
        name: subnet1Name
        properties: {
          addressPrefix: subnet1Address
        }
      }
      {
        name: subnet2Name
        properties: {
          addressPrefix: subnet2Adress
        }
      }
    ]
  }
  tags: {
    Name: resourceName
    env: envTag
  }
}

Crear interfaces de red en Azure con Bicep

Al inicio mencioné que reutilizaríamos código para crear recursos. Ha llegado el momento de usar los bucles. Como son varias máquinas virtuales (dependiendo del valor en el parámetro numberVM) se necesita una tarjeta de red para cada servidor. En este bloque se crean las interfaces de red virtuales de forma dinámica, para ello, un típico ciclo for se encarga de iterar desde 0 hasta el número de máquinas. Finalmente, con una condición determina a que subred asociarla, si el número es par se agrega a la subred1, si es impar, se asocia a la subred2.

resource nic 'Microsoft.Network/networkInterfaces@2021-03-01' = [for i in range(0, numberVM): {
  name: '${nicName}-${i}'
  location: location
  properties: {
    ipConfigurations: [ 
      {
        name: 'ipconfig1'
        properties: {
          privateIPAllocationMethod: 'Dynamic'
          subnet: {
            id: (((i % 2) == 0) ? subnet1Ref : subnet2Ref) 
          }
        }
      }
    ]
  }
  dependsOn: [
    vnet
  ]
  tags: {
    Name: resourceName
    env: envTag
  }
}]

Crear máquinas virtuales en Azure con Bicep

En este último bloque se crean todas las máquinas virtuales de forma dinámica, también usando un bucle con la misma funcionalidad que el anterior. Las máquinas se agregan al conjunto de disponibilidad creado previamente. Y lo demás, las propiedades de la máquina, el tamaño, las credenciales de acceso, la imagen de máquina o sistema operativo y la interfaz de red, que también es seleccionada de forma dinámica.

resource vm 'Microsoft.Compute/virtualMachines@2021-07-01' = [for i in range(0, numberVM): {
  name: '${vmName}-${i}'
  location: location
  properties: {
    availabilitySet: {
      id: availavilitySet.id
    }
    hardwareProfile: {
      vmSize: vmSize
    }
    osProfile: {
      computerName: 'VM-${i}'
      adminUsername: adminUsername
      adminPassword: adminPassword
    }
    storageProfile: {
      imageReference: imageReference[sistemaOperativo]
      osDisk: {
        createOption: 'FromImage'
      }
    }
    networkProfile: {
      networkInterfaces: [
        {
          id: resourceId('Microsoft.Network/networkInterfaces', '${nicName}-${i}')
        }
      ]
    }
  }
  dependsOn: [
    availavilitySet
    nic
  ]
  tags: {
    Name: resourceName
    env: envTag
  }
}]

Plantilla completa

A continuación, la plantilla ARM completa para crear máquinas virtuales en un conjunto de disponibilidad de Azure.

@description('Nombre de la aplicación o proyecto - Prefijo para el nombre de los recursos')
param resourceName string = 'crashell'

@description('Región para crear los recursos')
param location string = resourceGroup().location

@description('Cantidad de máquinas virtuales a crear')
param numberVM int = 4

@description('Sistema Operativo (Windows o Ubuntu)')
param sistemaOperativo string = 'Ubuntu'

@description('Nombre de usuario para las máquinas virtuales')
param adminUsername string

@description('Contraseña para las máquinas virtuales')
param adminPassword string

var imageReference = {
  Ubuntu: {
    publisher: 'Canonical'
    offer: '0001-com-ubuntu-server-hirsute'
    sku: '21_04-gen2'
    version: 'latest'
  }
  Windows: {
    publisher: 'MicrosoftWindowsServer'
    offer: 'WindowsServer'
    sku: '2019-Datacenter'
    version: 'latest'
  }
}

var avSetName       = '${resourceName}-avset'
var vnetName        = '${resourceName}-vnet'
var vnetAddress     = '10.0.0.0/16'
var subnet1Name     = 'subnet1'
var subnet2Name     = 'subnet2'
var subnet1Address  = '10.0.1.0/24'
var subnet2Adress   = '10.0.2.0/24'
var subnet1Ref      = resourceId('Microsoft.Network/virtualNetworks/subnets', vnetName, subnet1Name)
var subnet2Ref      = resourceId('Microsoft.Network/virtualNetworks/subnets', vnetName, subnet2Name)
var vmName          = '${resourceName}-vm'
var vmSize          = 'Standard_B1s'
var nicName         = '${resourceName}-nic'
var envTag          = 'dev'

resource availavilitySet 'Microsoft.Compute/availabilitySets@2021-07-01' = {
  name: avSetName
  location: location
  properties: {
    platformFaultDomainCount: 2
    platformUpdateDomainCount: 5
  }
  sku: {
    name: 'Aligned'
  }
  tags: {
    Name: resourceName
    env: envTag
  }
}

resource vnet 'Microsoft.Network/virtualNetworks@2021-03-01' = {
  name: vnetName
  location: location
  properties: {
    addressSpace: {
      addressPrefixes: [
        vnetAddress
      ]
    }
    subnets: [
      {
        name: subnet1Name
        properties: {
          addressPrefix: subnet1Address
        }
      }
      {
        name: subnet2Name
        properties: {
          addressPrefix: subnet2Adress
        }
      }
    ]
  }
  tags: {
    Name: resourceName
    env: envTag
  }
}

resource nic 'Microsoft.Network/networkInterfaces@2021-03-01' = [for i in range(0, numberVM): {
  name: '${nicName}-${i}'
  location: location
  properties: {
    ipConfigurations: [ 
      {
        name: 'ipconfig1'
        properties: {
          privateIPAllocationMethod: 'Dynamic'
          subnet: {
            id: (((i % 2) == 0) ? subnet1Ref : subnet2Ref) 
          }
        }
      }
    ]
  }
  dependsOn: [
    vnet
  ]
  tags: {
    Name: resourceName
    env: envTag
  }
}]

resource vm 'Microsoft.Compute/virtualMachines@2021-07-01' = [for i in range(0, numberVM): {
  name: '${vmName}-${i}'
  location: location
  properties: {
    availabilitySet: {
      id: availavilitySet.id
    }
    hardwareProfile: {
      vmSize: vmSize
    }
    osProfile: {
      computerName: 'VM-${i}'
      adminUsername: adminUsername
      adminPassword: adminPassword
    }
    storageProfile: {
      imageReference: imageReference[sistemaOperativo]
      osDisk: {
        createOption: 'FromImage'
      }
    }
    networkProfile: {
      networkInterfaces: [
        {
          id: resourceId('Microsoft.Network/networkInterfaces', '${nicName}-${i}')
        }
      ]
    }
  }
  dependsOn: [
    availavilitySet
    nic
  ]
  tags: {
    Name: resourceName
    env: envTag
  }
}]

Implementar plantilla ARM desde la CLI

Dinámicamente Es ideal comprobar para encontrar errores y obtener una vista previa de los cambios antes de hacer la implementación. Para ello, ejecuta:

az deployment group create --resource-group CrashellRG --template-file availavility-set.bicep -c

El comando anterior hace la comprobación y pregunta si quieres hacer el deployment. Para hacer la implementación sin hacer una comprobación, ejecuta la siguiente instrucción:

az deployment group create --resource-group CrashellRG --template-file availavility-set.bicep

Cambia CrashellRG por tu grupo de recursos.

Para eliminar todos los recursos creados, la forma más rápida es eliminar el grupo de recursos.

Puedes visitar el repositorio Infraestructura como código en Azure con Bicep para encontrar para encontrar esta plantilla completa y otras más.

  • John Doe
    43 Sales$156,24 Totals
    62%
  • Rosy O'Dowell
    12 Leads$56,24 Totals
    32%

With supporting text below as a natural lead-in to additional content.

Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled.