本教程介绍如何使用常用的 GitOps 方法,通过 Terraform 和 Cloud Build 以代码形式管理基础设施。术语 GitOps 一词由 Weaveworks 首先提出,其主要概念是使用 Git 代码库来存储您所需的环境状态。Terraform 是一种 HashiCorp 工具,可让您使用代码以可预测的方式创建、更改和改进您的云基础设施。在本教程中,您将使用 Google Cloud 持续集成服务 Cloud Build 自动将 Terraform 清单应用到您的环境。
本教程适用于正在寻求一种出色的解决方案来以可预测的方式对基础架构做出更改的开发者和运维人员。本文假设您熟悉 Google Cloud、Linux 和 GitHub。
DevOps 现状报告确定了可提高软件交付方面表现的功能。本教程将帮助您使用以下功能:
架构
为了演示本教程如何运用 GitOps 方法来管理 Terraform 的执行,请参考以下架构图。请注意,它使用 GitHub 分支 dev
和 prod
来表示实际环境。这些环境分别由 Virtual Private Cloud (VPC) 网络 dev
和 prod
定义,组合成一个 Google Cloud 项目。
当您将 Terraform 代码推送到 dev
或 prod
分支时,该过程就会启动。在这种情况下,Cloud Build 会触发,然后会应用 Terraform 清单在相应环境中实现所需状态。另一方面,当您将 Terraform 代码推送到任何其他分支(例如,某个功能分支)时,Cloud Build 会运行以执行 terraform plan
,但不会对任何环境应用任何内容。
理想情况下,开发者或运维人员必须向未受保护的分支提出基础设施提案,然后通过拉取请求提交这些提案。本教程稍后介绍的 Cloud Build GitHub 应用会自动触发构建作业,并将 terraform plan
报告与这些拉取请求进行关联。这样,您就可以与协作者讨论和查看潜在更改,并在将更改合并到基本分支之前添加后续提交。
如果不存在任何问题,您必须先将更改合并到 dev
分支。此合并会触发将基础架构部署到 dev
环境的操作,如此您便可以测试此环境。在测试所部署的内容并确信其没有问题之后,您必须将 dev
分支合并到 prod
分支,以触发在生产环境中安装基础架构的操作。
目标
- 设置 GitHub 代码库。
- 将 Terraform 配置为在 Cloud Storage 存储桶中存储状态。
- 向您的 Cloud Build 服务账号授予权限。
- 将 Cloud Build 连接到您的 GitHub 代码库。
- 更改功能分支中的环境配置。
- 将更改升级到开发环境。
- 推广对生产环境的更改。
费用
在本文档中,您将使用 Google Cloud 的以下收费组件:
您可使用价格计算器根据您的预计使用情况来估算费用。
完成本文档中描述的任务后,您可以通过删除所创建的资源来避免继续计费。如需了解详情,请参阅清理。
前提条件
- Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
In the Google Cloud console, activate Cloud Shell.
At the bottom of the Google Cloud console, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Google Cloud CLI already installed and with values already set for your current project. It can take a few seconds for the session to initialize.
- 在 Cloud Shell 中,获取您刚刚选择的项目的 ID:
如果此命令未返回项目 ID,请将 Cloud Shell 配置为使用您的项目。请将gcloud config get-value project
PROJECT_ID
替换为您的项目 ID。gcloud config set project PROJECT_ID
- 启用所需的 API:
此步骤可能需要几分钟才能完成。gcloud services enable cloudbuild.googleapis.com compute.googleapis.com
- 如果您从未在 Cloud Shell 中使用过 Git,请使用您的姓名和电子邮件地址配置 Cloud Shell:
Git 根据这些信息确定您就是在 Cloud Shell 中创建的提交的作者本人。git config --global user.email "YOUR_EMAIL_ADDRESS" git config --global user.name "YOUR_NAME"
设置 GitHub 代码库
在本教程中,您将使用一个 Git 代码库来定义您的云基础架构。您还可以通过使不同的分支对应于不同的环境,来编排此基础架构:
dev
分支包含应用于开发环境的最新更改。prod
分支包含应用于生产环境的最新更改。
借助此基础架构,您可以随时参考代码库以了解每个环境中的预期配置,并通过先将它们合并到 dev
环境中来提出新的更改建议。然后,您可以通过将 dev
分支合并到后续的 prod
分支来推广更改。
首先,请创建 solutions-terraform-cloudbuild-gitops 分支制品库。
- 在 GitHub 上,导航到 https://github.com/GoogleCloudPlatform/solutions-terraform-cloudbuild-gitops.git。
在页面的右上角,点击创建分支。
现在,您已拥有包含源文件的
solutions-terraform-cloudbuild-gitops
代码库副本。
在 Cloud Shell 中,克隆此分支代码库,将
YOUR_GITHUB_USERNAME
替换为您的 GitHub 用户名:cd ~ git clone https://github.com/YOUR_GITHUB_USERNAME/solutions-terraform-cloudbuild-gitops.git cd ~/solutions-terraform-cloudbuild-gitops
此代码库中代码的结构如下所示:
environments/
文件夹包含代表环境(例如dev
和prod
)的子文件夹,它们将处于不同成熟阶段(分别为开发和生产阶段)的工作负载进行逻辑分隔。尽管让这些环境尽可能保持相似是不错的做法,但每个子文件夹都有自己的 Terraform 配置,以确保它们可以根据需要采用独特的设置。modules/
文件夹包含内嵌 Terraform 模块。这些模块代表相关资源的逻辑分组,用于跨不同环境共享代码。cloudbuild.yaml
文件是包含 Cloud Build 说明的 build 配置文件,例如如何根据一系列步骤执行任务。此文件根据 Cloud Build 从中提取代码的分支指定条件执行,例如:对于
dev
和prod
分支,执行以下步骤:terraform init
terraform plan
terraform apply
对于任何其他分支,执行以下步骤:
- 对于所有
environments
子文件夹,执行terraform init
- 对于所有
environments
子文件夹,执行terraform plan
- 对于所有
为了确保建议的更改适用于每种环境,请为所有 environments
子文件夹运行 terraform init
和 terraform plan
。例如,在合并拉取请求之前,您可以查看这些方案,以确保不会对未经授权的实体授予访问权限等等。
将 Terraform 配置为在 Cloud Storage 存储桶中存储状态
默认情况下,Terraform 会将状态存储在名为 terraform.tfstate
的本地文件中。采用此默认配置,使用 Terraform 对团队而言可能会很困难,尤其是当许多用户同时运行 Terraform 并且每个机器都对当前基础架构有自己的理解时。
为帮助您避免此类问题,本部分将配置指向 Cloud Storage 存储桶的远程状态。远程状态是一项backends功能,在本教程中,该功能在 backend.tf
文件中进行配置,例如:
在以下步骤中,您将创建一个 Cloud Storage 存储桶,并将一些文件更改为指向新存储桶和 Google Cloud 项目。
在 Cloud Shell 中,创建 Cloud Storage 存储桶:
1. 启用对象版本控制,以保留部署历史记录:PROJECT_ID=$(gcloud config get-value project) gsutil mb gs://${PROJECT_ID}-tfstate
```sh gcloud storage buckets update gs://${PROJECT_ID}-tfstate --versioning ``` Enabling Object Versioning increases [storage costs](/storage/pricing){: track-type="tutorial" track-name="internalLink" track-metadata-position="body" }, which you can mitigate by configuring [Object Lifecycle Management](/storage/docs/lifecycle){: track-type="tutorial" track-name="internalLink" track-metadata-position="body" } to delete old state versions.
将
PROJECT_ID
占位符替换为terraform.tfvars
和backend.tf
文件中的项目 ID:cd ~/solutions-terraform-cloudbuild-gitops sed -i s/PROJECT_ID/$PROJECT_ID/g environments/*/terraform.tfvars sed -i s/PROJECT_ID/$PROJECT_ID/g environments/*/backend.tf
在 OS X/MacOS 上,您可能需要在
sed -i
后添加两个引号 (""
),如下所示:cd ~/solutions-terraform-cloudbuild-gitops sed -i "" s/PROJECT_ID/$PROJECT_ID/g environments/*/terraform.tfvars sed -i "" s/PROJECT_ID/$PROJECT_ID/g environments/*/backend.tf
检查是否所有文件都已更新:
git status
输出类似于以下内容:
On branch dev Your branch is up-to-date with 'origin/dev'. Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: environments/dev/backend.tf modified: environments/dev/terraform.tfvars modified: environments/prod/backend.tf modified: environments/prod/terraform.tfvars no changes added to commit (use "git add" and/or "git commit -a")
提交并推送您的更改:
git add --all git commit -m "Update project IDs and buckets" git push origin dev
根据您的 GitHub 配置,您需要进行身份验证才能推送上述更改。
向您的 Cloud Build 服务账号授予权限
如需允许 Cloud Build 服务账号运行 Terraform 脚本以管理 Google Cloud 资源,您需要向其授予项目的相应访问权限。为简单起见,本教程中授予了 Project Editor 访问权限。但是,如果 Project Editor 角色具有较宽泛的权限,那么在生产环境中,您必须遵循公司的 IT 安全最佳做法,此类最佳做法通常提供的是最低访问权限。
在 Cloud Shell 中,从电子邮件中检索项目的 Cloud Build 服务账号:
CLOUDBUILD_SA="$(gcloud projects describe $PROJECT_ID \ --format 'value(projectNumber)')@cloudbuild.gserviceaccount.com"
向 Cloud Build 服务账号授予所需的访问权限:
gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:$CLOUDBUILD_SA --role roles/editor
将 Cloud Build 直接连接到 GitHub 代码库
本部分介绍如何安装 Cloud Build GitHub 应用。在此安装过程中,您可以将 GitHub 代码库与 Google Cloud 项目关联,这样每当您创建新分支或将代码推送到 GitHub 时,Cloud Build 都能自动应用 Terraform 清单。
以下步骤提供了仅针对
solutions-terraform-cloudbuild-gitops
代码库安装该应用的说明,但您可以选择针对更多或所有代码库安装该应用。转到 Cloud Build 应用的 GitHub Marketplace 页面:
- 如果您是第一次在 GitHub 中配置应用,请点击页面底部的使用 Google Cloud Build 进行设置。然后点击向此应用授予对 GitHub 账号的访问权限。
- 如果这不是在 GitHub 中首次配置应用:请点击配置访问权限。您的个人账号的应用页面随即打开。
点击 Cloud Build 行中的配置。
选择仅选择代码库,然后选择
solutions-terraform-cloudbuild-gitops
以连接到该代码库。点击保存或安装 - 按钮标签会因工作流而异。系统会将您重定向到 Google Cloud 以继续安装。
使用您的 Google Cloud 账号登录。如果需要,请授权 Cloud Build 与 GitHub 集成。
在 Cloud Build 页面上,选择您的项目。系统会显示一个向导。
在选择代码库部分中,选择您的 GitHub 账号和
solutions-terraform-cloudbuild-gitops
代码库。如果您同意这些条款及条件,请选中复选框,然后点击连接。
在创建触发器部分,点击创建触发器:
- 添加触发器名称,例如
push-to-branch
。请记下此触发器名称,稍后您将用到它。 - 在事件部分中,选择推送到分支。
- 在来源部分的分支字段中,选择
.*
。 - 点击创建。
- 添加触发器名称,例如
Cloud Build GitHub 应用现已配置完毕,您的 GitHub 代码库已关联到您的 Google Cloud 项目。从现在起,对 GitHub 代码库的更改会触发 Cloud Build 的执行操作,该操作会使用 GitHub 检查将结果发回 GitHub。
更改新功能分支中的环境配置
到目前为止,您已经配置了环境的大部分设置。现在,您可以在开发环境中更改代码了。
在 GitHub 中,导航到分支代码库的主页。
https://github.com/YOUR_GITHUB_USERNAME/solutions-terraform-cloudbuild-gitops
确保您位于
dev
分支中。如需打开文件进行修改,请转至
modules/firewall/main.tf
文件,然后点击铅笔图标。在第 30 行,更正
target_tags
字段中的"http-server2"
拼写错误。该值必须为
"http-server"
。在页面底部添加提交消息,例如“Fixing http firewall target”(修复 http 防火墙目标),然后选择 Ceate a new branch for this commit and start a pull request。
点击建议修改。
在随后出现的页面上,点击 Create pull request,以打开包含更改的新拉取请求。
打开拉取请求后,系统会自动启动 Cloud Build 作业。
点击 Show all checks,然后等待检查变为绿色。
点击 Details 查看更多信息,包括 View more details on Google Cloud Build 链接中
terraform plan
的输出。
暂时不要合并拉取请求。
请注意,Cloud Build 作业运行了
cloudbuild.yaml
文件中定义的流水线。如前所述,根据所提取的分支,此流水线的行为会有所不同。该构建会检查$BRANCH_NAME
变量是否与任何环境文件夹匹配。如果匹配,Cloud Build 会针对该环境执行terraform plan
。否则,Cloud Build 会针对所有环境执行terraform plan
,以确保建议的更改适用于所有环境。如果这些方案中的任一方案未能执行,构建会失败。同样,
terraform apply
命令会针对各环境分支运行,但它在任何其他情况下都会被完全忽略。在此部分中,您是向新分支提交的代码更改,因此未对您的 Google Cloud 项目应用任何基础架构部署。强制 Cloud Build 执行成功后才合并分支
如需确保仅在各个 Cloud Build 执行成功时才应用合并,请继续执行以下步骤:
在 GitHub 中,导航到分支代码库的主页。
https://github.com/YOUR_GITHUB_USERNAME/solutions-terraform-cloudbuild-gitops
在代码库名称下,点击设置。
在左侧菜单中,点击 Branches。
在 Branch protection rules 下,点击 Add rule。
在分支名称模式中,输入
dev
。在保护匹配的分支部分中,选择合并前需要先通过状态检查。
搜索您之前创建的 Cloud Build 触发器名称。
点击创建。
重复第 3 步到第 7 步,将分支名称模式 (Branch name pattern) 设置为
prod
。
此配置非常重要,可用于保护
dev
和prod
分支。这意味着,必须首先将提交内容推送到另一个分支,然后才能将它们合并到受保护的分支。在本教程中,该保护机制要求 Cloud Build 执行成功后,才能合并提交内容。推广对开发环境的更改
您有一个待合并的拉取请求。现在可以对您的
dev
环境应用所需的状态。在 GitHub 中,导航到分支代码库的主页。
https://github.com/YOUR_GITHUB_USERNAME/solutions-terraform-cloudbuild-gitops
在代码库名称下,点击 Pull requests。
点击您刚创建的拉取请求。
点击 Merge pull request,然后点击 Confirm merge。
检查是否已触发新的 Cloud Build:
打开该构建并检查日志。
构建完成后,您会看到如下内容:
Step #3 - "tf apply": external_ip = EXTERNAL_IP_VALUE Step #3 - "tf apply": firewall_rule = dev-allow-http Step #3 - "tf apply": instance_name = dev-apache2-instance Step #3 - "tf apply": network = dev Step #3 - "tf apply": subnet = dev-subnet-01
复制
EXTERNAL_IP_VALUE
,并在网络浏览器中打开该地址。http://EXTERNAL_IP_VALUE
此配置可能需要几秒钟时间来启动虚拟机并传播防火墙规则。最终,您将在网络浏览器中看到 Environment: dev。
导航到 Cloud Storage 存储桶中的 Terraform 状态文件。
https://storage.cloud.google.com/PROJECT_ID-tfstate/env/dev/default.tfstate
推广对生产环境的更改
现在,您已经对开发环境进行了全面测试,可以将您的基础架构代码推广到生产环境。
在 GitHub 中,导航到分支代码库的主页。
https://github.com/YOUR_GITHUB_USERNAME/solutions-terraform-cloudbuild-gitops
在代码库名称下,点击 Pull requests。
点击 New pull request。
对于 base repository,请选择刚创建的分支代码库。
对于 base,请从您自己的基本代码库中选择
prod
。对于比较,请选择dev
。点击创建拉取请求。
对于 title,请输入一个标题(如
Promoting networking changes
),然后点击 Create pull request。查看建议的更改,包括 Cloud Build 中的
terraform plan
详细信息,然后点击 Merge pull request。点击 Confirm merge。
在 Google Cloud 控制台中,打开构建记录页面,查看应用到生产环境的更改:
等待构建完成,然后检查日志。
日志末尾会显示如下内容:
Step #3 - "tf apply": external_ip = EXTERNAL_IP_VALUE Step #3 - "tf apply": firewall_rule = prod-allow-http Step #3 - "tf apply": instance_name = prod-apache2-instance Step #3 - "tf apply": network = prod Step #3 - "tf apply": subnet = prod-subnet-01
复制
EXTERNAL_IP_VALUE
,并在网络浏览器中打开该地址。http://EXTERNAL_IP_VALUE
此配置可能需要几秒钟时间来启动虚拟机并传播防火墙规则。最终,您将在网络浏览器中看到 Environment: prod。
导航到 Cloud Storage 存储桶中的 Terraform 状态文件。
https://storage.cloud.google.com/PROJECT_ID-tfstate/env/prod/default.tfstate
您已在 Cloud Build 上成功配置了无服务器基础架构即代码流水线。以后,您可能想要尝试以下操作:
- 针对不同的使用情形添加部署。
- 创建其他环境以满足您的需求。
- 每个环境使用一个项目,而非每个环境使用一个 VPC。
清理
完成本教程后,请清理您在 Google Cloud 上创建的资源,以免这些资源将来产生费用。
删除项目
- In the Google Cloud console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- In the dialog, type the project ID, and then click Shut down to delete the project.
删除 GitHub 代码库
为避免在 GitHub 代码库中阻止新的拉取请求,您可以删除分支保护规则:
- 在 GitHub 中,导航到分支代码库的主页。
- 在代码库名称下,点击设置。
- 在左侧菜单中,点击 Branches。
- 在分支保护规则部分,点击
dev
和prod
行的删除按钮。
或者,您可以从 GitHub 中完全卸载 Cloud Build 应用:
转到您的 GitHub 应用设置。
在已安装的 GitHub 应用 (Installed GitHub Apps) 标签页中,点击 Cloud Build 行中的配置。然后,在危险可用区 (Danger zone) 部分中,点击卸载 Google Cloud Builder (Uninstall Google Cloud Builder) 行中的卸载按钮。
在页面顶部,您会看到一条消息:“您已设置完毕。作业已加入队列以卸载 Google Cloud Build。”
在已获授权的 GitHub 应用标签页中,点击 Google Cloud Build 行中的撤消按钮,然后选中弹出窗口中的我了解,撤消访问权限。
如果您不想保留 GitHub 代码库,请执行以下操作:
- 在 GitHub 中,转到分支代码库的主页面。
- 在代码库名称下,点击设置。
- 向下滚动到危险可用区。
- 点击删除此代码库,然后按照确认步骤操作。
后续步骤
- 考虑使用 Cloud Foundation Toolkit 模板在 Google Cloud 中快速构可重复的企业级基础环境。
- 观看 Next' 19 视频借助 Cloud Build 的基础架构即代码流水线规模化创建可重复的 Google Cloud 环境,了解本教程中介绍的 GitOps 工作流。
- 查看使用 Cloud Build 实现 GitOps 形式的持续交付教程。
- 查看更高级的 Cloud Build 功能:配置构建步骤的顺序、构建、测试和部署工件以及创建自定义构建步骤。
- 查看使用 Cloud Build 确保 Terraform 部署的规模和合规性中的博客。
- 阅读我们关于 DevOps 的资源。
- 详细了解与本教程相关的 DevOps 功能:
- 进行 DevOps 快速检查,了解您与业界其他公司相比所处的位置。