news 2026/10/15 3:47:27

用 Terraform 一键部署 Wild Workouts 到 Google Cloud:从环境准备到一键上线的完整实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用 Terraform 一键部署 Wild Workouts 到 Google Cloud:从环境准备到一键上线的完整实战指南
  • 示例工程
  • 后端
  • 前端
  • 微服务

【免费下载链接】wild-workouts-go-ddd-example

Go DDD example application. Complete project to show how to apply DDD, Clean Architecture, and CQRS by practical refactoring.

项目地址:https://gitcode.com/gh_mirrors/wi/wild-workouts-go-ddd-example
点击查看免费下载

本文以仓库 terraform/README.md 为骨架,结合 terraform/ 目录下的全部 Terraform 配置与根目录 Makefile、cloudbuild.yaml、scripts/deploy.sh 等源码,系统讲解 Wild Workouts Go DDD 示例项目如何在 Google Cloud 上完成从零到一的生产级部署。读完本文,你将掌握:gcloud 认证与.env参数配置、make一键部署背后的完整执行链路、Cloud Run + Firebase + Firestore + Cloud Build 的 Terraform 资源编排原理,以及部署完成后的认证启用、构建观测与一键销毁等全部操作。

一、部署前必须准备的三样软件

根据 terraform/README.md,部署本项目需要三样本地软件:

软件作用
Terraform声明式编排 GCP 上的所有云资源(项目、IAM、Cloud Run、Firebase、Cloud Build 等)
gcloud CLI向 gcloud 授权认证、读取当前账号与账单账户信息、执行 Cloud Run / Firestore 相关命令
Docker(守护进程运行中)将占位镜像拉取、打标签并推送到 Container Registry,为 Cloud Run 服务预置镜像

该文档明确给出了当时验证通过的版本组合:

Terraform v0.12.24 Google Cloud SDK 290.0.1 alpha 2019.05.17 beta 2019.05.17 core 2020.04.24

需要说明的是,这套版本是原文档记录的历史验证基线。项目当前使用golang:1.25基础镜像(见 docker/app/Dockerfile)与GO111MODULE=on的构建选项(见 cloudbuild.yaml),实际部署时请以你当前环境中的 Terraform / gcloud 新版本为准,并留意google、google-betaprovider 的兼容性。

二、Setup:三步完成全量部署

2.1 第一步:在 gcloud CLI 中完成双重授权

项目追求"尽可能简单的安装体验",但文档明确指出:默认应用登录(Default application login)不建议用于生产环境。你需要执行两条命令:

gcloud auth login gcloud auth application-default login
  • gcloud auth login:登录用户账号,用于gcloud命令行操作(后续set-envs.sh会读取当前 ACTIVE 账号作为默认部署用户)。
  • gcloud auth application-default login:生成 Application Default Credentials,供 Terraform 的 google provider 在本地读取并使用。

2.2 第二步:运行 make,按提示确认并填写参数

make

make运行时 Terraform 会要求你确认应用变更,请输入yes。从根目录 Makefile 对应的 terraform/Makefile 可以看到,all目标实际串起了五个阶段:

all: check init apply push_repo done
阶段执行内容
check校验terraform、gcloud命令是否已安装(未安装直接报错退出)
init运行./set-envs.sh交互式采集环境变量并写入.env,随后执行terraform init
apply加载.env后执行terraform apply,创建全部云资源
push_repo配置 gcloud 作为 git 凭据助手,把master分支推送到新建的 Cloud Source Repositories,触发 Cloud Build
done打印后续手动步骤:启用 Firebase Email/Password、可选降级计费套餐、给出 Web 站点地址与构建观测链接
交互式参数采集脚本set-envs.sh的工作原理

init阶段调用的 terraform/set-envs.sh 是整个部署体验的核心:

  • 读取当前 gcloud ACTIVE 账号作为TF_VAR_user默认值(未设置时);
  • 读取第一个open=true的账单账户作为TF_VAR_billing_account;
  • TF_VAR_region默认europe-west1,TF_VAR_firebase_location默认europe-west;
  • 依据 terraform/.env.example 逐项向用户询问并生成.env文件。

.env.example中定义的五个TF_VAR_变量,恰好对应 terraform/vars.tf 中 Terraform 声明的变量:

export TF_VAR_project=wild-workouts-project export TF_VAR_user=user@company.com export TF_VAR_billing_account=My billing account export TF_VAR_region=europe-west1 export TF_VAR_firebase_location=europe-west
变量含义默认值 / 来源
TF_VAR_project新建 GCP 项目 ID(Project ID)无默认,必填
TF_VAR_user被授予项目 owner 角色的用户邮箱自动取当前 gcloud ACTIVE 账号
TF_VAR_billing_account账单账户的 display name自动取第一个 open 的账单账户
TF_VAR_regionCloud Run 部署区域europe-west1
TF_VAR_firebase_locationFirebase 项目位置europe-west

此外 terraform/vars.tf 中还有一个非交互变量repository_name,默认值wild-workouts,用于命名 Cloud Source Repositories 仓库。

区域选择的重要提醒

文档明确提示:如果你想把 Cloud Run 部署到europe-west1以外的区域,必须同步修改(并提交)以下两个文件:

  • ./scripts/deploy.sh
  • ./web/firebase.json

原因在于这两处把区域硬编码了:

  1. scripts/deploy.sh 中的gcloud run deploy固定使用--region europe-west1:
gcloud run deploy "$service-$server_to_run" \ --image "gcr.io/$project_id/$service" \ --region europe-west1 \ --platform managed

该脚本被 cloudbuild.yaml 中的六个部署步骤调用(trainer-http、trainer-grpc、trainings-http、users-http、users-grpc)。

  1. web/firebase.json 的 hosting rewrites 中,三个 API 路由"/api/trainer{,/**}"、"/api/trainings{,/**}"、"/api/users{,/**}"指向的 Cloud Run 服务都写死了"region": "europe-west1":
{ "source": "/api/trainer{,/**}", "run": { "serviceId": "trainer-http", "region": "europe-west1" } }

这一配置实现了 Firebase Hosting 对 Cloud Run 服务的反向代理:前端静态资源由 Hosting 托管,/api/*请求被转发到对应服务。

三、make 背后的 Terraform 资源全景(源码级剖析)

terraform apply一次创建了整条部署链路。理解这些资源,你就理解了整个项目的云上架构。

3.1 项目、账单与 IAM(project.tf、iam.tf)

terraform/project.tf 完成地基建设:

  • 通过google_billing_account按 display name 查找账单账户;
  • 创建名为 "Wild Workouts"、ID 为var.project的google_project;
  • 为var.user授予roles/owner;
  • 依次启用 7 个 API:Compute Engine、Container Registry、Cloud Run、Cloud Build、Firebase、Firestore、Source Repo。

terraform/iam.tf 则为 Cloud Build 服务账号授权,使其能执行后续的 Firebase 部署与 Cloud Run 管理:

  • roles/firebase.admin、roles/serviceusage.apiKeysViewer、roles/run.admin;
  • 对默认 Compute 服务账号授予roles/iam.serviceAccountUser。

3.2 Docker 镜像占位与推送(docker-images.tf)

resource "null_resource" "init_docker_images" { provisioner "local-exec" { command = "make docker_images" } depends_on = [google_project_service.container_registry] }

对应 terraform/Makefile 的docker_images目标:先docker pull gcr.io/cloudrun/hello,再对trainer、trainings、users三个服务分别打标签为gcr.io/$TF_VAR_project/<service>并docker push。这样 Cloud Run 服务在创建时就能引用到真实存在的镜像(后续真正的应用镜像会由 Cloud Build 构建后覆盖)。

3.3 Cloud Run 服务编排(cloud-run.tf + service/ 子模块)

terraform/cloud-run.tf 通过复用 terraform/service/ 子模块,创建了5 个 Cloud Run 服务:

模块实例服务名协议认证关键环境变量
cloud_run_trainer_grpctrainer-grpcgrpc默认开启—
cloud_run_trainer_httptrainer-httphttp关闭(auth=false)TRAINER_GRPC_ADDR指向 trainer-grpc 端点
cloud_run_trainings_httptrainings-httphttp关闭TRAINER_GRPC_ADDR、USERS_GRPC_ADDR
cloud_run_users_grpcusers-grpcgrpc默认开启—
cloud_run_users_httpusers-httphttp关闭USERS_GRPC_ADDR指向 users-grpc 端点

这种"一个服务拆成 HTTP 入口 + gRPC 内部端点"的布局,与项目的架构设计直接对应:trainer 与 users 的内部 gRPC 服务不直接对外暴露,而 HTTP 服务通过环境变量注入内部端点,实现服务间的 gRPC 调用。

terraform/service/service.tf 展示了子模块的核心逻辑:

  • 每个服务默认注入GCP_PROJECT与SERVER_TO_RUN(取值为var.protocol)两个环境变量,SERVER_TO_RUN正是各服务启动时选择启动 HTTP 还是 gRPC 服务器的开关;
  • 通过dynamic "env"把调用方传入的自定义envs与默认变量合并注入容器;
  • 设置autoscaling.knative.dev/maxScale = 3限制最大实例数;
  • 使用autogenerate_revision_name = true自动生成修订版本名;
  • auth为 false 时,通过google_cloud_run_service_iam_policy把roles/run.invoker授予allUsers(公开可调用);默认(auth=true)则保持内部调用,gRPC 端点不对外开放。

terraform/service/outputs.tf 输出url与endpoint,其中endpoint将 URL 的https://前缀去掉并追加:443,即${url去掉https://}:443,作为 gRPC 目标地址注入到 HTTP 服务中。

根级 terraform/outputs.tf 汇总输出trainer_grpc_url、trainer_http_url、trainings_http_url、users_grpc_url、users_http_url与repo_url(Source Repo 地址,供push_repo阶段解析使用)。

3.4 Firebase 与 Firestore(firebase.tf、firestore.tf)

terraform/firebase.tf 使用google-betaprovider:

  • 创建名为firebase的服务账号并授予roles/editor,生成密钥给 provider 使用;
  • 创建 Firebase 项目(google_firebase_project)并设置位置var.firebase_location(默认europe-west);
  • 创建 Firebase Web AppWild Workouts,前端部署时会写入对应的配置。

terraform/firestore.tf 则:

  • 通过null_resource调用make firestore(内部执行gcloud alpha firestore databases create --region=$TF_VAR_firebase_location)启用 Firestore 数据库;
  • 创建复合索引trainings_user_time,按UserUuid(升序)、Canceled(升序)、Time(升序)加__name__排序——这正是 trainings 服务按用户查询训练列表(trainings_for_user)时 Firestore 所需的索引。

3.5 Cloud Source Repo 与 Cloud Build 触发器(repo.tf)

terraform/repo.tf 创建:

  • google_sourcerepo_repository.wild_workouts(名称取repository_name,默认wild-workouts);
  • google_cloudbuild_trigger:监听master分支,构建文件为根目录的 cloudbuild.yaml;
  • null_resource.firebase_builder:克隆 GoogleCloudPlatform/cloud-builders-community 并提交 Firebase builder 镜像到项目 Container Registry,供流水线最后一步的gcr.io/$PROJECT_ID/firebase使用。

四、make 之后:Cloud Build 流水线自动完成剩余工作

push_repo阶段把master分支推送到 Source Repo 后,Cloud Build 触发器随即启动 cloudbuild.yaml 定义的流水线:

  1. lint:对common、trainer、trainings、users四个 Go 模块执行 lint;
  2. 构建镜像:调用 scripts/build-docker.sh,用 docker/app-prod/Dockerfile 分别构建并推送gcr.io/$PROJECT_ID/trainer、trainings、users(覆盖先前推送的占位镜像);
  3. 测试:以docker/compose:1.19.0拉起 docker-compose.yml 与 docker-compose.ci.yml,依次运行四个模块的单测与common模块的 e2e 测试(见 internal/common/tests/e2e_test.go),全部通过后down清理;
  4. 部署:调用 scripts/deploy.sh 部署 6 个 Cloud Run 服务(trainer-http/grpc、trainings-http、users-http/grpc),所有部署步骤waitFor: [e2e-tests];
  5. 前端:在web目录执行yarn install、生成 OpenAPI 客户端、yarn build,最后用gcr.io/$PROJECT_ID/firebase执行firebase deploy --project=$PROJECT_ID,把静态资源与 hosting rewrites 发布到 Firebase Hosting。

构建选项统一设置GO111MODULE=on,并使用N1_HIGHCPU_8机型加速构建。

查看最近构建记录:打开 Google Cloud 控制台 → Cloud Build → Builds,即文档给出的 https://console.cloud.google.com/cloud-build/builds 。make done阶段也会打印该链接(带?project=$TF_VAR_project参数)。

五、第三步:在 Firebase 控制台启用 Email/Password 认证

部署完成后,Web 应用登录功能依赖 Firebase Authentication。按 terraform/README.md 的步骤操作(make done也会给出直达链接):

  1. 打开 Firebase 控制台:https://console.firebase.google.com
  2. 选择Wild Workouts项目
  3. 进入Authentication
  4. 选择Sign-in method标签页
  5. 点击Email/Password,切换到Enabled并点击Save

同时done阶段还提示两件可选事项:

  • 计费套餐默认设为 Blaze,可按需降级为Spark(完全免费,且具备运行本项目所需的所有功能);
  • 部署完成后 Web 站点应可通过https://$TF_VAR_project.web.app访问;若无法访问,请检查 Cloud Build 是否构建成功。

六、Destroy:彻底拆除云资源

如需拆除整个部署环境,运行:

make destroy

terraform/Makefile 的destroy目标执行了完整的清理流程:

destroy: terraform state rm "google_project_iam_member.owner" terraform state rm "google_project_service.container_registry" terraform state rm "google_project_service.cloud_run" ${load_envs} && terraform destroy git remote rm google

其中先terraform state rm移除三个资源再执行terraform destroy,是为了避免销毁时因资源依赖顺序(项目 owner、Container Registry、Cloud Run)导致的拆除失败,最后移除名为google的 git remote。

若之后想重新部署,文档明确提醒两点:

  • 换一个项目名(TF_VAR_project,因为原项目销毁后 Google 对项目 ID 有回收期限制);
  • 删除本地terraform.tfstate文件(旧状态文件与新项目不匹配,避免 apply 报错)。

七、总结:一条命令背后的完整交付链路

把整个部署串起来看,make只花了你一次交互,背后却完成了从 GCP 项目创建、IAM 授权、API 启用、Firebase/Firestore 初始化,到 Cloud Run 五服务编排、Cloud Source Repo 推送、Cloud Build 全自动构建测试部署、Firebase Hosting 上线的端到端闭环。这种"本地 Terraform 编排 + 云端流水线持续交付"的组合,正是 Wild Workouts 作为 DDD / Clean Architecture 示例项目在工程化落地层面的完整示范:

  • 想验证部署结果,看 terraform/outputs.tf 输出的各服务 URL 与 Cloud Build 构建历史;
  • 想调整部署拓扑,改 terraform/cloud-run.tf 与 terraform/service/service.tf;
  • 想定制 CI/CD 流程,改 cloudbuild.yaml;
  • 想换区域,务必同步修改 scripts/deploy.sh 与 web/firebase.json 两处硬编码的europe-west1。
  • 示例工程
  • 后端
  • 前端
  • 微服务

【免费下载链接】wild-workouts-go-ddd-example

Go DDD example application. Complete project to show how to apply DDD, Clean Architecture, and CQRS by practical refactoring.

项目地址:https://gitcode.com/gh_mirrors/wi/wild-workouts-go-ddd-example
点击查看免费下载

相关推荐

上一篇:brpc 负载均衡与命名服务全解析:从 NamingService 到健康检查的完整实践指南
下一篇:PyO3 示例仓库全解析:从装饰器到插件系统的一线实战模板

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 3:47:12

如何做到 Godot 场景切换不卡顿:Godot 场景管理实战指南

如何做到 Godot 场景切换不卡顿&#xff1a;Godot 场景管理实战指南 【免费下载链接】godot-docs Godot Engine official documentation 项目地址: https://gitcode.com/GitHub_Trending/go/godot-docs 点"开始游戏"卡住 1 秒、每过一关内存往上爬、切回主界面…

作者头像 李华
网站建设 2026/10/15 3:46:24

一文读懂ResNet:残差块、网络搭建与训练优化

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/15 3:44:06

为什么外贸企业需要AIGEO优化?AI搜索时代下海外获客的新机会

为什么外贸企业需要AIGEO优化&#xff1f;AI搜索时代下海外获客的新机会核心摘要海外采购者的搜索行为正在发生根本性变化&#xff1a;越来越多人通过ChatGPT、Perplexity、Copilot等AI工具获取供应商信息&#xff0c;而非仅仅依赖传统搜索结果页。AIGEO&#xff08;AI生成引擎…

作者头像 李华
网站建设 2026/10/15 3:44:05

庆祝冬余数据联合广东省商业地产租赁协会举办“AI 赋能商业企业创新实践案例”活动取得圆满成功!

庆祝冬余数据联合广东省商业地产租赁协会举办“AI 赋能商业企业创新实践案例”活动取得圆满成功&#xff01;近日&#xff0c;由冬余数据携手广东省商业地产租赁协会及数智经济专委会共同主办的“AI赋能商业企业创新实践案例”主题活动&#xff0c;在各方与会嘉宾的热烈交流中圆…

作者头像 李华
网站建设 2026/10/15 3:43:36

C/C++避坑指南:内存管理、指针与多线程实战经验

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华