规划 Bicep 文件的结构
Bicep 让你能够灵活地确定如何构建代码。 本单元将介绍构建 Bicep 代码的方法,以及使 Bicep 代码样式保持一致、清晰、易懂的重要性。
Bicep 代码应遵循何种顺序?
Bicep 模板可包含多种元素,包括参数、变量、资源、模块、输出和整个模板的 targetScope
。 Bicep 不强制元素遵循某个顺序。 但必须考虑元素的顺序,确保模板清晰易懂。
对代码排序的方法主要有两种:
- 按元素类型对元素进行分组
- 按资源对元素进行分组
你应该与团队达成共识,使用一致的分组方法。
按元素类型对元素进行分组
可将同一类型的所有元素分为一组。 所有参数都将放在一个位置(通常在文件的顶部)。 接下来是变量,资源和模块紧随其后,输出位于底部。 例如,你可能有一个部署了 Azure SQL 数据库和存储帐户的 Bicep 文件。
如果按类型对元素进行分组,效果可能如下所示:
提示
如果遵循此约定,请考虑将 targetScope
放在文件的顶部。
使用其他基础结构即代码语言(例如 Azure 资源管理器模板中的语言)时,这种排序很有意义。 它还可以让模板易于理解,因为这样可以清楚地查找特定类型的元素。 然而,在较长的模板中,在元素之间导航和跳转可能很难。
你仍需确定如何对这些类别中的元素进行排序。 最好将相关参数分为一组。 例如,有关存储帐户的所有参数属于一组,其中,存储帐户的 SKU 参数属于一组。
同样,可将相关资源分为一组。 这样可帮助使用模板的任何用户快速导航并了解模板的各个重要部分。
有时,需创建一个模板来部署包含多项辅助支持资源的主资源。 例如,可创建一个模板来部署 Azure 应用服务上托管的网站。 主资源是应用服务应用。 同一模板中的辅助资源可能包括应用服务计划、存储帐户、Application Insights 实例以及其他资源。 如果有类似的模板,最好将主资源放在模板“资源”部分的顶部,让打开模板的任何人员都能快速明确模板的用途并找到重要资源。
按资源对元素进行分组
或者,可根据要部署的资源类型对元素进行分组。 继续看前面的示例,你可将与 Azure SQL 数据库资源相关的所有参数、变量、资源和输出进行分组。 然后,可以为存储帐户添加参数、变量、资源和输出,如下所示:
按资源分组可以更轻松地读取模板,因为特定资源所需的所有元素都位于同一位置。 但在某些情况下,例如当你想要查看所有参数时,通过这种分组方式更难快速查看特定元素类型的声明方式。
另外,还需考虑如何处理多项资源的常用参数和变量,例如在使用配置映射时需考虑 environmentType
参数。 常用参数和变量应放置在一起,通常放在 Bicep 文件的顶部。
提示
请考虑为相关资源组创建模块是否更有意义,然后再使用更简单的模板来合并模块。 我们将在 Bicep 学习路径中更详细地介绍 Bicep 模块。
空格如何帮助创建结构?
空行或空格有助于将视觉对象结构添加到模板。 通过谨慎使用空格,可在逻辑上对 Bicep 代码的各个部分进行分组,进而帮助阐明资源之间的关系。 为此,无论你喜欢哪种分组样式,都请考虑在主要部分之间添加空行。
如何定义多项类似的资源?
利用 Bicep,可以使用循环从单个定义部署相似的资源。 通过使用 for
关键字来定义资源循环,可让 Bicep 代码更整洁,并减少资源定义发生不必要的重复。 将来,如需更改资源定义,只需更新一次即可。 默认情况下,Azure 资源管理器在部署资源时,会同时部署循环中的所有资源,让部署尽可能高效。
查找定义了相同的或属性有些许不同的多项资源的位置。 然后,添加一个变量来列出要创建的资源,以及不同于其他资源的属性。 下面的示例使用循环来定义一组 Azure Cosmos DB 容器,每个容器都有自己的名称和分区键:
var cosmosDBContainerDefinitions = [
{
name: 'customers'
partitionKey: '/customerId'
}
{
name: 'orders'
partitionKey: '/orderId'
}
{
name: 'products'
partitionKey: '/productId'
}
]
resource cosmosDBContainers 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2024-05-15' = [for cosmosDBContainerDefinition in cosmosDBContainerDefinitions: {
parent: cosmosDBDatabase
name: cosmosDBContainerDefinition.name
properties: {
resource: {
id: cosmosDBContainerDefinition.name
partitionKey: {
kind: 'Hash'
paths: [
cosmosDBContainerDefinition.partitionKey
]
}
}
options: {}
}
}]
如何将资源仅部署到特定环境?
有时,需定义只应部署到特定环境或在某些情况下部署的资源。 可使用 if
关键字根据参数值、配置映射变量或其他条件选择性地部署资源。 以下示例使用配置映射来部署生产环境的日志记录资源,但不适用于测试环境:
var environmentConfigurationMap = {
Production: {
enableLogging: true
}
Test: {
enableLogging: false
}
}
resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' = if (environmentConfigurationMap[environmentType].enableLogging) {
name: logAnalyticsWorkspaceName
location: location
}
resource cosmosDBAccountDiagnostics 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = if (environmentConfigurationMap[environmentType].enableLogging) {
scope: cosmosDBAccount
name: cosmosDBAccountDiagnosticSettingsName
properties: {
workspaceId: logAnalyticsWorkspace.id
// ...
}
}
如何表示资源之间的依赖关系?
在任何复杂的 Bicep 模板中,都需要表示资源之间的依赖关系。 Bicep 理解资源之间的依赖关系后,它会按正确的顺序进行部署。
通过 Bicep,可使用 dependsOn
属性显式指定依赖关系。 但在大多数情况下,都可以让 Bicep 自动检测依赖关系。 如果在一项资源的属性中使用一项资源的符号名称,Bicep 将检测此关系。 如可能,最好让 Bicep 自己管理这些关系。 这样,在更改模板时,Bicep 将确保依赖关系始终正确,你也不用添加不必要的代码,让模板更加繁琐、更难阅读。
如何表示父子关系?
Azure 资源管理器和 Bicep 有一个“子资源”的概念,只有将它们部署到其父级的上下文中时,才有意义。 例如,Azure SQL 数据库是 SQL 服务器实例的子级。 有多种方法可以定义子资源,但在大多数情况下,最好使用 parent
属性。 这有助于 Bicep 了解关系,以便它可以在 Visual Studio Code 中提供验证,并使读取模板的任何其他人都清楚关系。
如何设置资源属性?
你需要在 Bicep 文件中指定资源属性的值。 将值硬编码到资源定义中是一种很好的做法。 如果知道这些值不会更改,则对值进行硬编码可能比使用其他参数更难测试和使用模板。 不过,如果值可能发生更改,可考虑将其定义为参数或变量,以提升 Bicep 代码的动态性和可重用性。
处理硬编码值时,最好确保其他人可以理解它们。 例如,如果需要将属性设置为资源的特定值才能使其在解决方案中正确运行,应考虑创建一个采用适当名称并提供相应说明的变量,然后使用该变量赋值。 如果变量名称不能说明全部的情况,可考虑添加注释。 本模块稍后会详细介绍这些注释。
对于某些资源属性,若要自动构造值,需要创建包含函数和字符串内插的复杂表达式。 如果声明变量并在资源代码块中引用它们,Bicep 代码通常更清晰。
提示
创建输出时,请尽可能尝试使用资源属性。 避免引入自己有关资源工作方式的假设,因为这些假设可能会随着时间的推移而改变。
例如,如果需要输出应用服务应用的 URL,请避免构造 URL:
output hostname string = '${app.name}.azurewebsites.net'
如果应用服务更改了向应用分配主机名的方式,或者你部署到使用不同 URL 的 Azure 环境,则前述方法将失效。
请改为使用应用资源的 defaultHostname
属性:
output hostname string = app.properties.defaultHostname
如何有效地使用版本控制?
版本控制系统(如 Git)有助于简化重构代码时的工作。
由于版本控制系统旨在跟踪对文件所做的更改,因此,如果发生错误,可使用它们轻松返回到旧版代码。 最好时常提交工作,以便可以返回到所需的确切时间点。
版本控制还可帮助你删除 Bicep 文件中的旧代码。 如果 Bicep 代码包含不再需要的资源定义怎么办? 将来可能还需要此定义,只需将其注释掉并将其保存在文件中即可。 但实际上,把其保留在那儿只会使 Bicep 文件变得混乱,让其他人很难理解为何注释掉的资源仍在文件中。
另一个考虑因素是,有人可能会意外地对定义取消注释,由此产生不可预测的结果或潜在的不良后果。 使用版本控制系统时,只需删除旧资源定义。 如果将来还需要此定义,就可从文件历史记录中检索它。