Bicep 模块

通过使用 Bicep,可将部署组织到模块中。 模块是另一个 Bicep 文件部署的 Bicep 文件。 模块也可以是 JSON 的 Azure 资源管理器模板(ARM 模板)。 使用模块,可以通过封装部署的复杂细节来改善 Bicep 文件的可读性。 你还可以轻松地将模块重用于不同的部署。

要与组织中的其他人共享模块,请创建模板规格专用注册表。 只有拥有正确权限的用户才能使用模板规格和注册表中的模块。

提示

在模块注册表和模板规格之间进行的选择主要取决于偏好。 在两者之间进行选择时,需要考虑一些事项:

  • 只有 Bicep 支持模块注册表。 如果未使用 Bicep,请使用模板规格。
  • 只能从另一个 Bicep 文件在 Bicep 模块注册表中部署内容。 可以直接从 API、Azure PowerShell、Azure CLI 和 Azure 门户部署模板规格。 甚至可以使用 UiFormDefinition 来自定义门户部署体验。
  • 通过使用 loadTextContentloadFileAsBase64 函数,Bicep 在嵌入其他项目工件(包括非 Bicep 和非 ARM 模板文件,如 PowerShell 脚本、CLI 脚本和其他二进制文件)方面具有一些有限的功能。 模板规格无法打包这些工件。

Bicep 模块将转换为包含嵌套模板的单个 ARM 模板。 要详细了解 Bicep 如何解析配置文件以及 Bicep 如何将用户定义的配置文件与默认配置文件合并,请参阅配置文件解析过程配置文件合并过程

定义模块

用于定义模块的基本语法是:

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

下面是一个简单的真实例子:

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

还可以使用适用于 JSON 的 ARM 模板来作为模块:

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

使用符号名称引用 Bicep 文件另一部分中的模块。 例如,可以使用符号名称来获取模块的输出。 符号名称可以包含 a-z、A-Z、0-9 和下划线 (_)。 名称不能以数字开头。 模块不能与参数、变量或资源同名。

路径可以是本地文件,也可以是注册表中的文件。 本地文件可以是 Bicep 文件或是适用于 JSON 的 ARM 模板。 有关详细信息,请参阅模块的路径

name 属性是必需的。 它将成为生成的模板中嵌套部署资源的名称。

如果将具有静态名称的模块同时部署到同一范围,那么其中一个部署可能会干扰来自另一个部署的输出。 例如,如果两个 Bicep 文件使用具有相同静态名称 (examplemodule) 的同一模块并且面向同一资源组,则其中一个部署可能会显示错误的输出。 如果担心并发部署到同一范围内,请为模块指定唯一名称。

以下示例将部署名称连接到模块名称。 如果为部署提供唯一名称,那么模块名称也是唯一的。

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

如果需要指定一个与主文件范围不同的范围,请添加 scope 属性。 有关详细信息,请参阅设置模块范围

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

若要有条件地部署模块,请添加 if 表达式。 用法类似于有条件地部署资源

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

若要部署一个模块的多个实例,请添加 for 表达式。 可以使用 batchSize 修饰器指定是串行部署实例还是并行部署实例。 有关详细信息,请参阅 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>
  }
}]

与资源一样,模块会并行部署,除非它们依赖于其他模块或资源。 通常无需设置依赖项,因为它们是隐式确定的。 如果需要设置显式依赖项,请在模块定义中添加 dependsOn。 若要了解有关依赖项的详细信息,请参阅资源依赖项

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

模块的路径

模块的文件可以是本地文件,也可以是外部文件。 外部文件可以在模板规格或 Bicep 模块注册表中。

本地文件

如果模块是本地文件,请提供该文件的相对路径。 必须通过使用正斜杠 (/) 目录分隔符来指定 Bicep 中的所有路径,以确保跨平台编译时的一致性。 不支持 Windows 反斜杠 (\) 字符。 路径可以包含空格。

例如,要从主文件部署目录中的上一级的文件,请使用:

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

注册表中的文件

有公共和专用模块注册表。

公共模块注册表

注意

非 Azure Verified Modules 将从公共模块注册表中停用。

Azure Verified Modules 是预生成、预测试和预先验证的模块,可以使用它们在 Azure 上部署资源。 Microsoft 员工创建并拥有这些模块。 它们旨在简化和加速常见 Azure 资源和配置的部署流程。 这些模块还与 Azure 架构良好的框架等最佳做法相一致。

浏览到 Azure 验证模块 Bicep 索引以查看可用的模块列表。 选择以下屏幕截图中突出显示的数字,即可直接进入该筛选视图。

显示 Azure 验证模块的屏幕截图。

模块列表显示最新版本。 选择版本号以查看可用版本列表。

显示 Azure 验证模块版本的屏幕截图。

若要链接到公共模块,请使用以下语法指定模块路径:

module <symbolic-name> 'br/public:<file-path>:<tag>' = {}
  • br/public:是公共模块的别名。 可以在 Bicep 配置文件中自定义此别名。
  • 文件路径:可以包含由 / 字符分隔的段。
  • tag:用于指定模块的版本。

例如:

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

注意

公共模块的别名为 br/public。 也可以将其写为:

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

专用模块注册表

如果已将模块发布到注册表,则可以链接到该模块。 提供 Azure 容器注册表的名称和模块的路径。 使用以下语法指定模块路径:

module <symbolic-name> 'br:<registry-name>.azurecr.cn/<file-path>:<tag>' = {
  • br:是 Bicep 注册表的方案名称。
  • 文件路径:在 Azure 容器注册表中称作 repository。 文件路径可以包含由 / 字符分隔的段。
  • tag:用于指定模块的版本。

例如:

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

引用注册表中的模块时,Visual Studio Code 中的 Bicep 扩展会自动调用 bicep restore,以将外部模块复制到本地缓存。 还原外部模块需要片刻时间。 如果模块的 IntelliSense 没有立即运行,请等待还原完成。

注册表中模块的完整路径可能很长。 在 bicepconfig.json 文件中配置别名,而不是在每次使用模块时都提供完整路径。 使用别名可以更方便地引用模块。 例如,使用别名可将路径缩短为:

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

公共模块注册表有一个预定义的别名:

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

可以替代 bicepconfig.json 文件中的公共别名。

模板规格中的文件

在创建模板规格后,可以在模块中链接到该模板规格。 按以下格式指定模板规格:

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

为了简化 Bicep 文件,可以通过为包含模板规格的资源组创建别名。 使用别名时,语法变为:

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

以下模块部署了用于创建存储帐户的模板规格。 模板规格的订阅和资源组是在名为 ContosoSpecs 的别名中定义的。

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

使用修饰器

修饰器是以格式 @expression 编写的,放置在模块声明上方。 下表显示了模块的可用修饰器。

修饰器 Argument 说明
batchSize 设置实例以按顺序部署。
说明 string 提供模块的说明。

修饰器位于 sys 命名空间中。 如果需要将修饰器与具有相同名称的其他项区分开来,请在修饰器前面加上 sys。 例如,如果 Bicep 文件包含一个名为 description 的参数,则必须在使用 description 修饰器时添加 sys 命名空间。

BatchSize

只能将 @batchSize() 应用于使用 for 表达式的资源或模块定义。

默认情况下,模块会并行部署。 添加 @batchSize(int) 修饰器时,将串行部署实例。

@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}'
  }
}]

有关详细信息,请参阅批量部署

说明

若要添加解释,请将说明添加到模块声明。 例如:

@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}'
  }
}

可以使用 Markdown 格式的文本作为说明文本。

参数

模块定义中提供的参数与 Bicep 文件中的参数匹配。

以下 Bicep 示例有三个参数:storagePrefixstorageSKUlocationstorageSKU 参数有默认值,因此在部署期间不必提供该参数的值。

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

@allowed([
  'Standard_LRS'
  'Standard_GRS'
  'Standard_RAGRS'
  'Premium_LRS'
])
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

若要将前面的示例用作模块,请提供这些参数的值。

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

设置模块范围

在声明模块时,为模块设置的范围应与包含模块的 Bicep 文件的范围不同。 使用 scope 属性设置模块的范围。 未提供 scope 属性时,将在父级的目标范围部署模块。

以下 Bicep 文件将创建一个资源组,并在该资源组中创建一个存储帐户。 该文件将部署到订阅,但模块的作用域限定为新资源组。

// 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

以下示例将存储帐户部署到两个不同的资源组。 这两个资源组都必须已存在。

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: 'chinanorthdeploy'
  scope: firstRG
  params: {
    storagePrefix: 'stg1'
    location: 'chinanorth'
  }
}

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

scope 属性设置为有效的范围对象。 如果 Bicep 文件部署资源组、订阅或管理组,可以将模块的范围设置为该资源的符号名称。 或者,可以使用 scope 函数来获取有效的范围。

这些函数包括:

下面的示例使用 managementGroup 函数来设置范围。

param managementGroupName string

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

输出

可以从模块获取值,并在主 Bicep 文件中使用这些值。 若要从模块获取输出值,请在模块对象上使用 outputs 属性。

第一个示例创建存储帐户并返回主终结点。

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

@allowed([
  'Standard_LRS'
  'Standard_GRS'
  'Standard_RAGRS'
])
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

当属性作为模块使用时,可以获得该输出值。

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
  • 若要将敏感值传递给模块,请使用 getSecret 函数。