65.9K
CodeProject 正在变化。 阅读更多。
Home

利用 Bicep 部署 Azure 资源

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2024 年 1 月 29 日

CPOL

12分钟阅读

viewsIcon

2633

downloadIcon

40

如何使用 Bicep 自动部署 Azure 资源?

引言

在过去十年中,云计算的普及趋势促使众多组织将大量应用程序迁移到云端,鼓励更深入地拥抱这一范式。而这种迁移则需要更严格的应用程序开发和部署流程。

  • 这一趋势主要影响了应用程序,促使工程师越来越多地采用 CI/CD 最佳实践,而云服务提供商(例如 Azure DevOps)提供的集成工具则极大地便利了这一点。

  • 如今,一场新的趋势正在展开,自动化已从应用程序扩展到基础设施。资源不再手动分配,而是通过配置文件自动配置。这种范式通常被称为“基础设施即代码”。

为了满足基础设施即代码范式的需求,涌现出了各种工具,其中 Terraform 和 Ansible 最为突出。最近,微软推出了一款新工具 Bicep,在本系列文章中,我们将探讨其在实际场景中的应用。

后续的教科书对于完成本系列非常有帮助,它们将基础设施即代码作为一个全面的主题进行深入探讨。

本文最初发布于: 利用 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 会自动为我们管理)。

最终想法

如果您想更深入地了解此主题,请获取以下书籍,它们涵盖了本系列中强调的所有概念,并深入探讨了更高级的概念。

如果您需要更多信息,请随时与我联系。

历史

  • 2024 年 1 月 29 日:初版
© . All rights reserved.