Módulos de Bicep

Bicep permite organizar las implementaciones en módulos. Un módulo es un archivo Bicep (o una plantilla de Azure Resource Manager JSON) que se implementa desde otro archivo de Bicep. Con los módulos, mejora la legibilidad de los archivos de Bicep mediante la encapsulación de detalles complejos de la implementación. También puede reutilizar fácilmente módulos para distintas implementaciones.

A fin de compartir módulos con otros miembros de su organización, cree una especificación de plantilla o un registro privado. Las especificaciones de plantilla y los módulos del registro solo están disponibles para los usuarios con los permisos correctos.

Sugerencia

La elección entre el registro del módulo y las especificaciones de plantilla es principalmente una cuestión de preferencia. Hay algunas cosas que debe tener en cuenta al elegir entre ambas opciones:

  • Solo Bicep admite el registro de módulos. Si aún no usa Bicep, utilice las especificaciones de plantilla.
  • El contenido del registro del módulo de Bicep solo se puede implementar desde otro archivo Bicep. Las especificaciones de plantilla se pueden implementar directamente desde la API, Azure PowerShell, la CLI de Azure y Azure Portal. Incluso puede usar para UiFormDefinition personalizar la experiencia de implementación del portal.
  • Bicep tiene algunas funcionalidades limitadas para insertar otros artefactos de proyecto (incluidos los archivos de plantilla que no son de Bicep y que no son de ARM. Por ejemplo, scripts de PowerShell, scripts de la CLI y otros archivos binarios) mediante las funciones loadTextContent y loadFileAsBase64. Las especificaciones de plantilla no pueden empaquetar estos artefactos.

Los módulos de Bicep se convierten en una sola plantilla de Azure Resource Manager con plantillas anidadas. Para obtener más información sobre cómo Bicep resuelve los archivos de configuración y cómo Bicep combina el archivo de configuración definido por el usuario con el archivo de configuración predeterminado, consulte Proceso de resolución de archivos de configuración y Proceso de combinación de archivos de configuración.

Recursos de aprendizaje

Para más información sobre los módulos mediante una guía detallada, consulte Creación de archivos Bicep que admiten composición mediante módulos.

Definición de los módulos

La sintaxis básica para definir un módulo es:

@<decorator>(<argument>)
module <symbolic-name> '<path-to-file>' = {
  name: '<linked-deployment-name>'
  params: {
    <parameter-names-and-values>
  }
}

Por lo tanto, un ejemplo sencillo del mundo real tendría un aspecto similar a este:

module stgModule '../storageAccount.bicep' = {
  name: 'storageDeploy'
  params: {
    storagePrefix: 'examplestg1'
  }
}

También puede usar una plantilla ARM JSON como un módulo:

module stgModule '../storageAccount.json' = {
  name: 'storageDeploy'
  params: {
    storagePrefix: 'examplestg1'
  }
}

Use el nombre simbólico para hacer referencia al módulo en otra parte del archivo de Bicep. Por ejemplo, puede usar el nombre simbólico para obtener la salida de un módulo. El nombre simbólico puede contener a-z, A-Z, 0-9 y subrayado (_). No puede empezar con un número. Un módulo no puede tener el mismo nombre que un parámetro, una variable o un recurso.

La ruta de acceso puede ser un archivo local o un archivo en un registro. El archivo local puede ser un archivo de Bicep o una plantilla JSON de ARM. Para más información, consulte Ruta de acceso al módulo.

La propiedad name es obligatoria. Se convierte en el nombre del recurso de implementación anidado en la plantilla generada.

Si un módulo con un nombre estático se implementa simultáneamente en el mismo ámbito, existe la posibilidad de que una implementación interfiera con la salida de la otra implementación. Por ejemplo, si dos archivos de Bicep usan el mismo módulo con el mismo nombre estático (examplemodule) y tienen como destino el mismo grupo de recursos, una implementación podría mostrar la salida incorrecta. Si le preocupan las implementaciones simultáneas en el mismo ámbito, asigne un nombre único al módulo.

En el ejemplo siguiente se concatena el nombre de la implementación en el nombre del módulo. Si proporciona un nombre único para la implementación, el nombre del módulo también es único.

module stgModule 'storageAccount.bicep' = {
  name: '${deployment().name}-storageDeploy'
  scope: resourceGroup('demoRG')
}

Si necesita especificar un ámbito distinto del ámbito del archivo principal, agregue la propiedad correspondiente. Para más información, consulte Establecimiento del ámbito del módulo.

// deploy to different scope
module <symbolic-name> '<path-to-file>' = {
  name: '<linked-deployment-name>'
  scope: <scope-object>
  params: {
    <parameter-names-and-values>
  }
}

A fin de implementar un módulo de manera condicional, agregue una expresión if. El uso es similar a la implementación condicional de un recurso.

// conditional deployment
module <symbolic-name> '<path-to-file>' = if (<condition-to-deploy>) {
  name: '<linked-deployment-name>'
  params: {
    <parameter-names-and-values>
  }
}

Para implementar más de una instancia de un módulo, agregue la expresión for. Puede usar el decorador batchSize para especificar si las instancias se implementan en serie o en paralelo. Para más información, consulte Bucles iterativos en Bicep.

// iterative deployment
@batchSize(int) // optional decorator for serial deployment
module <symbolic-name> '<path-to-file>' = [for <item> in <collection>: {
  name: '<linked-deployment-name>'
  params: {
    <parameter-names-and-values>
  }
}]

Al igual que los recursos, los módulos se implementan en paralelo a menos que dependan de otros módulos o recursos. Normalmente, no es necesario establecer dependencias, ya que se determinan implícitamente. Si necesita establecer una dependencia explícita, puede agregar dependsOn a la definición del módulo. Para más información sobre las dependencias, consulte Dependencias de recursos.

module <symbolic-name> '<path-to-file>' = {
  name: '<linked-deployment-name>'
  params: {
    <parameter-names-and-values>
  }
  dependsOn: [
    <symbolic-names-to-deploy-before-this-item>
  ]
}

Ruta de acceso al módulo

El archivo del módulo puede ser un archivo local o uno externo en un registro. El archivo externo puede estar en una especificación de plantilla o en un registro de módulo Bícep.

Archivo local

Si el módulo es un archivo local, proporcione una ruta de acceso relativa a ese archivo. Todas las rutas de acceso de Bicep deben especificarse mediante el separador de directorios de barra diagonal (/), con el fin de garantizar una compilación coherente entre plataformas. El carácter de barra diagonal inversa de Windows (\) no se admite. Las rutas de acceso pueden contener espacios.

Por ejemplo, para implementar un archivo que está un nivel más arriba del archivo principal en el directorio, utilice:

module stgModule '../storageAccount.bicep' = {
  name: 'storageDeploy'
  params: {
    storagePrefix: 'examplestg1'
  }
}

Archivo en el registro

Registro de módulos públicos

Nota:

Los módulos que no son AVM (módulos comprobados de Azure) se retiran del registro de módulos públicos.

Los módulos comprobados de Azure son módulos precompilados, probados y verificados previamente para implementar recursos en Azure. Creados y propiedad de los empleados de Microsoft, estos módulos están diseñados para simplificar y acelerar el proceso de implementación de configuraciones y recursos comunes de Azure, a la vez que se alinean con los procedimientos recomendados; como el Well-Architected Framework.

Vaya al índice Bicep de módulos comprobados de Azure para ver la lista de módulos disponibles, seleccione los números resaltados en el siguiente recorte de pantalla para ir directamente a esa vista filtrada.

Recorte de pantalla de módulos comprobados de Azure (AVM).

La lista de módulos muestra la versión más reciente. Seleccione el número de versión para ver una lista de las versiones disponibles:

Recorte de pantalla de las versiones de los módulos comprobados de Azure (AVM).

Para crear vínculos a un módulo público, especifique su ruta de acceso mediante la siguiente sintaxis:

module <symbolic-name> 'br/public:<file-path>:<tag>' = {}
  • br/public es el alias de los módulos públicos. Puede personalizar este alias en el archivo de configuración Bicep.
  • La ruta de acceso (file path) del archivo puede contener segmentos separados por el carácter /.
  • tag se usa para especificar una versión del módulo.

Por ejemplo:

module storage 'br/public:avm/res/storage/storage-account:0.9.0' = {
  name: 'myStorage'
  params: {
    name: 'store${resourceGroup().name}'
  }
}

Nota:

br/public es el alias de los módulos públicos. También se puede escribir como:

module <symbolic-name> 'br:mcr.microsoft.com/bicep/<file-path>:<tag>' = {}

Registro de módulos privados

Si ha publicado un módulo en un registro, puede crear un vínculo a ese módulo. Proporcione el nombre del registro de contenedor de Azure y una ruta de acceso al módulo. Especifique la ruta de acceso al módulo con la sintaxis siguiente:

module <symbolic-name> 'br:<registry-name>.azurecr.io/<file-path>:<tag>' = {
  • br es el nombre del esquema de un registro de Bicep.
  • La ruta de acceso al archivo en Azure Container Registry se denomina repository. La ruta de acceso del archivo puede contener segmentos separados por el carácter /.
  • tag se usa para especificar una versión del módulo.

Por ejemplo:

module stgModule 'br:exampleregistry.azurecr.io/bicep/modules/storage:v1' = {
  name: 'storageDeploy'
  params: {
    storagePrefix: 'examplestg1'
  }
}

Cuando se hace referencia a un módulo en un registro, la extensión de Bicep en Visual Studio Code automáticamente llama a bicep restore para copiar el módulo externo en la caché local. El módulo externo tarda unos minutos en restaurarse. Si IntelliSense para el módulo no funciona de inmediato, espere a que se complete la restauración.

La ruta de acceso completa de un módulo en un registro puede ser larga. En lugar de proporcionar la ruta de acceso completa cada vez que desea usar el módulo, puede configurar alias en el archivo bicepconfig.json. Los alias facilitan la referencia al módulo. Por ejemplo, con un alias, puede acortar la ruta de acceso a:

module stgModule 'br/ContosoModules:storage:v1' = {
  name: 'storageDeploy'
  params: {
    storagePrefix: 'examplestg1'
  }
}

Se ha predefinido un alias para el registro de módulos públicos:

module storage 'br/public:avm/res/storage/storage-account:0.9.0' = {
  name: 'myStorage'
  params: {
    name: 'store${resourceGroup().name}'
  }
}

Puede invalidar el alias público en el archivo bicepconfig.json.

Archivo en especificación de plantilla

Después de crear una especificación de plantilla, puede vincularla en un módulo. Especifique la especificación de plantilla en el siguiente formato:

module <symbolic-name> 'ts:<sub-id>/<rg-name>/<template-spec-name>:<version>' = {

Sin embargo, puede simplificar el archivo Bicep creando un alias para el grupo de recursos que contiene las especificaciones de plantilla. Al usar un alias, la sintaxis se convierte en:

module <symbolic-name> 'ts/<alias>:<template-spec-name>:<version>' = {

El siguiente módulo implementa una especificación de plantilla para crear una cuenta de almacenamiento. La suscripción y el grupo de recursos para la especificación de plantilla se definen en el alias denominado ContosoSpecs.

module stgModule 'ts/ContosoSpecs:storageSpec:2.0' = {
  name: 'storageDeploy'
  params: {
    storagePrefix: 'examplestg1'
  }
}

Uso de decoradores

Los decoradores se escriben en el formato @expression y se colocan encima de las declaraciones de módulo. La siguiente tabla muestra los decoradores disponibles para los módulos.

Decorador Argumento Descripción
batchSize None Configure instancias para implementarlas secuencialmente.
descripción string Proporcione descripciones para el módulo.

Los decoradores están en el espacio de nombres sys. Si tiene que diferenciar un decorador de otro elemento con el mismo nombre, anteceda el decorador con sys. Por ejemplo, si el archivo de Bicep incluye un parámetro llamado description, debe agregar el espacio de nombres sys al usar el decorador description.

BatchSize

Solo puede aplicar @batchSize() a un recurso o definición de módulo que use una expresión for.

De manera predeterminada, los módulos se implementan en paralelo. Cuando agrega el decorador @batchSize(int), implementa las instancias en serie.

@batchSize(3)
module storage 'br/public:avm/res/storage/storage-account:0.11.1' = [for storageName in storageAccounts: {
  name: 'myStorage'
  params: {
    name: 'store${resourceGroup().name}'
  }
}]

Para más información, consulte Implementación en lotes.

Descripción

Para añadir una explicación, añada una descripción a las declaraciones de módulo. Por ejemplo:

@description('Create storage accounts referencing an AVM.')
module storage 'br/public:avm/res/storage/storage-account:0.9.0' = {
  name: 'myStorage'
  params: {
    name: 'store${resourceGroup().name}'
  }
}

El texto con formato Markdown se puede usar para el texto de descripción.

Parámetros

Los parámetros que proporciona en la definición del módulo coinciden con los parámetros del archivo de Bicep.

El ejemplo de Bicep siguiente tiene tres parámetros: storagePrefix, storageSKU y location. El parámetro storageSKU tiene un valor predeterminado, por lo que no es necesario proporcionar un valor para ese parámetro durante la implementación.

@minLength(3)
@maxLength(11)
param storagePrefix string

@allowed([
  'Standard_LRS'
  'Standard_GRS'
  'Standard_RAGRS'
  'Standard_ZRS'
  'Premium_LRS'
  'Premium_ZRS'
  'Standard_GZRS'
  'Standard_RAGZRS'
])
param storageSKU string = 'Standard_LRS'

param location string

var uniqueStorageName = '${storagePrefix}${uniqueString(resourceGroup().id)}'

resource stg 'Microsoft.Storage/storageAccounts@2023-04-01' = {
  name: uniqueStorageName
  location: location
  sku: {
    name: storageSKU
  }
  kind: 'StorageV2'
  properties: {
    supportsHttpsTrafficOnly: true
  }
}

output storageEndpoint object = stg.properties.primaryEndpoints

Para usar el ejemplo anterior como módulo, proporcione valores para esos parámetros.

targetScope = 'subscription'

@minLength(3)
@maxLength(11)
param namePrefix string

resource demoRG 'Microsoft.Resources/resourceGroups@2024-03-01' existing = {
  name: 'demogroup1'
}

module stgModule '../create-storage-account/main.bicep' = {
  name: 'storageDeploy'
  scope: demoRG
  params: {
    storagePrefix: namePrefix
    location: demoRG.location
  }
}

output storageEndpoint object = stgModule.outputs.storageEndpoint

Establecimiento del ámbito del módulo

Al declarar un módulo, puede establecer un ámbito para el módulo que sea diferente del ámbito del archivo de Bicep que lo contiene. Use la propiedad scope para establecer el ámbito del módulo. Cuando no se proporciona la propiedad scope, el módulo se implementa en el ámbito de destino del elemento primario.

En el archivo de Bicep siguiente se crea un grupo de recursos y una cuenta de almacenamiento en ese grupo. El archivo se implementa en una suscripción, pero el ámbito del módulo es el grupo de recursos nuevo.

// set the target scope for this file
targetScope = 'subscription'

@minLength(3)
@maxLength(11)
param namePrefix string

param location string = deployment().location

var resourceGroupName = '${namePrefix}rg'

resource newRG 'Microsoft.Resources/resourceGroups@2024-03-01' = {
  name: resourceGroupName
  location: location
}

module stgModule '../create-storage-account/main.bicep' = {
  name: 'storageDeploy'
  scope: newRG
  params: {
    storagePrefix: namePrefix
    location: location
  }
}

output storageEndpoint object = stgModule.outputs.storageEndpoint

En el ejemplo siguiente se implementan cuentas de almacenamiento en dos grupos de recursos diferentes. Ambos grupos de recursos ya deben existir.

targetScope = 'subscription'

resource firstRG 'Microsoft.Resources/resourceGroups@2024-03-01' existing = {
  name: 'demogroup1'
}

resource secondRG 'Microsoft.Resources/resourceGroups@2024-03-01' existing = {
  name: 'demogroup2'
}

module storage1 '../create-storage-account/main.bicep' = {
  name: 'westusdeploy'
  scope: firstRG
  params: {
    storagePrefix: 'stg1'
    location: 'westus'
  }
}

module storage2 '../create-storage-account/main.bicep' = {
  name: 'eastusdeploy'
  scope: secondRG
  params: {
    storagePrefix: 'stg2'
    location: 'eastus'
  }
}

Establezca la propiedad scope en un objeto de ámbito válido. Si el archivo Bicep implementa un grupo de recursos, una suscripción o un grupo de administración, puede establecer el ámbito de un módulo en el nombre simbólico de ese recurso. O bien, puede usar las funciones de ámbito para obtener un ámbito válido.

Estas funciones son las siguientes:

En el ejemplo siguiente se usa la función managementGroup para establecer el ámbito.

param managementGroupName string

module mgDeploy 'main.bicep' = {
  name: 'deployToMG'
  scope: managementGroup(managementGroupName)
}

Resultados

Puede obtener valores de un módulo y usarlos en el archivo de Bicep principal. Si desea obtener un valor de salida de un módulo, use la propiedad outputs en el objeto de módulo.

En el primer ejemplo se crea una cuenta de almacenamiento y se devuelven los puntos de conexión principales.

@minLength(3)
@maxLength(11)
param storagePrefix string

@allowed([
  'Standard_LRS'
  'Standard_GRS'
  'Standard_RAGRS'
  'Standard_ZRS'
  'Premium_LRS'
  'Premium_ZRS'
  'Standard_GZRS'
  'Standard_RAGZRS'
])
param storageSKU string = 'Standard_LRS'

param location string

var uniqueStorageName = '${storagePrefix}${uniqueString(resourceGroup().id)}'

resource stg 'Microsoft.Storage/storageAccounts@2023-04-01' = {
  name: uniqueStorageName
  location: location
  sku: {
    name: storageSKU
  }
  kind: 'StorageV2'
  properties: {
    supportsHttpsTrafficOnly: true
  }
}

output storageEndpoint object = stg.properties.primaryEndpoints

Cuando se usa como módulo, puede obtener ese valor de salida.

targetScope = 'subscription'

@minLength(3)
@maxLength(11)
param namePrefix string

resource demoRG 'Microsoft.Resources/resourceGroups@2024-03-01' existing = {
  name: 'demogroup1'
}

module stgModule '../create-storage-account/main.bicep' = {
  name: 'storageDeploy'
  scope: demoRG
  params: {
    storagePrefix: namePrefix
    location: demoRG.location
  }
}

output storageEndpoint object = stgModule.outputs.storageEndpoint

Pasos siguientes