使用 Terraform 和 GitHub 进行 GitOps





5.00/5 (1投票)
如何编写 Terraform 代码来部署简单的 Azure 基础架构,并探索软件开发人员用于“限制”到主分支的基础架构更改的 Git 工作流程。
在上一篇文章中,我们介绍了 DevOps,这是一种现代化的协作理念,通过人员、流程和工具来加速软件开发。我们研究了它如何采纳持续集成 (CI) 和持续部署 (CD) 等软件开发实践。我们还探讨了 DevOps 如何催生了 GitOps 的新概念,即一种名为基础设施即代码 (IaC) 的源代码类型,存储在 Git 源代码管理中,作为当前已部署基础设施的单一事实来源。
IaC 有许多工具,但在我工作过的所有地方,Terraform 都获得了最大的关注,主要是因为它面面俱到——甚至在许多用例中省去了 Ansible 等额外的配置管理 (CM) 工具的需求。
Terraform 的主要功能是部署和管理基础设施的状态。Terraform 的工作流程如下:
编写
:修改基础设施代码(由人员执行)初始化
:设置工作目录(由 Terraform 执行)计划
:确定需要创建、更新或销毁什么,才能将当前活动状态迁移到代码中新的/期望的状态(由 Terraform 执行)应用
:对活动基础设施进行更改(由 Terraform 执行)销毁
:移除不再需要的活动资源(由 Terraform 执行)
在本文中,我们将把在第一篇文章中学到的理论应用于实际场景,使用 Terraform 来配置 Azure Function App 的基础设施。然后,我们将探讨如何利用 Git 工作流——分支、提交更改以及对拉取请求进行核心审查——作为 GitOps 流程的一部分。
必备组件
这是一个动手教程,需要提前进行以下设置:
- Azure 订阅(免费试用)
- 已安装 Azure CLI(如何安装)
- 已本地安装 Terraform(下载)
- 注意:Terraform 下载只是一个单一的可执行文件,不是安装程序。您需要将其复制到您的执行路径中的某个位置。
- PowerShell
- GitHub 上的一个空仓库(说明)
创建 Azure 帐户后,登录到门户,然后在页面顶部的搜索栏中搜索“Subscriptions”部分。记下分配给它的订阅 ID——稍后您将需要它。
完整的代码在此处可用,并且也在文章中包含,供您参考。
步骤 1:使用 Azure Provider
Terraform 是云无关的。它可以跨 Azure、Amazon Web Services (AWS) 和 Google Cloud Platform (GCP) 等多种云服务配置基础设施。它还可以用于配置其他 SaaS 提供商和 API 的服务,例如身份即服务 (IaaS) 供应商 Auth0,或可观察性服务 Datadog。
这些服务提供的插件称为 Terraform provider。Terraform Registry 上提供了已验证 provider 的完整列表。
Provider 主要由以下部分组成:
- 版本号——这些通常遵循语义版本控制,因此我们知道何时更新。
- 资源——这是我们要配置的新事物。
- 数据源——这些用于访问已存在的资源。例如,我们可能需要获取 Key Vault 的详细信息来获取机密。
与 Azure 配合使用时,有三个 provider:
- Azure Resource Manager (ARM)——您将用于与 Azure Cloud 交互的基础 provider。
- Azure Stack——用于处理本地实例。
- Azure Active Directory——Azure 专门处理 Azure AD。
在存储库的根文件夹中创建一个名为 main.tf 的新文件,并添加以下代码行。请注意,required_providers
是可选的,但强烈建议设置版本和源。
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = ">=3.0.0"
}
}
}
provider "azurerm" {
features {}
}
最佳实践提示:对于具有大量 provider 或 provider 版本的大型生产系统,您应该考虑将 provider 移至一个单独的文件 provider.tf。这样可以更轻松地进行管理。
步骤 2:编写 Terraform 代码
要为非常简单的 Web 请求部署我们的无服务器函数代码,我们需要配置 Azure Function App 的基础设施。
Azure Function App 还需要额外的基础设施:
- 资源组——Azure 中的*所有*资源都必须位于资源组内。
- 应用服务计划——这定义了您的计算资源。本质上,此计划决定了您需要付费的内容。
- 存储帐户——这对于函数操作是必需的。
所以,我们也需要配置这些!
我们希望设置资源的区域位置,以及它们名称的通用前缀。在更复杂的可生产系统中,请将它们组织在变量定义‘tfvars’文件中。为了使此示例保持简单并包含在单个 main.tf 文件中,我们将使用本地变量。
在文件顶部添加以下内容:
locals {
location = "uksouth"
prefix = "gitopsdemo"
}
在 main.tf 文件的底部,在我们迄今为止添加的所有内容下方,粘贴我们将需要配置的基础设施的代码。
resource "azurerm_resource_group" "main" {
name = "${local.prefix}-rg"
location = local.location
}
resource "azurerm_storage_account" "main" {
name = "${local.prefix}storageacct"
resource_group_name = azurerm_resource_group.main.name
location = azurerm_resource_group.main.location
account_tier = "Standard"
account_replication_type = "LRS"
}
resource "azurerm_service_plan" "main" {
name = "${local.prefix}-asp"
resource_group_name = azurerm_resource_group.main.name
location = azurerm_resource_group.main.location
os_type = "Linux"
sku_name = "Y1"
}
resource "azurerm_linux_function_app" "main" {
name = "${local.prefix}-function"
resource_group_name = azurerm_resource_group.main.name
location = azurerm_resource_group.main.location
service_plan_id = azurerm_service_plan.main.id
storage_account_name = azurerm_storage_account.main.name
storage_account_access_key = azurerm_storage_account.main.primary_access_key
site_config {}
}
Terraform 部分就到这里。
现在我们已经拥有了将 Function App 部署到 Azure 所需的所有基础设施,这些基础设施都声明在一个文件中。我们可以利用它轻松地在多个环境中配置(或重新配置)相同资源,速度比手动执行任务快得多。如果需要,所有这些都可以通过自动化实现,而无需承担常见的风险,如配置漂移和不一致。
最重要的是,通过将我们的基础设施声明为代码,我们正在迈向实践 GitOps 的道路。现在我们可以利用 Git 的开发人员工具,包括版本历史记录、分支和带有代码审查的拉取请求,以确保代码中描述的基础设施与我们活动系统中实际配置的基础设施相匹配。根据您组织中开发人员使用的系统,您还可以将代码更改与用于跟踪项目工作的工具(如 Azure DevOps Boards)关联起来。
步骤 3:使用 Git
Terraform 通过跟踪状态极大地改进了 DevOps 实践。但是,状态问题会(而且确实)发生。通过使用 Git 作为当前基础设施状态的单一事实来源,我们可以减轻这种风险。
通过 CLI 或您喜欢的 Git UI 将更改推送到 GitHub。
代码审查
GitOps 从软件开发中借鉴了一个重要的控制机制,即*拉取请求*——我们希望有人*手动*检查代码所做的更改。这通常被称为代码审查。
现在,我们将向 Function App 添加Application Insights。与应用程序开发一样,我们将此操作放在一个单独的分支上,以避免破坏当前在 main 分支上的活动代码。只有在代码经过审查后,我们才会将其合并到 main 分支。
在本地 Git UI 或使用命令行创建名为 add-app-insights
的新分支,命令如下:
git checkout -b add-app-insights
添加新资源
resource "azurerm_application_insights" "main" {
name = "${local.prefix}-appinsights"
resource_group_name = azurerm_resource_group.main.name
location = azurerm_resource_group.main.location
application_type = "web"
}
为了让 Function App 能够与 Application Insights 实例通信,请向函数资源添加一个新的应用设置,其键为:
resource "azurerm_linux_function_app" "main" {
…
app_settings = {
AppInsights_InstrumentationKey = azurerm_application_insights.main.instrumentation_key
}
}
暂存更新后的 main.tf,提交更改,然后将新分支推送到 GitHub。
git add main.tf
git commit -m “Add app insights”
git push --set-upstream origin add-app-insights
导航到 GitHub 网站上的存储库,然后转到“Pull requests”选项卡。它应该已经注意到您的新更改,并提供“Compare & pull request”选项。点击该按钮。
打开 PR 的屏幕是您向审查者解释任何复杂更改的机会。在我们的例子中,这是一个不言自明的添加,所以我们可以将注释留空。
这也是最后一次检查您要求合并到 main 分支的更改的好时机。我记不清有多少次在这个阶段发现了错误。
如果您乐意继续,请点击“Create pull request”按钮。
您的团队中的其他成员可以验证您的代码。在为 GitOps 工作流设置存储库时,与应用程序代码一样,最好设置规则来强制执行所需的批准数量、谁应该批准以及其他自动化检查。我们将在下一篇文章中探讨这一点。
然后可以通过“Merge pull request”将其合并到 main 分支。
我们将在下一篇文章中介绍如何使用 GitHub Actions 自动将这些更改部署到 Azure。
摘要
在本文中,您获得了编写 Terraform 代码来配置简单的 Azure 基础设施的实践经验。我们还探讨了软件开发人员使用的 Git 工作流,该工作流将基础设施更改“门控”到我们的 main 分支,其中 main 分支是基础设施所需状态的事实来源。
在下一篇文章中,我们将构建一个 CI/CD 管道,该管道除了代码审查流程外,还可以使用自动化检查,并将资源配置到 Azure。
要了解更多关于 GitOps 的信息以及如何使用 GitOps 管理部署到 Kubernetes 的应用程序的配置,请查阅资源如何将 GitOps 与 Microsoft Azure 结合使用。