基础结构即代码

提示

此内容摘自电子书《为 Azure 构建云原生 .NET 应用程序》,可在 .NET 文档上获取,也可作为免费可下载的 PDF 脱机阅读。

Cloud Native .NET apps for Azure eBook cover thumbnail.

云原生系统采用微服务、容器和新式系统设计来实现一定的速度和敏捷性。 它们提供自动化的生成和发布阶段,以确保代码的一致性和质量。 但这只是其中的一部分。 如何预配这些系统所运行的云环境?

新式云原生应用程序采用了广泛接受的基础结构即代码 (IaC) 做法。 借助 IaC,可以自动完成平台预配。 实质上你是将软件工程做法(例如测试和版本控制)应用到 DevOps 做法。 基础结构和部署是自动执行的,具有一致性和可重复性。 正如持续交付自动执行传统的手动部署模型一样,基础结构即代码 (IaC) 也在不断演变应用程序环境的管理方式。

使用 Azure 资源管理器 (ARM)、Terraform 和 Azure 命令行接口 (CLI) 等工具,你能够以声明方式对所需的云基础结构编写脚本。

Azure 资源管理器模板

ARM 是 Azure Resource Manager(Azure 资源管理器)的缩写。 它是 Azure 中内置的 API 预配引擎,以 API 服务的形式公开。 通过 ARM,你可以在一次协调的操作中部署、更新、删除和管理 Azure 资源组中包含的资源。 你向引擎提供一个基于 JSON 的模板,指定你需要的资源及其配置。 ARM 会按与依赖关系有关的正确顺序自动协调部署。 引擎可确保幂等性。 如果所需的资源已经以相同的配置存在,则将忽略预配。

Azure 资源管理器模板是一种基于 JSON 的语言,用于定义 Azure 中的各种资源。 基本架构如图 10-14 所示。

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "",
  "apiProfile": "",
  "parameters": {  },
  "variables": {  },
  "functions": [  ],
  "resources": [  ],
  "outputs": {  }
}

图 10-14 - 资源管理器模板的架构

在此模板中,可能会在资源部分中定义一个存储容器,如下所示:

"resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "name": "[variables('storageAccountName')]",
      "location": "[parameters('location')]",
      "apiVersion": "2018-07-01",
      "sku": {
        "name": "[parameters('storageAccountType')]"
      },
      "kind": "StorageV2",
      "properties": {}
    }
  ],

图 10-15 - 资源管理器模板中定义的存储帐户的示例

可以使用动态环境和配置信息对 ARM 模板执行参数化。 这样做可以重复使用它来定义不同的环境,例如开发、QA 或生产环境。 通常,模板会在单个 Azure 资源组中创建所有资源。 如果需要,可以在单个资源管理器模板中定义多个资源组。 可以通过删除资源组本身来删除环境中的所有资源。 成本分析还可以在资源组级别运行,使得可以快速评估每个环境的成本。

GitHub 上的 Azure 快速入门模板项目中提供了许多 ARM 模板的示例。 它们有助于加速创建新模板或修改现有模板。

可以通过多种方式运行资源管理器模板。 也许最简单的方法是将它们粘贴到 Azure 门户中。 对于试验部署,这种方法很快捷。 它们还可以作为 Azure DevOps 中的生成或发布过程的一部分运行。 有一些任务会利用连接到 Azure 来运行模板。 对资源管理器模板的更改是以增量方式应用的,这意味着,要添加新资源,只需将其添加到模板中。 工具将协调当前资源与模板中定义的那些资源之间的差异。 然后,将创建或更改资源,使其与模板中定义的资源相匹配。

Terraform

云原生应用程序通常被构建为cloud agnostic。 这样做意味着应用程序并不与特定的云供应商紧密相连,可以部署到任何公有云。

Terraform 是一个商业模板工具,可以在所有主要的云平台(Azure、Google Cloud Platform、AWS 和 AliCloud)之间预配云原生应用程序。 它没有使用 JSON 作为模板定义语言,而是使用了稍微简明一些的 HCL(Hashicorp 配置语言)。

图 10-16 中展示了一个示例 Terraform 文件,它与先前的资源管理器模板(图 10-15)一样:

provider "azurerm" {
  version = "=1.28.0"
}

resource "azurerm_resource_group" "testrg" {
  name     = "production"
  location = "West US"
}

resource "azurerm_storage_account" "testsa" {
  name                     = "${var.storageAccountName}"
  resource_group_name      = "${azurerm_resource_group.testrg.name}"
  location                 = "${var.region}"
  account_tier             = "${var.tier}"
  account_replication_type = "${var.replicationType}"

}

图 10-16 - 资源管理器模板的示例

Terraform 还为问题模板提供直观的错误消息。 还有一个方便的验证任务,可以在生成阶段用于提前捕获模板错误。

与资源管理器模板一样,可以使用命令行工具来部署 Terraform 模板。 Azure Pipelines 中还提供了社区创建的任务,可以验证和应用 Terraform 模板。

有时,Terraform 和 ARM 模板会输出有意义的值,例如新创建的数据库的连接字符串。 此信息可以在生成管道中捕获,并在后续任务中使用。

Azure CLI 脚本和任务

最后,可以利用 Azure CLI 以声明方式为你的云基础结构编写脚本。 可以创建、找到并共享 Azure CLI 脚本,用来预配和配置几乎任何 Azure 资源。 CLI 易于使用,学习曲线很平缓。 脚本是在 PowerShell 或 Bash 内执行的。 脚本调试起来也很简单,特别是与 ARM 模板相比。

当你需要拆解和重新部署基础结构时,Azure CLI 脚本非常有效。 更新现有环境可能比较棘手。 许多 CLI 命令不是幂等的。 这意味着,它们将在每次运行时重新创建资源,即使资源已存在也是如此。 在创建每个资源之前,始终可以添加代码来检查其是否存在。 但这样做会使你的脚本变得臃肿且难以管理。

这些脚本也可以作为 Azure CLI tasks 嵌入 Azure DevOps 管道中。 执行管道将调用脚本。

图 10-17 展示了一个 YAML 代码段,其中列出了 Azure CLI 的版本和订阅的详细信息。 请注意内联脚本中包含的 Azure CLI 命令。

- task: AzureCLI@2
  displayName: Azure CLI
  inputs:
    azureSubscription: <Name of the Azure Resource Manager service connection>
    scriptType: ps
    scriptLocation: inlineScript
    inlineScript: |
      az --version
      az account show

图 10-17 - Azure CLI 任务

什么是基础结构即代码一文中,作者 Sam Guckenheimer 介绍了“实现 IaC 的团队能够快速、大规模地提供稳定的环境。 团队避免了手动配置环境,并通过代码来表示环境所需的状态,从而强制执行一致性。 采用 IaC 的基础结构部署是可重复的,可以防止因配置偏移或缺少依赖项而导致的运行时问题。 DevOps 团队可以结合使用一系列统一的做法和工具,迅速、大规模、可靠地提供应用程序及其支持的基础结构。”