本教程介绍如何使用常用的 GitOps 方法,通过 Terraform 和 Cloud Build 以代码形式管理基础设施。术语 GitOps 一词由 Weaveworks 首先提出,其主要概念是使用 Git 代码库来存储您所需的环境状态。Terraform 是一种 HashiCorp 开源工具,可让您使用代码以可预测的方式创建、更改和改进您的云基础架构。在本教程中,您将使用 Cloud Build(一个 Google Cloud 持续集成服务)自动将 Terraform 清单应用到您的环境。
本教程适用于正在寻求一种出色的解决方案来以可预测的方式对基础架构做出更改的开发者和运维人员。本文假设您熟悉 Google Cloud和 Linux。
DevOps 现状报告确定了可提高软件交付方面表现的功能。本教程将帮助您使用以下功能:
架构
本教程应用 GitOps 实践来管理 Terraform 执行。请注意,它使用 Secure Source Manager 分支 dev 和 prod 来表示实际环境。这些环境分别由Google Cloud 项目中的虚拟私有云 (VPC) 网络 dev 和 prod 定义。
当您将 Terraform 代码推送到 dev 或 prod 分支时,该过程就会启动。在这种情况下,Cloud Build 会触发,然后会应用 Terraform 清单在相应环境中实现所需状态。另一方面,当您将 Terraform 代码推送到任何其他分支(例如,某个功能分支)时,Cloud Build 会运行以执行 terraform plan,但不会对任何环境应用任何内容。
理想情况下,开发者或运维人员必须向开发分支或功能分支提出基础设施提案,然后通过拉取请求提交这些提案。这样,您就可以与协作者讨论和查看潜在更改,并在将更改合并到基本分支之前添加后续提交。
如果不存在任何问题,您必须先将更改合并到 dev 分支。此合并会触发将基础架构部署到 dev 环境的操作,如此您便可以测试此环境。在测试所部署的内容并确信其没有问题之后,您必须将 dev 分支合并到 prod 分支,以触发在生产环境中安装基础架构的操作。
目标
- 设置 Secure Source Manager 实例和代码库。
- 将 Terraform 配置为在 Cloud Storage 存储桶中存储状态。
- 向您的 Cloud Build 服务账号授予权限。
- 将 Cloud Build 连接到 Secure Source Manager 代码库。
- 更改功能分支中的环境配置。
- 将更改升级到开发环境。
- 推广对生产环境的更改。
费用
在本文档中,您将使用 Google Cloud的以下收费组件:
如需根据您的预计使用情况来估算费用,请使用价格计算器。
完成本文档中描述的任务后,您可以通过删除所创建的资源来避免继续计费。如需了解详情,请参阅清理。
准备工作
- 登录您的 Google Cloud 账号。如果您是 Google Cloud新手,请 创建一个账号来评估我们的产品在实际场景中的表现。新客户还可获享 $300 赠金,用于运行、测试和部署工作负载。
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
Roles required to select or create a project
- Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
-
Create a project: To create a project, you need the Project Creator role
(
roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.createpermission. Learn how to grant roles.
-
Verify 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.
Roles required to select or create a project
- Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
-
Create a project: To create a project, you need the Project Creator role
(
roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.createpermission. Learn how to grant roles.
-
Verify that billing is enabled for your Google Cloud project.
-
在 Google Cloud 控制台中,激活 Cloud Shell。
Cloud Shell 会话随即会在 Google Cloud 控制台的底部启动,并显示命令行提示符。Cloud Shell 是一个已安装 Google Cloud CLI 且已为当前项目设置值的 Shell 环境。该会话可能需要几秒钟时间来完成初始化。
- 在 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 securesourcemanager.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"
设置 Secure Source Manager 代码库
在本教程中,您将使用一个 Secure Source Manager 代码库来定义您的云基础架构。您还可以通过使不同的分支对应于不同的环境,来编排此基础架构:
dev分支包含应用于开发环境的最新更改。prod分支包含应用于生产环境的最新更改。- 类似于
feature_x的功能分支用于在推送到dev或prod分支之前进行更改。
借助此基础架构,您可以随时参考代码库以了解每个环境中的预期配置,并通过先将它们合并到 dev 环境中来提出新的更改建议。然后,您可以通过将 dev 分支合并到后续的 prod 分支来推广更改。
- 创建空的 Secure Source Manager 代码库 - 请勿初始化代码库。
通过运行以下命令,将 Secure Source Manager 身份验证帮助程序添加到全局
git config:git config --global credential.'https://*.*.sourcemanager.dev'.helper gcloud.sh当您将 Git 命令与 Secure Source Manager 搭配使用时,身份验证帮助程序会使用 gcloud CLI 来获取您的Google Cloud 凭据。
如需在初始凭据设置后重新进行身份验证,请运行以下 gcloud CLI 命令:
gcloud auth login将 solutions-terraform-cloudbuild-gitops 代码库克隆到本地 shell 或工作环境:
git clone https://github.com/GoogleCloudPlatform/solutions-terraform-cloudbuild-gitops.git将 Secure Source Manager 代码库添加为上游。
git remote add google HTTPS_REPO_URL其中,
HTTPS_REP_URL是 Secure Source Manager 代码库的 HTTPS 网址。您可以在 Secure Source Manager 网页界面中,在代码库页面顶部找到该网址。创建并切换到
dev分支。git checkout dev使用以下命令将克隆的代码库推送到您的代码库:
git push -u google --all针对
prod分支重复前两个步骤。
此代码库中代码的结构如下所示:
environments/文件夹包含代表环境(例如dev和prod)的子文件夹,它们将处于不同成熟阶段(分别为开发和生产阶段)的工作负载进行逻辑分隔。尽管让这些环境尽可能保持相似是不错的做法,但每个子文件夹都有自己的 Terraform 配置,以确保它们可以根据需要采用独特的设置。modules/文件夹包含内嵌 Terraform 模块。这些模块代表相关资源的逻辑分组,用于跨不同环境共享代码。cloudbuild.yaml文件是包含 Cloud Build 说明的 build 配置文件,例如如何根据一系列步骤执行任务。此文件根据 Cloud Build 从中提取代码的分支指定条件执行,例如:对于
dev和prod分支,执行以下步骤:terraform initterraform planterraform apply
对于任何其他分支,执行以下步骤:
- 对于所有
environments子文件夹,执行terraform init - 对于所有
environments子文件夹,执行terraform plan
- 对于所有
为了确保建议的更改适用于每种环境,请为所有 environments 子文件夹运行 terraform init 和 terraform plan。例如,在合并拉取请求之前,您可以查看这些方案,以确保不会对未经授权的实体授予访问权限等等。
修改 build 配置文件
如需使示例 build 配置文件与 Secure Source Manager 搭配使用,您需要进行以下修改:
- 添加一个克隆代码库的步骤。
- 添加一个步骤,以获取分支名称并将其分配给一个变量。
修改 dev 分支中的 build 配置文件:
切换到
dev分支:git checkout dev打开
cloudbuild.yaml文件并将其内容替换为以下内容:# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. steps: - id: 'clone repository' name: 'gcr.io/cloud-builders/git' args: - clone - '${_REPO_URL}' - . - id: 'branch name' name: gcr.io/cloud-builders/git entrypoint: 'sh' args: - '-c' - | branch=$(basename "$_REF") git checkout ${branch} echo "***********************" git branch --show-current echo "***********************" - id: 'tf init' name: 'hashicorp/terraform:1.0.0' entrypoint: 'sh' args: - '-c' - | branch=$(basename "$_REF") if [ -d "environments/${branch}/" ]; then cd environments/${branch} terraform init else for dir in environments/*/ do cd ${dir} env=${dir%*/} env=${env#*/} echo "" echo "*************** TERRAFORM INIT ******************" echo "******* At environment: ${env} ********" echo "*************************************************" terraform init || exit 1 cd ../../ done fi - id: 'tf plan' name: 'hashicorp/terraform:1.0.0' entrypoint: 'sh' args: - '-c' - | branch=$(basename "$_REF") if [ -d "environments/${branch}/" ]; then cd environments/${branch} terraform plan else for dir in environments/*/ do cd ${dir} env=${dir%*/} env=${env#*/} echo "" echo "*************** TERRAFOM PLAN ******************" echo "******* At environment: ${env} ********" echo "*************************************************" terraform plan || exit 1 cd ../../ done fi - id: 'tf apply' name: 'hashicorp/terraform:1.0.0' entrypoint: 'sh' args: - '-c' - | branch=$(basename "$_REF") if [ -d "environments/${branch}/" ]; then cd environments/${branch} terraform apply -auto-approve else echo "***************************** SKIPPING APPLYING *******************************" echo "Branch '${branch}' does not represent an official environment." echo "*******************************************************************************" fi
检查文件是否已修改。
git status提交并推送您的更改:
git add --all git commit -m "Modify build config file." git push google dev打开拉取请求,以便快速将更改提升到
prod分支。- 在 Secure Source Manager 网页界面中,前往您的代码库。
- 点击 Pull request 标签页。
- 点击 New pull request。
- 在合并到:字段中,选择
prod分支。 - 在从以下位置拉取:字段中,选择
dev分支。 - 查看更改,然后点击新建拉取请求。
- 点击创建拉取请求。
- 点击合并拉取请求。
再次点击合并拉取请求。
相应更改会合并到您的
prod分支中。
将 Terraform 配置为在 Cloud Storage 存储桶中存储状态
默认情况下,Terraform 会将状态存储在名为 terraform.tfstate 的本地文件中。采用此默认配置,使用 Terraform 对团队而言可能会很困难,尤其是当许多用户同时运行 Terraform 并且每个机器都对当前基础架构有自己的理解时。
为帮助您避免此类问题,本部分将配置指向 Cloud Storage 存储桶的远程状态。远程状态是一项backends功能,在本教程中,该功能在 backend.tf 文件中进行配置,例如:
在以下步骤中,您将创建一个 Cloud Storage 存储桶,并将一些文件更改为指向新存储桶和您的项目。 Google Cloud
在 Cloud Shell 中,创建 Cloud Storage 存储分区:
PROJECT_ID=$(gcloud config get-value project) gcloud storage buckets create gs://${PROJECT_ID}-tfstate启用对象版本控制,以保留部署历史记录:
gcloud storage buckets update gs://${PROJECT_ID}-tfstate --versioning创建一个新的
cloud-storage-bucket分支以在其中进行更改:cd ~/solutions-terraform-cloudbuild-gitops git checkout -b cloud-storage-bucket将
PROJECT_ID占位符替换为terraform.tfvars和backend.tf文件中的项目 ID: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后添加两个引号 (""),如下所示: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 cloud-storage-bucket Changes not staged for commit: (use "git add
..." to update what will be committed) (use "git restore ..." 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 google -u cloud-storage-bucket您的新
cloud-storage-bucket分支已推送到代码库。通过为每个分支打开并提交合并请求,将
cloud-storage-bucket中的更改合并到dev和prod分支中。
向您的 Cloud Build 服务账号授予权限
如需允许 Cloud Build 服务账号运行 Terraform 脚本以管理 Google Cloud 资源,您需要向其授予项目的相应访问权限。为简单起见,本教程中授予了 Project Editor 访问权限。对于生产环境,请遵循公司的 IT 安全最佳实践,此类最佳实践通常提供的是最低访问权限。
如需查找 Cloud Build 服务账号电子邮件地址,请在 Cloud Build 页面中前往设置。
复制服务账号电子邮件地址的值。
向 Cloud Build 服务账号授予所需的访问权限:
gcloud projects add-iam-policy-binding PROJECT_ID \ --member serviceAccount:CLOUDBUILD_SA --role roles/editor替换以下内容:
- PROJECT_ID 替换为您的项目 ID。
- 将 CLOUDBUILD_SA 替换为 Cloud Build 服务账号电子邮件地址。
连接到 Cloud Build
如需在向任何分支推送时触发 Cloud Build,请设置 Secure Source Manager Webhook。build 配置将检查分支名称,以确定是否需要对 dev 或 prod 环境进行更改。
在项目中启用并设置 Cloud Build。
在 Google Cloud 控制台中打开触发器页面。
从页面顶部的项目选择器下拉菜单中选择您的项目。
点击打开。
点击创建触发器。
输入以下触发器设置:
名称:
trigger-on-push区域:选择触发器的区域。如果与触发器关联的 build 配置文件指定了专用池,则您为触发器选择的区域必须与专用池的区域一致。
如果您选择
global作为区域,Cloud Build 会使用 build 配置文件中指定的区域来运行构建。如果您在 build 配置中指定了专用池,则可以是专用池的区域;如果您未指定专用池,则可以是全局默认池。说明(可选):输入触发器的说明。
事件:选择 Webhook 事件作为用于调用触发器的代码库事件。
如果未安装 Secret Manager,系统会提示您启用 Secret Manager。
网络钩子网址:选择以下选项之一:
- 如果您想使用 Cloud Build 生成新的 Secret,请选择使用新的 Secret。点击创建密钥以创建密钥。
- 如果您想使用现有密文,请使用现有密文或创建自己的密文。在下拉选择框中输入密文和版本。
如果您使用现有 Secret,则可能需要手动向 Cloud Build 服务代理
service-PROJECT_NUMBER@gcp-sa-cloudbuild.iam.gserviceaccount.com授予 Secret Manager Secret Accessor 角色。如需了解详情,请参阅向 Cloud Build 服务代理授予角色。
点击显示网址预览,然后记录该网址。您需要此网址才能在 Secure Source Manager 中设置网络钩子。
- 配置:对于类型,选择 Cloud Build 配置文件(YAML 或 JSON);对于位置,选择内嵌。
点击打开编辑器按钮,修改您的 build 配置文件。
将
cloudbuild.yaml文件的内容复制到编辑器中。如前所述,根据所提取的分支,此流水线的行为会有所不同。该 build 会检查
${branch}变量是否与任何环境文件夹匹配。如果匹配,Cloud Build 会针对该环境执行terraform plan。否则,Cloud Build 会针对所有环境执行terraform plan,以确保建议的更改适用于所有环境。如果这些方案中的任一方案未能执行,构建会失败。- id: 'tf plan' name: 'hashicorp/terraform:1.0.0' entrypoint: 'sh' args: - '-c' - | branch=$(basename "$_REF") if [ -d "environments/${branch}/" ]; then cd environments/${branch} terraform plan else for dir in environments/*/ do cd ${dir} env=${dir%*/} env=${env#*/} echo "" echo "*************** TERRAFOM PLAN ******************" echo "******* At environment: ${env} ********" echo "*************************************************" terraform plan || exit 1 cd ../../ done fi
terraform apply命令会针对各环境分支运行,但它在任何其他情况下都会被完全忽略。点击 + 添加变量,然后添加以下两个替换变量:
- 变量:
_REPO_URL,值:$(body.repository.clone_url) - 变量:
_REF,值:$(body.ref)
- 变量:
点击创建。
在 Secure Source Manager 中设置 webhook
创建 Webhook 以在向 dev 或 prod 分支推送时触发构建。
- 在 Secure Source Manager 网页界面中,找到要为其创建 Webhook 的代码库。
- 点击设置。
- 点击 Webhooks,然后点击 Add webhook。
在 Hook ID 字段中,输入 Webhook 的 ID。
在目标网址字段中,输入您在 Cloud Build 中设置网络钩子触发器时复制的网络钩子网址。
如需查找网络钩子网址,请执行以下操作:
在 Google Cloud 控制台中打开触发器页面。
点击相应触发器。
在 网络钩子网址 部分,点击显示网址预览,然后复制网址。
网络钩子网址包含您在创建 Cloud Build 构建触发器时输入的密钥和密钥值。为防止这些值泄露,请从目标网址末尾移除这些值,然后将其复制到敏感查询字符串字段。
如需在网络钩子网址中找到您的密钥和密令,请查找以
key=开头的文本例如,假设有以下网址:
https://cloudbuild.googleapis.com/v1/projects/my-project/triggers/test-trigger:webhook?key=eitIfKhYnv0LrkdsyHqIros8fbsheKRIslfsdngf&secret=Hello%20Secret%20Manager复制并移除目标网址字段中以问号
?key=...开头的部分。然后移除初始问号,将剩余部分key=...移至敏感查询字符串字段。点击 Add webhook。
Webhook 会显示在 Webhooks 页面中。
更改新功能分支中的环境配置
确保您位于
dev分支中:cd ~/solutions-terraform-cloudbuild-gitops git checkout dev拉取最新更改:
git pull创建
bug-fix分支以更改环境配置。git checkout -b bug-fix打开
modules/firewall/main.tf进行修改。在第 30 行,更正
target_tags字段中的"http-server2"拼写错误。该值必须为
"http-server"。提交并推送您的更改:
git add --all git commit -m "Fix typo." git push google -u bug-fix在 Google Cloud 控制台中打开 Cloud Build 记录页面:
点击构建即可查看更多信息,包括
terraform plan的输出。
请注意,Cloud Build 作业运行了 cloudbuild.yaml 文件中定义的流水线。如前所述,根据所提取的分支,此流水线的行为会有所不同。该构建会检查 ${branch} 变量是否与任何环境文件夹匹配。如果匹配,Cloud Build 会针对该环境执行 terraform plan。否则,Cloud Build 会针对所有环境执行 terraform plan,以确保建议的更改适用于所有环境。如果这些方案中的任一方案未能执行,构建会失败。
- id: 'tf plan' name: 'hashicorp/terraform:1.0.0' entrypoint: 'sh' args: - '-c' - | branch=$(basename "$_REF") if [ -d "environments/${branch}/" ]; then cd environments/${branch} terraform plan else for dir in environments/*/ do cd ${dir} env=${dir%*/} env=${env#*/} echo "" echo "*************** TERRAFOM PLAN ******************" echo "******* At environment: ${env} ********" echo "*************************************************" terraform plan || exit 1 cd ../../ done fi
同样,terraform apply 命令会针对各环境分支运行,但它在任何其他情况下都会被完全忽略。在此部分中,您是向新分支提交的代码更改,因此未对您的 Google Cloud 项目应用任何基础架构部署。
推广对开发环境的更改
现在可以对您的 dev 环境应用所需的状态。
- 在 Secure Source Manager 网页界面中,前往您的代码库。
- 点击 New pull request(新建拉取请求)
- 在合并到:字段中,选择您的
dev分支。 - 在 pull from: 字段中,选择您的
bug-fix分支。 - 点击 New pull request。
- 点击创建拉取请求。
- 点击 合并拉取请求,然后再次点击 合并拉取请求。
检查是否已触发新的 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 状态存储桶。存储桶名称如下所示:
PROJECT_ID-tfstate
依次点击 env 和 dev,以查看您的 Terraform 状态文件。
推广对生产环境的更改
现在,您已经对开发环境进行了全面测试,可以将您的基础架构代码推广到生产环境。
- 在 Secure Source Manager 网页界面中,前往您的代码库。
- 点击 Pull request 标签页。
- 点击 New pull request。
- 对于合并到:,请选择您的代码库
prod分支。 - 对于 pull from:,请选择您的代码库
dev分支。 - 点击 New pull request。
- 对于 title,请输入一个标题(如“Promoting networking changes”),然后点击 创建拉取请求。
查看建议的更改,然后点击合并拉取请求。
日期和代码库网址会添加到评论字段中。
再次点击合并拉取请求进行确认。
在 Google Cloud 控制台中,打开 Build 历史记录页面,查看应用到生产环境的更改:
等待构建完成,然后检查日志。
日志末尾会显示如下内容:
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 状态存储桶。存储桶名称如下所示:
PROJECT_ID-tfstate
依次点击 env 和 prod,即可查看您的 Terraform 状态文件。
您已在 Cloud Build 上成功配置了无服务器基础架构即代码流水线。以后,您可能想要尝试以下操作:
- 针对不同的使用情形添加部署。
- 创建其他环境以满足您的需求。
- 每个环境使用一个项目,而非每个环境使用一个 VPC。
清理
完成本教程后,请清理在Google Cloud 上创建的资源,避免日后再为这些资源付费。
删除项目
- 在 Google Cloud 控制台中,前往管理资源页面。
- 在项目列表中,选择要删除的项目,然后点击删除。
- 在对话框中输入项目 ID,然后点击关闭以删除项目。
后续步骤
- 考虑使用 Cloud Foundation Toolkit 模板在Google Cloud中快速构可重复的企业级基础环境。
- 观看 Next' 19 视频借助 Cloud Build 的基础架构即代码流水线规模化创建可重复的 Google Cloud 环境,了解本教程中介绍的 GitOps 工作流。
- 查看使用 Cloud Build 实现 GitOps 形式的持续交付教程。
- 查看更高级的 Cloud Build 功能:配置构建步骤的顺序、构建、测试和部署工件以及创建自定义构建步骤。
- 查看使用 Cloud Build 确保 Terraform 部署的规模和合规性中的博客。
- 阅读我们关于 DevOps 的资源。
- 详细了解与本教程相关的 DevOps 功能:
- 进行 DevOps 快速检查,了解您与业界其他公司相比所处的位置。