本教程介绍了如何借助 Google Kubernetes Engine (GKE) 使用现代持续集成/持续交付 (CI/CD) 技术来初始配置新应用、为应用开发功能以及将应用部署到生产环境。
本文档是以下系列文章中的一篇:
- 借助 GKE 实现现代 CI/CD:软件交付框架
- 借助 GKE 实现现代 CI/CD:构建 CI/CD 系统(参考架构)
- 借助 GKE 使用现代 CI/CD:应用开发者工作流(本文档)
在本教程中,您将使用 Skaffold、kustomize
、Artifact Registry、Config Sync、Cloud Build 和 Cloud Deploy 等工具来开发、构建和部署应用。
本文档面向企业架构师和应用开发者,以及 IT 安全、DevOps 和网站可靠性工程 (SRE) 团队。拥有一些自动化部署工具和流程的相关经验对于理解本文档中的概念很有用。
架构
在本教程中,您将初始配置新应用。然后,您可以开发新功能,并在开发、预演和生产环境中部署应用。 参考架构包含使用新流程初始配置和发布新应用所需的基础架构和工具:
从 CI 的代码库开始,工作流包括以下步骤:
您可以通过应用代码库共享应用源代码。
当您提交代码并将其推送到应用代码库时,它会自动在 Cloud Build 中触发持续集成流水线。CI 流程创建容器映像并将其推送到 Artifact Registry。
CI 流程还会在 Cloud Deploy 中为应用创建 CD 版本。
CD 版本使用
skaffold
为开发生成完全渲染的 kubernetes 清单,并将其部署到开发 GKE 集群中。然后,CD 版本从开发提升到预演目标,可生成完全渲染的预演清单并将其部署到预演 GKE 集群。
然后,CD 版本从预演环境提升到生产环境,可生成完全渲染的生产清单并将其部署到生产 GKE 集群中。
如需详细了解此工作流中使用的工具和基础架构,请参��“借助 GKE 使用现代 CI/CD:构建 CI/CD 系统”。
目标
初始配置新应用。
在开发环境中部署应用。
开发新功能并将其部署到开发环境中。
将新功能提升到预演环境,然后将其发布到生产环境中。
测试应用的弹性。
费用
在本文档中,您将使用 Google Cloud 的以下收费组件:
- Google Kubernetes Engine
- Google Kubernetes Engine (GKE) Enterprise edition for Config Sync
- Artifact Registry
- Cloud Build
- Cloud Deploy
您可使用价格计算器根据您的预计使用情况来估算费用。
完成本文档中描述的任务后,您可以通过删除所创建的资源来避免继续计费。如需了解详情,请参阅清理。
准备工作
- 在本教程中,部署本系列文章中的参考架构。
准备环境
如果您要直接从借助 GKE 使用现代 CI/CD:构建 CI/CD 系统继续操作,请转到下一部分。但是,如果您有一个新会话,或者会话已过期,请打开 Cloud Shell 并设置安装参考架构基础架构的项目:
gcloud config set core/project PROJECT_ID
将
PROJECT_ID
替换为您的 Google Cloud 项目 ID。
初始配置新应用
参考架构包含应用工厂。此工厂是名为 application-factory-repo
的 Git 代码库和以下 Cloud Build 触发器的集合:
create-app
tf-plan
tf-apply
create-team
您可以使用应用工厂从入门级代码库初始配置新应用。应用初始配置包括以下步骤:
创建应用定义:您可以在 Terraform 文件中创建应用定义,并将其存储在充当应用目录的
application-factory-repo
中。创建应用基础架构:在应用定义文件上运行 Terraform 以创建应用基础架构。应用基础架构包括以下组件:
新应用的着陆区包括在
acm-gke-infrastructure-repo
代码库中定义命名空间、服务账号和基本政策。着陆区仅在初始配置新应用时在开发 GKE 集群中创建。这样做是为了取消屏蔽开发者,以便他们能够使用开发环境并开始迭代。预演集群和生产集群中的着陆区通过 GitOps 方法创建。本文档稍后会在您准备提升这些集群中的版本时演示此方法。来自基础架构起始代码库的基础架构代码库(该代码库托管代码以在 Cloud Build 中创建 CI 流水线、在 Cloud Deploy 中创建 CD 流水线)以及用于存储工件的 Artifact Registry 代码库。
基础架构 Cloud Build 触发器,可采用基础架构代码库中的代码,并根据其定义创建资源。
来自应用起始代码库的应用代码库,用于托管应用的源代码。
创建应用的 CI/CD 资源:您可以使用应用基础架构为应用创建 CI/CD 资源。
创建应用定义:
运行 create-app
触发器以在 application-factory-repo
中生成应用定义文件。定义文件包含创建应用所需的资源的声明性定义。
在 Google Cloud 控制台中,转到 Cloud Build 页面:
点击
create-app
触发器。点击显示网址预览以显示调用 webhook 所需的网址。
在 Cloud Shell 中,通过对上一步中获得的网址发出 curl 请求并将参数作为载荷传递给该参数来调用触发器。
curl "WEBHOOK_URL" -d '{"message": {"app": "sample","runtime": "python","trigger_type": "webhook","github_team": ""}}'
在上述代码示例中:
将
WEBHOOK_URL
替换为从触发器获取的网址。"app": "sample"
指定应用的名称。"runtime": "python"
指示应用工厂使用 Python 模板创建应用代码库。"trigger_type": "webhook"
指定应用的 CI/CD 流水线类型。"github_team": ""
是 GitHub 中将与为应用创建的代码库关联的团队。您尚���创建 GitHub 团队,因此请以空字符串的形式传递。
检查流水线中是否存在
create-app
触发器:create-app
触发器有一个新流水线。完成此操作后,系统会在application-factory-repo
中创建应用定义。查看应用定义文件:
在网络浏览器中,转到 GitHub 并登录您的账号。
点击图片图标,然后点击
Your organizations
选择您的组织。点击代码库
application-factory-repo
,转到文件夹apps/python
,然后打开由create-app
触发器创建的名为sample.tf
的新文件。检查该文件,此文件包含 Terraform 代码以创建新应用。
创建应用基础架构:
现在您已经创建了应用定义,接下来运行触发器 tf-apply
来创建应用基础架构。
在 Google Cloud 控制台中:
点击
tf-apply
触发器。点击“显示网址预览”,以显示调用 webhook 所需的网址。
调用触发器:
curl "WEBHOOK_URL" -d '{}'
在上述代码示例中:
- 将
WEBHOOK_URL
替换为从触发器获取的网址。
- 将
检查流水线中是否存在
tf-apply
触发器:tf-apply
触发器有一个新流水线。等待它完成。
此触发器会创建应用基础架构。
审核应用基础架构:
查看应用基础架构的各种组件。
着陆区
转到 Cloud Shell 并设置项目。
gcloud config set core/project PROJECT_ID
将
PROJECT_ID
替换为您的 Google Cloud 项目 ID。获取开发 GKE 集群的凭据。
gcloud container clusters get-credentials gke-dev-us-central1 --zone us-central1-a
检查应用的命名空间。命名空间以应用示例命名。
kubectl get namespaces sample
输出类似以下内容:
NAME STATUS AGE sample Active 15m
检查命名空间中的服务账号。
kubectl get serviceaccounts -n sample
除了默认服务账号之外,还有一个服务账号。输出类似以下内容:
NAME SECRETS AGE default 0 15m sample-ksa 0 15m
基础架构代码库
在网络浏览器中,转到 GitHub 并登录您的账号。 点击照片图标。然后点击 Your organizations
。选择您的组织,然后点击 sample-infra
代码库。
此代码库有四个分支:cicd-trigger
、dev
、staging
和 prod
。它还包含四个 cicd-trigger、dev、staging 和 prod 文件夹。默认分支为 cicd-trigger
,您可以将代码推送到其中,而其他分支则具有保护规则,因此您无法将代码直接推送到这些分支。为了将代码推送到这些分支,您需要创建拉取请求。cicd-trigger
文件夹包含用于为应用创建 CI/CD 资源的代码,而 dev
、staging
和 prod
文件夹包含用于为应用的不同环境创建基础架构的代码。
基础架构触发器
在 Google Cloud 控制台中:
有一个名为
deploy-infra-sample
的新触发器。此触发器已连接到代码库
sample-infra
,因此当代码推送到此代码库时,将调用该触发器并确定触发推送的分支,然后转到该分支上的相应文件夹,并在该处运行 Terraform。例如,如果代码推送到cicd-trigger
分支,则触发器会在 cicd-trigger 分支的 cicd-trigger 文件夹上运行 Terraform。同样,当推送到dev
分支时,触发器会在开发分支的开发文件夹上运行 Terraform,依此类推。
应用代码库
- 转到 GitHub 并拉取组织下的代码库。有一个名为
sample
的新代码库。此代码库托管在Dockerfile
中构建容器的源代码和步骤、kustomize
配置(描述应用的所需配置),以及skaffold.yaml
(定义 Cloud Deploy for CD 要使用的部署步骤)。
创建应用 CI/CD 资源
现在您已经创建了应用的框架,接下来运行触发器 deploy-infra-sample
以创建其 CI/CD 资源。您可以使用触发器的 webhook 网址或向 Git 代码库 sample-infra
提交来手动调用触发器。
如需调用 Cloud Build 触发器,请在代码库的文件中添加一个新行。然后,推送更改:
如果您从未在 Cloud Shell 中使用过 Git,请使用您的姓名和电子邮件地址配置 Git。Git 根据这些信息确定您就是在 Cloud Shell 中创建的提交的作者本人。
git config --global user.email "GITHUB_EMAIL_ADDRESS" git config --global user.name "GITHUB_USERNAME"
替换以下内容:
GITHUB_EMAIL_ADDRESS
:与您的 GitHub 账号关联的电子邮件地址GITHUB_USERNAME
:与您的 GitHub 账号关联的用户名
克隆 Git 代码库
sample-infra
:git clone https://github.com/GITHUB_ORG/sample-infra cd sample-infra
替换以下内容:
- 将
GITHUB_ORG
替换为您的 GitHub 组织。
默认分支 cicd 触发器已签出。
- 将
在 env/cicd-trigger/main.tf 文件中添加新行,提交更改并推送。
echo "" >> env/cicd-trigger/main.tf
提交并推送更改:
git add . git commit -m "A dummy commit to invoke the infrastrucutre trigger" git push cd ..
推送更改后,Cloud Deploy 触发器
deploy-infra-sample
会启动。
监控触发器的状态:
前往 Cloud Build 历史记录页面,查看流水线,并等待它完成。
查看应用 CICD 资源
查看为应用创建的各种 CI/CD 资源。
在 Google Cloud 控制台中:
转到 Cloud Build 页面,并查看
deploy-app-sample
触发器。这是 CI 流水线触发器。该触发器已连接到应用代码库
sample
。推送到应用代码库时,系统会调用触发器,并按照触发器配置中的定义执行构建步骤。如需查看触发器调用时执行的步骤,请点击触发器名称,然后点击打开编辑器���钮。转到 Artifact Registry 页面,查看名为
sample
的新代码库。此工件代码库存储应用的工件。
转到 Cloud Deploy 流水线页面,查看名为
sample
的流水线。 这是在 GKE 集群上部署应用的持续部署流水线。
在开发环境中部署应用
触发器 deploy-app-sample
连接到名为 sample
的应用代码库。您可以使用 webhook 网址手动调用触发器,也可以通过推送至应用代码库来调用。
在代码库
sample
的文件中添加一个新行,然后推送更改以调用 Cloud Build 触发器:克隆 Git 代码库
sample
:在 Cloud Shell 中:
git clone https://github.com/GITHUB_ORG/sample cd sample
将
GITHUB_ORG
替换为您的 GitHub 语法。向
skaffold.yaml
文件中添加新行。echo "" >> skaffold.yaml
提交并推送更改:
git add . git commit -m "A dummy commit to invoke CI/CD trigger" git push
推送更改后,Cloud Deploy 触发器
deploy-app-sample
会启动。
监控触发器的状态:
前往 Cloud Build 历史记录页面,查看流水线,并等待它完成。
触发器会执行其配置中定义的步骤。第一步是从代码库
sample
中的应用代码构建 Docker 映像。最后一步是启动将应用部署到开发 GKE 集群的 Cloud Deploy 流水线。检查开发集群中的部署:
点击
sample
流水线,已开始部署到开发 GKE 集群。等待它完成。
验证应用已成功部署:
获取开发集群的凭据。
gcloud container clusters get-credentials gke-dev-us-central1 --zone us-central1-a
通过隧道连接到 GKE 集群。
gcloud container clusters get-credentials gke-dev-us-central1 --zone us-central1-a && kubectl port-forward --namespace sample $(kubectl get pod --namespace sample --selector="deploy.cloud.google.com/delivery-pipeline-id=sample" --output jsonpath='{.items[0].metadata.name}') 8080:8080
在 Cloud Shell 工具栏上,点击
网页预览,然后点击在端口 8080 上预览:输出如下所示:
Hello World!
在 Cloud Shell 中,按
CTRL+C
结束端口转发。
向应用添加新功能
开发新功能时,您需要将更改快速部署到开发环境中,以对更改进行测试和迭代。在本教程中,您将在应用代码库中进行更改,并将其部署到开发环境。
在 Cloud Shell 中,将目录更改为已克隆的
sample
代码库:更新应用以输出其他消息:
sed -i "s/Hello World/My new feature/g" main.py
提交并推送更改:
git add . git commit -m "Changed the message" git push
代码推送到 GitHub 代码库后,webhook 触发器
deploy-app-sample
便会启动。在 Cloud Build 历史记录页面上监控触发器的状态,并等待触发器运行完成。
-
点击
sample
流水线,已开始部署到开发 GKE 集群。等待它完成。
验证应用已成功部署:
如果您打开了新的 Cloud Shell,请获取开发集群的凭据:
gcloud container clusters get-credentials gke-dev-us-central1 --zone us-central1-a
通过隧道连接到 GKE 集群:
gcloud container clusters get-credentials gke-dev-us-central1 --zone us-central1-a && kubectl port-forward --namespace sample $(kubectl get pod --namespace sample --selector="deploy.cloud.google.com/delivery-pipeline-id=sample" --output jsonpath='{.items[0].metadata.name}') 8080:8080
在 Cloud Shell 工具栏上,点击
网页预览,然后点击在端口 8080 上预览:
输出如下所示:
My new feature!
在 Cloud Shell 中,按
CTRL+C
结束端口转发。
将您的更改升级到预演集群和生产集群
在将应用提升到预演环境和生产环境之前,您需要在 GKE 集群中为这些环境创建应用着陆区。当您初始配置应用时,通过将代码添加到开发分支中的 acm-gke-infrastructure-repo
,开发 GKE 集群会自动创建开发着陆区。
在预演和生产 GKE 集群中创建着陆区
在预演 GKE 集群中创建着陆区:您需要在
acm-gke-infrastructure-repo
中创建从开发到暂存分支的拉取请求并将其合并。转到 GitHub 并遍历代码库
acm-gke-infrastructure-repo
。点击Pull requests
,然后点击New pull request
按钮。在基本菜单中,选择暂存,然后在比较菜单中,选择开发。点击Create pull request
按钮。通常,有权访问代码库的人员会审核更改,然后合并 PR,以确保仅将预期更改提升到预演环境中。为了让个人试用参考架构,分支保护规则已放宽,以便代码库管理员可以绕过审核并合并 PR。如果您是代码库的管理员,请合并拉取请求。否则,请让管理员合并它。
Config Sync 将到达代码库
acm-gke-infrastructure-repo
的暂存分支的更改同步到预演 GKE 集群,该集群会导致在预演 GKE 集群上创建应用的着陆区。在生产 GKE 集群中创建着陆区:您需要创建一个从预演到生产分支的拉取请求并将其合并。
点击
Pull requests
,然后点击New pull request
按钮。在基本菜单中,选择生产,在比较菜单中,选择预演。点击Create pull request
按钮。如果您是代码库的管理员,请合并拉取请求。否则,请让管理员合并它。
Config Sync 将到达代码库
acm-gke-infrastructure-repo
的生产分支的更改同步到生产 GKE 集群,以使生产 GKE 集群上应用的着陆区创建。
将更改从开发升级到预演
现在,您已在预演集群和生产 GKE 集群中为应用创建了着陆区,接下来可以将应用从开发环境提升到预演环境。
查找最新版本名称并将其保存为环境变量:
export RELEASE=$(gcloud deploy targets describe dev --region=us-central1 --format="json" | jq -r '."Active Pipeline"[0]."projects/PROJECT_ID/locations/us-central1/deliveryPipelines/sample"."Latest release"' | awk -F '/' '{print $NF}')
将
PROJECT_ID
替换为您的 Google Cloud 项目 ID。验证是否已设置环境变量:
echo $RELEASE
在 Cloud Shell 中,运行以下命令以触发将版本从开发环境提升到预演环境的步骤:
gcloud deploy releases promote --release=$RELEASE --delivery-pipeline=sample --region=us-central1 --to-target=staging --quiet
检查预演部署:
点击
sample
流水线,已启动到预演 GKE 集群的部署。等待它完成。验证预演部署是否已成功执行:
获取预演集群的凭据:
gcloud container clusters get-credentials gke-staging-us-central1 --zone us-central1-a
通过隧道连接到 GKE 集群:
gcloud container clusters get-credentials gke-staging-us-central1 --zone us-central1-a && kubectl port-forward --namespace sample $(kubectl get pod --namespace sample --selector="deploy.cloud.google.com/delivery-pipeline-id=sample" --output jsonpath='{.items[0].metadata.name}') 8080:8080
在 Cloud Shell 工具栏上,点击
网页预览,然后点击在端口 8080 上预览:
输出如下所示:
My new feature!
在 Cloud Shell 中,按
CTRL+C
结束端口转发。
将更改从预演环境提升到生产环境
现在,将版本从预演环境提升到生产环境。您有两个生产集群,并且 Cloud Deploy 分别为每个集群创建一个名为 prod1 和 prod2 的目标。
在 Cloud Shell 中,运行以下命令以触发将版本从预演环境提升到 prod1 集群:
gcloud deploy releases promote --release=$RELEASE --delivery-pipeline=sample --region=us-central1 --to-target=prod1 --quiet
发布到生产集群需要批准,因此发布会等到您批准为止。如需查看它,请执行以下操作:
点击
sample
流水线。发布到 prod1 需要批准,并且需要 clouddeploy.Approver 角色才能批准发布。由于您是项目的所有者,因此有权批准版本。将版本批准到 prod1:
运行以下命令以获取待批准的发布名称,并将其保存到环境变量中:
export ROLLOUT=$(gcloud deploy targets describe prod1 --region=us-central1 --format="json" | jq -r '."Pending Approvals"[]' | awk -F '/' '{print $NF}')
批准版本:
gcloud deploy rollouts approve $ROLLOUT --delivery-pipeline=sample --region=us-central1 --release=$RELEASE --quiet
批准后,prod1 版本将启动。在 Cloud Deploy 流水线页面上监控进度。
prod1 部署完成后,启动 prod2 版本。
gcloud deploy releases promote --release=$RELEASE --delivery-pipeline=sample --region=us-central1 --to-target=prod2 --quiet
发布到 prod2 也需要批准。批准发布到 prod2 集群:
运行以下命令以获取待批准的发布名称,并将其保存到环境变量中:
export ROLLOUT=$(gcloud deploy targets describe prod2 --region=us-central1 --format="json" | jq -r '."Pending Approvals"[]' | awk -F '/' '{print $NF}')
批准版本:
gcloud deploy rollouts approve $ROLLOUT --delivery-pipeline=sample --region=us-central1 --release=$RELEASE --quiet
批准后,prod2 版本就会启动。在 Cloud Deploy 流水线页面上监控进度。
在 prod1 和 prod2 中的 Cloud Deploy 流水线完成后,验证生产集群中的部署是否成功。
生产集群中创建了多集群 Ingress,您可以使用负载均衡器访问生产应用。此多集群 Ingress 配置是使用代码库
sample
中的 YAML 文件 k8s/prod/mci.yaml 和 k8s/prod/mcs.yaml 创建的。当您将请求发送到负载均衡器的 IP 地址时,多集群 Ingress 会将请求转发到在两个不同 GKE 集群中运行的应用的两个实例之一。列出与负载均衡器关联的转发规则以查找 IP 地址。
gcloud compute forwarding-rules list
输出类似以下内容:
NAME: mci-qqxs9x-fw-sample-sample-ingress REGION: IP_ADDRESS: 34.36.123.118 IP_PROTOCOL: TCP TARGET: mci-qqxs9x-sample-sample-ingress
打开网络浏览器,然后在网址栏中输入以下内容:
http://IP_ADDRESS:80
将
IP_ADDRESS
替换为负载均衡器的 IP 地址。输出如下所示:
My new feature!
这会确认应用按预期在生产集群中进行部署。
测试应用的弹性
在本部分中,您将通过重启两个生产 GKE 集群的节点之一来测试在生产环境中运行的应用的弹性,而不会影响应用。
生产环境中的应用使用多集群 Ingress,并且可通过负载均衡器 IP 地址访问。当通过该 IP 访问应用时,多集群 Ingress 会将其路由到在两个不同的 GKE 集群上运行的应用的两个实例之一。当其中一个 GKE 集群运行状况不佳且无法访问在该集群中运行的应用实例时,多集群 Ingress 会继续将流量发送到在另一个 GKE 集群上运行的应用的运行状况良好的实例。这使最终用户看不到集群中断,并且应用会持续处理请求。
如需测试弹性,请执行以下操作:
找到在 us-west1 中运行的生产 GKE 集群的节点池。
gcloud container clusters describe gke-prod-us-west1 --zone=us-west1-a --format=json | jq ".nodePools[0].instanceGroupUrls[]" | tr '"' ' ' | awk -F '/' '{for(i=NF-2; i<=NF; i=i+2) printf ("%s ",$i); print ""}'
输出类似以下内容:
us-west1-b gke-gke-prod-us-west1-node-pool-01-6ad4e1ed-grp us-west1-c gke-gke-prod-us-west1-node-pool-01-98407373-grp
输出有两列,第一列是可用区,第二列是与 us-west1 区域中生产 GKE 集群的节点池关联的实例组的名称。
重启与节点池对应的实例组:
gcloud compute instance-groups managed rolling-action restart INSTANCE_GROUP_1 --zone=ZONE_1 --max-unavailable=100% gcloud compute instance-groups managed rolling-action restart INSTANCE_GROUP_2 --zone=ZONE_2 --max-unavailable=100%
将
INSTANCE_GROUP_1
替换为第一个实例组的名称。将
ZONE_1
替换为第一个实例组的可用区。将
INSTANCE_GROUP_2
替换为第二个实例组的名称。将
ZONE_2
替换为第二个实例组的可用区。检查实例组的状态。
两个实例组正在重新启动,而其他实例组对其显示绿色对勾标记。
打开网络浏览器,然后在网址栏中输入以下内容:
http://IP_ADDRESS:80
将
IP_ADDRESS
替换为负载均衡器的 IP 地址。即使两个 GKE 集群中的一个关闭,应用也可用,输出如下:
My new feature!
这表明您的应用具备弹性和高可用性。
管理应用
从应用工厂创建此应用时,您会获得该应用的单独 Git 代码库、基础架构和 CI/CD 流水线。您可以使用这些资源来部署应用并添加新功能。为了进一步管理应用,您只需与这些 Git 代码库和流水线进行交互,而无需更新应用工厂。您可以根据需要自定义应用的流水线和 git 代码库。作为应用所有者,您可以定义谁有权访问应用的流水线和 Git 代码库来管理该应用。
清理
为避免因本教程中使用的资源导致您的 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.
后续步骤
- 了解设置身份联合的最佳做法。
- 阅读 Kubernetes 和持续软件部署的挑战。
- 了解混合云和多云环境的监控和日志记录模式。
- 探索有关 Google Cloud 的参考架构、图表和最佳实践。查看我们的 Cloud 架构中心。