使用 Bicep,可以将部署组织成模块。 模块是由另一个 Bicep 文件部署的 Bicep 文件。 模块也可以是 JSON 的 Azure 资源管理器模板(ARM 模板)。 通过使用模块,你可以将部署的复杂细节封装起来,从而提高 Bicep 文件的可读性。 你还可以轻松地将模块重用于不同的部署。
要与组织中的其他人共享模块,请创建模板规格或专用注册表。 只有拥有正确权限的用户才能使用模板规格和注册表中的模块。
提示
在模块注册表和模板规格之间进行的选择主要取决于偏好。 在两个选项之间进行选择时,请考虑以下几点:
- 仅Bicep支持模块注册表。 如果不使用Bicep,请使用模板规格。
- 只能通过另一个 Bicep 文件部署 Bicep 模块注册表中的内容。 可以直接从 API、Azure PowerShell、Azure CLI 和 Azure 门户部署模板规格。 你甚至可以使用
UiFormDefinition自定义门户部署体验。 - 通过使用
loadTextContent和loadFileAsBase64函数,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 属性为可选。 它将成为生成的模板中嵌套部署资源的名称。 如果未提供名称,则会生成 GUID 作为嵌套部署资源的名称。
如果将具有静态名称的模块同时部署到同一范围,则一个部署可能会干扰另一个部署的输出。 例如,如果两个 Bicep 文件使用具有相同静态名称 (examplemodule) 的同一模块并且面向同一资源组,则其中一个部署可能会显示错误的输出。 如果你担心在同一作用域中进行并发部署,请为你的模块指定一个唯一的名称。 确保唯一模块名称的另一种方法是省略 name 属性,自动生成唯一的模块名称。
no-module-name linter 规则旨在通过标记仍包含显式name属性的任何模块来强制实施这种更简洁的编码做法。
以下示例将部署名称连接到模块名称。 如果为部署提供唯一名称,那么模块名称也是唯一的。
module stgModule 'storageAccount.bicep' = {
name: '${deployment().name}-storageDeploy'
scope: resourceGroup('demoRG')
}
不提供任何模块名称也是可以的。 系统会生成一个 GUID 作为模块名称。
module stgModule 'storageAccount.bicep' = {
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>
}
}
若要部署一个模块的多个实例,请添加 表达式。 可以使用 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。 若要了解有关依赖项的详细信息,请参阅 Bicep 中的资源依赖项。
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 架构良好的框架等最佳做法相一致。
浏览Bicep 模块,查看可用模块列表。 在以下屏幕截图中选择突出显示的数字,直接转到该筛选视图:
模块列表显示最新版本。 选择版本号以查看可用版本列表。
若要链接到公共模块,请使用以下语法指定模块路径:
module <symbolic-name> 'br/public:<file-path>:<tag>' = {}
- br/public:这是公共模块的别名。 可以在 Bicep 配置文件中自定义此别名。
-
文件路径:可以包含用字符分隔的
/段。 - 标记:指定模块的版本。
例如:
module storage 'br/public:avm/res/storage/storage-account:0.18.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。 文件路径可以包含由/字符分隔的段。 - 标记:指定模块的版本。
例如:
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.18.0' = {
name: 'myStorage'
params: {
name: 'store${resourceGroup().name}'
}
}
您可以在 bicepconfig.json 文件中替换公共别名。
从 Bicep CLI v0.43.1 开始,Bicep在从 Azure 容器注册表(ACR)引用或还原模块时显式阻止使用自定义域。 此安全措施可防止使用不受支持的配置,否则会导致合规性问题。
如果尝试引用自定义域,例如moduleStore.myCompany.com,Bicep CLI 将返回诊断错误 BCP446。 例如:
module foo 'br:moduleStore.myCompany.com/networking/hub:1.0.0' = { ... }
Bicep 根据内置的允许列表验证所有注册表主机名。 目前,仅允许以下域:
*.azurecr.io*.azurecr.cn*.azurecr.usmcr.microsoft.commcr.azure.cnghcr.io
如果组织使用自定义域,请更新Bicep文件以符合以下限制:
-
还原为原生主机名:更新所有 Bicep 模块引用,使其使用原生
.azurecr.io(或相应云环境的)域名。 -
清除本地缓存: 更新引用后,可能需要清除本地模块缓存。 再次运行
bicep restore,使用已更正的原生主机名拉取这些模块。
模板规范中的文件
在创建模板规格后,可以在模块中链接到该模板规格。 按以下格式指定模板规格:
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 编写修饰器,并将其置于模块声明之上。 下表显示了模块的可用修饰器:
| 装饰器 | 论点 | 说明 |
|---|---|---|
| batchSize | 无 | 设置实例以按顺序部署。 |
| 说明 | 字符串 | 提供模块的说明。 |
修饰器位于 sys 命名空间中。 如果需要将某个装饰器与另一个同名项区分开来,请在该装饰器前加上 sys。 例如,如果 Bicep 文件包含一个名为 description 的参数,则必须在使用 sys 修饰器时添加 description 命名空间。
批量大小
只能将 @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.18.0' = {
name: 'myStorage'
params: {
name: 'store${resourceGroup().name}'
}
}
可以使用 Markdown 格式的文本作为说明文本。
参数
模块定义中提供的参数与 Bicep 文件中的参数匹配。
以下 Bicep 示例有三个参数:storagePrefix、storageSKU 和 location。
storageSKU 参数有默认值,因此在部署期间不必提供该参数的值。
@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@2025-06-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@2025-04-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@2025-04-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@2025-04-01' existing = {
name: 'demogroup1'
}
resource secondRG 'Microsoft.Resources/resourceGroups@2025-04-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: 'chinaeast2deploy'
scope: secondRG
params: {
storagePrefix: 'stg2'
location: 'chinaeast2'
}
}
将 scope 属性设置为有效的范围对象。 如果 Bicep 文件部署的是资源组、订阅或管理组,请将模块的作用域设置为该对象的符号名称。 或者,使用作用域函数来获取有效的作用域。
这些函数包括:
下面的示例使用 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@2025-06-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@2025-04-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 版本 0.35.1 或更高版本,可以将@secure()修饰器应用于模块输出,将其标记为敏感,确保其值不会在日志或部署历史记录中公开。 当模块需要将敏感数据(如生成的密钥或连接字符串)返回到父Bicep文件时,此方法非常有用,而不会有风险暴露。 有关详细信息,请参阅 安全输出。
模块标识
从 Bicep 版本 0.36.1 开始,可以将用户分配的托管标识分配给模块。 此标识在模块中可用 -例如,访问密钥保管库。 但是,后端服务尚不支持此功能。
param identityId string
module mod './module.bicep' = {
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${identityId}': {}
}
}
name: 'mod'
params: {
keyVaultUri: 'keyVaultUri'
identityId: identityId
}
}
相关内容
- 若要将敏感值传递给模块,请使用函数
getSecret。