Bicep 模块

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

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

提示

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

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

Bicep 模块将转换为包含嵌套模板的单个 Azure 资源管理器模板。 有关 Bicep 如何解析配置文件以及 Bicep 如何将用户定义的配置文件与默认配置文件合并的详细信息,请参阅配置文件解析过程配置文件合并过程

定义语法

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

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

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

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

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

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

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

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

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

注册表中的文件

公共模块注册表

公共模块注册表托管在 Microsoft 容器注册表 (MCR) 中。 源代码和模块存储在 GitHub 中。 若要查看可用的模块及其版本,请参阅 Bicep 注册表模块索引

The screenshot of public module registry.

选择版本以查看可用版本。 还可选择“源代码”来查看模块源代码,并打开自述文件。

目前只有几个已发布的模块。 即将推出更多模块。 如果想要参与注册表,请参阅参与指南

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

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

例如:

module hw 'br/public:samples/hello-world:1.0.2' = {
  name: 'helloWorld'
  params: {
    name: 'John Dole'
  }
}

注意

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 注册表的方案名称。
  • file-path 在 Azure 容器注册表中称作 repository。 file-path 可以包含由 / 字符分隔的段。
  • 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 hw 'br/public:samples/hello-world:1.0.2' = {
  name: 'helloWorld'
  params: {
    name: 'John Dole'
  }
}

可以替代 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'
  }
}

参数

模块定义中提供的参数与 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@2021-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@2021-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@2021-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@2021-04-01' existing = {
  name: 'demogroup1'
}

resource secondRG 'Microsoft.Resources/resourceGroups@2021-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: '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@2021-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@2021-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

后续步骤

  • 若要将敏感值传递给模块,请使用 getSecret 函数。