利用 Bicep 部署 Azure 资源





0/5 (0投票)
如何使用 Bicep 自动部署 Azure 资源?
引言
在过去十年中,云计算的普及趋势促使众多组织将大量应用程序迁移到云端,鼓励更深入地拥抱这一范式。而这种迁移则需要更严格的应用程序开发和部署流程。
-
这一趋势主要影响了应用程序,促使工程师越来越多地采用 CI/CD 最佳实践,而云服务提供商(例如 Azure DevOps)提供的集成工具则极大地便利了这一点。
-
如今,一场新的趋势正在展开,自动化已从应用程序扩展到基础设施。资源不再手动分配,而是通过配置文件自动配置。这种范式通常被称为“基础设施即代码”。
为了满足基础设施即代码范式的需求,涌现出了各种工具,其中 Terraform 和 Ansible 最为突出。最近,微软推出了一款新工具 Bicep,在本系列文章中,我们将探讨其在实际场景中的应用。
后续的教科书对于完成本系列非常有帮助,它们将基础设施即代码作为一个全面的主题进行深入探讨。
- Terraform: Up and Running: Writing Infrastructure as Code (Brikman)
- Getting started with Bicep: Infrastructure as code on Azure (Berson)
本文最初发布于: 利用 Bicep 部署 Azure 资源
什么是基础设施即代码 (IaC)?
基础设施即代码 (IaC) 是一种管理和配置计算基础设施的方法,它通过机器可读的脚本文件来完成,而不是通过物理硬件配置或交互式配置工具。本质上,它将服务器、网络和数据库等基础设施视为代码,允许使用与应用程序代码相同的实践来进行版本控制、测试和部署。
通过基础设施即代码,配置以声明式或命令式脚本语言表示,指定基础设施的期望状态。该脚本通常被称为“模板”或“清单”,可用于自动化配置和管理基础设施组件。
简化自动化
IaC 实现了基础设施的自动化配置和管理,减少了人工干预和人为错误的风险。
确保版本控制
基础设施配置可以使用版本控制系统进行版本控制,从而能够跟踪随时间推移的更改,回滚到之前的状态,并促进团队成员之间的协作。
确保可复现性
通过使用相同的代码库,可以在不同环境(开发、测试、生产)之间一致地复现基础设施,最大限度地减少差异并提高可靠性。
为什么是现在?
前面提到的挑战并非新鲜事物;它们自计算机科学诞生以来就一直存在。然而,根本性的转变在于过去服务器通常在本地部署,当时自动化部署的工具要么不可用,要么难以实现。随着云计算的广泛普及,云平台引入了简化这些流程的方法和机制。因此,应用自动化变得势在必行,尤其是在项目生命周期的早期阶段。
IaC 已迅速从一个开创性的概念发展成为软件开发流程的基础元素。
实施基础设施即代码的常用工具有哪些?
目前,IaC 有许多提供商,其中 Terraform 和 Ansible 是最著名的。值得注意的是,微软推出了 Bicep,这是一款专为 Azure 平台设计的工具,为 IaC 实现提供了更多选择。
什么是 Terraform?
Terraform 由 HashiCorp 开发,它允许用户使用 **声明式** 配置文件语言来定义和配置基础设施。通过 Terraform,我们在高级配置文件中描述基础设施所需的组件和资源,然后 Terraform 会自动完成这些资源的配置和管理过程。
-
Terraform 使用声明式语言来定义基础设施的期望状态。用户指定他们需要的资源及其配置,Terraform 则负责找出如何使当前基础设施与期望状态匹配。
信息
我们将看到,Bicep 也使用声明式语法进行基础设施配置,在这种情况下,我们描述期望的结果,而无需指定实现该结果的各个步骤。
-
Terraform 在状态文件中跟踪基础设施的状态。该文件记录了资源及其当前配置之间的关系,使 Terraform 能够在后续运行中做出明智的决策。
信息
状态文件对于 Terraform 监控更改至关重要,需要将其存储在指定位置。这可以通过 Azure 存储或 Terraform Cloud 来完成。值得注意的是,Azure 通过自动管理状态文件的存储,简化了 Bicep 的这一过程。
什么是 Ansible?
Ansible 是由 Red Hat 开发的开源自动化工具。它通过允许用户将基础设施描述为代码,从而简化复杂任务并促进 IT 基础设施的管理。
Ansible 是命令式 IaC 工具的一个显著示例,它使用基于 YAML 的 Playbook 来描述一系列任务。
信息
命令式 IaC 是一种方法,用户在此方法中指定实现所需基础设施状态所需的步骤序列。在命令式 IaC 中,重点是详细说明应执行的具体任务和操作,通常类似于过程式或脚本式的风格。
虽然命令式 IaC 提供了对部署过程的高度控制和更大的灵活性,但有时维护起来可能更复杂,并且可能需要更多手动干预来处理更改或更新。
我们的目标是介绍 Bicep,展示其在实际中的应用,并探讨它可能如何带来独特的优势或功能,从而对其在 IaC 领域的竞争对手构成挑战。
如何在 Azure 上部署资源?
可以通过 Azure 门户(提供图形用户界面 GUI 模式)或更技术性的 Azure CLI 直接在 Azure 上部署资源。虽然这些方法很方便,但它们缺乏自动化流程或确保可复现性的能力。这一限制促使 Azure 引入了带 ARM 模板的基础设施即代码,从而实现了更系统化和自动化的资源部署方法。
什么是 ARM 模板?
ARM 模板是定义我们项目基础设施和配置的 JSON 文件。这些模板使用 **声明式** 语法,允许我们说明要部署的内容,而无需编写创建它的编程命令序列。以下是创建存储帐户的 ARM 模板示例。
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2022-09-01",
"name": "mystorageaccount",
"location": "East US",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"kind": "StorageV2",
"properties": {}
}
]
}
此特定模板指定在“East US
”区域使用“Standard_LRS
”SKU 创建一个名为“mystorageaccount
”的存储帐户。
顺便说一句,我们看到了声明式的本质;在这种情况下,我们描述了我们想要部署的内容,而没有指定过程步骤。实际上,微软会以命令式的方式解释该文件,将定义转换为相应的 REST API 操作。然后,此操作会传输到 Microsoft.Storage
资源提供程序。
PUT https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/
providers/Microsoft.Storage/storageAccounts/mystorageaccount?api-version=2022-09-01
REQUEST BODY
{
"location": "eastus",
"sku": {
"name": "Standard_LRS"
},
"kind": "StorageV2",
"properties": {}
}
重要
此 JSON 文件可以随后存储、用于未来目的并进行版本控制,例如使用 Git。它还可以集成到 Azure DevOps 中的持续交付 (CD) 管道中,从而实现部署过程的完全自动化。
有什么局限性?
到目前为止,一切都与流程一致。然而,软件工程师采用这种语法被证明是具有挑战性的;他们发现它很麻烦且难以使用。考虑到 Terraform 等其他提供商提供了更简洁直观的资源声明方法,这一点尤其值得注意。为了响应这些反馈,微软采取行动,推出了一种新的、更适应的语言。这就是 Bicep。
什么是 Bicep?
Bicep 是一种用于定义 ARM 模板的声明式语法。它旨在简化和增强 ARM 模板的编写体验。
- Bicep 也采用声明式语法,允许用户指定其 Azure 资源的期望状态,而无需详细说明实现该状态的过程。
- Bicep 抽象了 ARM 模板的复杂性,使其更简洁易读。它提供了更高级别的抽象,更接近用户的意图。
- Bicep 引入了类型系统,通过确保指定类型与预期的 Azure 资源类型匹配来增强代码安全性。
- Bicep 提供了内置验证工具,用于在部署前检查代码中的错误和问题,从而降低运行时错误的可能性。
信息 1
请记住,Bicep 旨在成为直接编写 ARM 模板的更友好的替代方案。它旨在通过提供更直观、更高效的编写体验来简化 Azure 资源的配置和管理过程。 **事实上,它本身并不是一项突破性技术,也不是什么前所未闻的事物。**
信息 2
与 Terraform 和 Ansible 不同,后者是可用于 Azure、AWS 和 GCP 等各种云提供商的通用工具,Bicep 专为 Azure 设计。值得注意的是,如果意图是为 BigQuery 或 Redshift 等工具配置资源,则不应使用 Bicep。
现在,我们将深入研究 Bicep 的实际方面。然而,在继续之前,我们需要安装一些先决条件以确保其正常运行。虽然这可能有点麻烦,但对我们继续探索具体示例至关重要。
设置 Bicep 开发和部署环境
免责声明
本节中概述的安装过程有些主观,它侧重于使用 Visual Studio 2022 编写 Bicep 文件并使用 Azure CLI 进行部署。但是,也存在其他选项,例如在基本编辑器中编写文件并使用 PowerShell 进行部署。
创建 Bicep 文件
完全掌握 Bicep 的语法可能不可行,但 IntelliSense 会提供帮助。在此上下文中,我们将使用 Visual Studio 2022 的 Bicep 扩展,可以 在此处 下载。下载扩展后,只需在 IDE 中安装它。
部署 Bicep 文件
目前不支持直接从 Visual Studio 部署 Bicep 文件。Bicep 文件的部署只能使用 Azure CLI 或 Azure PowerShell 来完成,在本系列中,我们将选择 Azure CLI。
要在 Windows 上安装 Azure CLI,请按照 此处 提供的说明进行操作。
- 安装 Azure CLI 后,打开命令提示符并执行命令 '
az bicep version
'。 - 运行命令 '
az bicep install
' 来解决错误。一切就绪后,现在是时候探索 Bicep 文件的实际示例了。我们的目标是创建一个包含资源组和 Azure 函数的订阅。
免责声明
为了简洁起见,我们将在此省略管理组的创建。但是,在实际场景中,建议使用 Bicep 管理它们以获得更好的组织和治理。
环境设置
- 打开 Visual Studio,创建一个新解决方案。
我们将系统地创建所需的资源,从订阅开始。
- 为了部署 Azure 资源,必须拥有必要的权限,特别是被指定为根作用域的所有者。可以使用以下 Azure CLI 命令授予此权限
az role assignment create --assignee <id_user_assignee> --scope "/" --role "Owner"
"
id_user_assignee
" 指的是将执行部署的 Azure CLI 命令的用户帐户。
需要注意的是,授予其他用户访问权限的能力也需要授权。仅拥有 Microsoft Enterprise ID 中的全局管理员权限是不够的;需要明确声明以确认用户管理租户中所有 Azure 订阅和管理组的访问权限的能力。
为此,请导航到 Microsoft Entra ID,访问属性,然后在相应的部分选择 **是**。
创建新订阅
- 在解决方案中创建一个名为 create.subscription.bicep 的新文件。
- 在此处添加以下内容
metadata description = 'Creates a subscription' targetScope = 'tenant' param billingScope string = '/providers/Microsoft.Billing/billingAccounts/432a9fe6-a481-55xxxxxxxxxxxxxxxxxxxxxxxx' param subscriptionName string = 'EOCS_Bicep' resource alias 'Microsoft.Subscription/aliases@2020-09-01' = { scope: tenant() name: subscriptionName properties: { workload: 'Production' displayName: subscriptionName billingScope: billingScope } } output subscriptionId string = alias.properties.subscriptionId
此时有几个值得注意的方面。
-
在 Bicep 中,
targetScope
是一个属性,它允许我们指定 Bicep 文件中定义的资源的应用范围。targetScope
属性决定了模板执行时资源将部署在哪里。 -
我们可以使用
param
关键字定义某些变量。 -
新创建订阅的 ID 可通过输出变量访问。
信息 1
账单范围是创建订阅的重要信息,获取它可能有些复杂。请遵循以下步骤。
- 在 Azure CLI 中执行命令 '
az billing account list
' 并记下 name 属性。 - 执行命令 '
az billing profile list --account-name "<name_property>" --expand "InvoiceSections"
' - 记下
invoiceSections
中的 id 属性。
此属性即为账单范围。
信息 2
在涉及 CI/CD 管道的实际场景中,一些变量应在当前环境中配置,然后在运行时由专用任务替换。举例来说,订阅的名称可能取决于生成它的环境(开发、暂存或生产),因此需要一个恰当反映该上下文的名称。
重要
此代码专门用于简单的 Microsoft 帐户。但是,它需要进行调整,尤其是在与企业协议设置一起使用时。
部署文件
要部署文件,请打开 Azure CLI 并执行以下命令
az deployment tenant create --template-file create.subscription.bicep --location westus
显然,订阅已成功创建。
创建新资源组
在定义了订阅之后,下一步是在此订阅中包含一个资源组。
- 在解决方案中创建一个名为 create.resourcegroup.bicep 的新文件。
metadata description = 'Creates a resource group'
targetScope = 'subscription'
param resourceGroupName string = 'Infra'
param location string = deployment().location
resource infraResourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = {
name: resourceGroupName
location: location
}
-
targetScope
现在是 **subscription**。 -
资源组的位置通过
deployment().location
获取。此变量实际上是在使用 Azure CLI 执行部署时提供的,需要我们显式指定位置。稍后将详细介绍。
部署文件
部署资源组需要位于特定订阅内。因此,首先切换到指定的订阅至关重要,确保资源在正确的位置进行配置。
az account set --subscription EOCS_Bicep
az deployment sub create --template-file create.resourceGroup.bicep --location westus
在前面的命令中,可以清楚地看到我们指定了资源组应部署的位置。此参数随后被 Bicep 文件通过 deployment().location
辅助函数重用。
创建新 Azure 函数
最后,我们在资源组内部署一个 Azure 函数。需要注意的是,Azure 函数需要一个关联的托管计划和一个存储帐户。
- 在解决方案中创建一个名为 create.azurefunction.bicep 的新文件。
param appName string = 'func-company-project-catalogueservice' param storageAccountType string = 'Standard_LRS' param location string = resourceGroup().location param runtime string = 'dotnet' var functionAppName = appName var hostingPlanName = appName var storageAccountName = '${uniqueString(resourceGroup().id)}azfunctions' var functionWorkerRuntime = runtime resource storageAccount 'Microsoft.Storage/storageAccounts@2022-05-01' = { name: storageAccountName location: location sku: { name: storageAccountType } kind: 'Storage' properties: { supportsHttpsTrafficOnly: true defaultToOAuthAuthentication: true } } resource hostingPlan 'Microsoft.Web/serverfarms@2021-03-01' = { name: hostingPlanName location: location sku: { name: 'Y1' tier: 'Dynamic' } properties: {} } resource functionApp 'Microsoft.Web/sites@2021-03-01' = { name: functionAppName location: location kind: 'functionapp' identity: { type: 'SystemAssigned' } properties: { serverFarmId: hostingPlan.id siteConfig: { appSettings: [ { name: 'AzureWebJobsStorage' value: 'DefaultEndpointsProtocol=https; AccountName=${storageAccountName}; EndpointSuffix=${environment().suffixes.storage}; AccountKey=${storageAccount.listKeys().keys[0].value}' } { name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING' value: 'DefaultEndpointsProtocol=https; AccountName=${storageAccountName}; EndpointSuffix=${environment().suffixes.storage}; AccountKey=${storageAccount.listKeys().keys[0].value}' } { name: 'WEBSITE_CONTENTSHARE' value: toLower(functionAppName) } { name: 'FUNCTIONS_EXTENSION_VERSION' value: '~4' } { name: 'WEBSITE_NODE_DEFAULT_VERSION' value: '~14' } { name: 'FUNCTIONS_WORKER_RUNTIME' value: functionWorkerRuntime } ] ftpsState: 'FtpsOnly' minTlsVersion: '1.2' } httpsOnly: true } } output azureFunctionId string = functionApp.id
targetScope
未明确指示;默认情况下,它设置为resourceGroup
,我们打算在该范围内部署我们的函数。
部署文件
我们在 Azure CLI 中执行以下命令。
az deployment group create --resource-group Infra --template-file create.azurefunction.bicep
这样,我们的资源就已配置完毕,如果需要,我们可以放心地在另一个数据中心执行这些脚本。此外,这些 Bicep 脚本可以进行版本控制,以便根据需要重新部署。
重要
最后的说明:当前部署的状态存储在哪里?换句话说,Bicep 如何确定资源的数量或需要创建的资源?与 Terraform 不同,Terraform 需要显式存储状态,而 Azure 与 Bicep 之间的无缝集成使开发人员免去了此职责(Azure 会自动为我们管理)。
最终想法
如果您想更深入地了解此主题,请获取以下书籍,它们涵盖了本系列中强调的所有概念,并深入探讨了更高级的概念。
- Terraform: Up and Running: Writing Infrastructure as Code (Brikman)
- Getting started with Bicep: Infrastructure as code on Azure (Berson)
如果您需要更多信息,请随时与我联系。
历史
- 2024 年 1 月 29 日:初版