SiyaR-SSH/gcp-ha-web-tier
GitHub: SiyaR-SSH/gcp-ha-web-tier
该项目演示了如何在 GCP 上通过 gcloud CLI 构建跨多可用区的高可用 Web 层,实现负载均衡与自动故障恢复。
Stars: 0 | Forks: 0
# Google Cloud 上的高可用、负载均衡 Web 层
## 目标
将 Web 层从单点故障转变为具有弹性的服务。与其使用单个 VM,不如运行一个分布在多个可用区的、由相同服务器组成的**托管实例组** (managed instance group),在其前端放置一个**负载均衡器** (load balancer),并添加一个**健康检查** (health check),以便自动替换不健康的实例。
完成后的环境包含:
- 一个定义了可复现 Web 服务器的**实例模板** (instance template) (通过启动脚本运行 nginx)
- 一个运行在跨多个可用区的 2 个以上实例的**区域托管实例组 (MIG)**
- 一个通过端口 80 监控每个实例的**健康检查**
- 一个在健康实例之间分配流量的**全球 HTTP 负载均衡器**
- **自我修复**:销毁一个实例,MIG 会自动重建它
- 用于管理访问的 **基于 IAP 的 SSH** —— 无需在任何地方硬编码家庭 IP
## 架构
```
Internet
|
+-----------v------------+
| Global HTTP Load | single public IP
| Balancer | (forwarding rule → proxy → URL map)
+-----------+------------+
|
+-----------v------------+
| Backend Service | + Health Check (HTTP :80)
+-----------+------------+
|
+---------------+---------------+
| | |
+----v----+ +----v----+ +----v----+
| web-vm | | web-vm | | web-vm | Regional MIG
| zone-a | | zone-b | | zone-c | (spread across zones)
+---------+ +---------+ +---------+
\_______________|_______________/
|
VPC: secure-vpc / public-subnet (10.0.1.0/24)
```
**高可用理念:** 任何单个实例——甚至单个可用区——的宕机都不会导致网站下线。负载均衡器仅将流量发送到健康检查报告为健康的实例,并且 MIG 通过重建任何死掉的实例来保持组的规模达到目标大小。
## 关键概念(构建前值得了解)
- **实例模板** (Instance template) —— VM 的不可变蓝图。MIG 从中复制出相同的实例。修改配置 = 新建模板,而不是编辑运行中的 VM。
- **托管实例组 (MIG)** (Managed Instance Group) —— 根据模板维护目标数量的实例。*区域* (Regional) MIG 将实例分布在多个可用区,比*可用区* (zonal) MIG 具有更高的可用性。
- **健康检查** (Health check) —— 定期探测每个实例。不健康的实例将被移出轮询,并且(通过自动修复)被重新创建。
- **负载均衡器组件** —— GCP 的负载均衡器由多个部分组装而成:*转发规则* (forwarding rule) (公网 IP) → *目标代理* (target proxy) → *URL 映射* (URL map) (路由规则) → *后端服务* (backend service) (哪个组服务流量,以及健康检查)。手动构建它们可以让你了解各个部分是如何组合在一起的。
## 负载均衡器的实际工作原理(组件链)
这个实验教会我的最重要的一点是:在 GCP 中,负载均衡器**不是一个单一对象** —— 它是一条由你组装的、执行单一任务的小型资源链。请求沿着这条链传递:
```
Visitor → Forwarding rule → Target proxy → URL map → Backend service → Instance group → VM
```
| 组件 | 它的唯一职责 | 通俗易懂的作用解释 |
|---|---|---|
| **转发规则** (Forwarding rule) | 持有公网 IP + 端口 | 前门——唯一的公共入口 |
| **目标 HTTP 代理** (Target HTTP proxy) | 在特定协议下终止连接 | 负责应答的前台(HTTP 还是 HTTPS;在 HTTPS 下,SSL 证书附加在这里) |
| **URL 映射** (URL map) | 根据主机/路径将请求路由到后端 | 交换机目录(`/api` → 一个后端,`/images` → 另一个) |
| **后端服务** (Backend service) | 持有策略 + 健康检查 | 管理者:哪个池服务流量,以及谁处于健康状态 |
| **后端** (Backend) | 附加到该服务的一个池 | 管理者名册上的一个团队(指向一个*组*,而不是单个 VM) |
| **实例组 (MIG)** | 跨可用区运行相同的 VM | 实际提供页面服务的工人 |
| **健康检查** (Health check) | 通过 :80 探测每个实例 | 主管的点名——死掉的实例会被移出轮询 |
**为什么它是自下而上构建的:** 你不能将某个东西连接到一个尚不存在的资源上,因此构建顺序是 workers → health check → backend service → URL map → proxy → forwarding rule。转发规则(公共门)是在机器内部的整个部分准备好*之后*创建的。
**“后端服务”与“一个后端”——命名陷阱:** *后端服务*是管理者(规则 + 健康检查)。*一个后端*是一个附加到其上的池——我的实例组 `web-mig`。后端指向一整个**组**,而不是单个 VM;这种间接性正是消除单点故障的关键。
**每个组件都是必不可少的粘合剂,而不是装饰品:** 转发规则不能直接指向 URL map——它只能指向*目标代理* (target proxy),而目标代理又是唯一可以引用 URL map 的对象。移除任何中间链接,链条就无法组装(在构建时)或会中断服务(如果在运行时被删除),即使 VM 保持完全健康也是如此。
## 构建方式(`gcloud` CLI)
在这里,CLI 实际上比控制台*更容易*——负载均衡器有许多组件,逐个点击屏幕比执行这些命令要慢。请在 Cloud Shell 中运行。
### 0. 网络基础(如果已销毁,请重建 Phase 1 的网络)
```
gcloud compute networks create secure-vpc --subnet-mode=custom
gcloud compute networks subnets create public-subnet \
--network=secure-vpc --region=us-central1 --range=10.0.1.0/24
```
### 1. 防火墙规则
```
# 允许健康检查和 load-balancer 流量访问 Web 层。
# 这两个范围是 Google 的健康检查 / LB 源范围 —— 并非任意指定。
gcloud compute firewall-rules create allow-health-check \
--network=secure-vpc --direction=INGRESS --action=ALLOW \
--rules=tcp:80 \
--source-ranges=130.211.0.0/22,35.191.0.0/16 \
--target-tags=web-server
# 仅通过 IAP 进行 Admin SSH —— 基于身份,任何地方都不使用家庭 IP。
gcloud compute firewall-rules create allow-ssh-iap \
--network=secure-vpc --direction=INGRESS --action=ALLOW \
--rules=tcp:22 --source-ranges=35.235.240.0/20 --target-tags=web-server
```
### 2. 实例模板
```
gcloud compute instance-templates create web-template \
--machine-type=e2-micro \
--network=secure-vpc --subnet=public-subnet --region=us-central1 \
--tags=web-server \
--image-family=debian-12 --image-project=debian-cloud \
--metadata=startup-script='#! /bin/bash
apt update && apt install -y nginx
echo " --zone= -q
# 一分钟后重新列出 —— MIG 已经将其重建,恢复至大小 2
```
## ⚠️ 费用警告——离开前请务必阅读
与 Phase 1 不同,**负载均衡器不是免费的**。无论是否有人访问,全球转发规则每小时大约都会扣费,并且它不包含在永久免费层级中。你的 $300 额度可以轻松承担一个实验的费用,**但你必须在完成后将其销毁**——转发规则运行一个月是要花真金白银的。如有需要,请设置日历提醒。
## 清理(按相反的依赖顺序删除)
```
gcloud compute forwarding-rules delete web-forwarding-rule --global -q
gcloud compute target-http-proxies delete web-proxy -q
gcloud compute url-maps delete web-map -q
gcloud compute backend-services delete web-backend --global -q
gcloud compute health-checks delete web-health-check -q
gcloud compute instance-groups managed delete web-mig --region=us-central1 -q
gcloud compute instance-templates delete web-template -q
gcloud compute firewall-rules delete allow-health-check allow-ssh-iap -q
gcloud compute networks subnets delete public-subnet --region=us-central1 -q
gcloud compute networks delete secure-vpc -q
```
一天后,确认 **Billing → Reports** 费用图表降为零。
## 展现的技能
高可用性设计 · 负载均衡(后端服务、URL 映射、目标代理、转发规则) · 托管实例组与实例模板 · 健康检查与自我修复 · 多可用区弹性 · 自动扩缩容 · 基于身份的访问 (IAP) · 通过 CLI (`gcloud`) 管理基础设施
## 我学到了什么
核心教训是 GCP 负载均衡器是一个*由独立资源组成的链条*,而不是一个单一对象——只有当你通过它追踪一个请求(转发规则 → 代理 → URL 映射 → 后端服务 → 实例组)时,这些组件才有意义。将“后端服务”(管理者)与“一个后端”(附加的组)区分开来是豁然开朗的时刻。我还了解到,这些组件必须自下而上构建,因为每个组件都引用了它下方的资源。
在运维方面,有两点让我印象深刻:销毁顺序很重要——我在删除 VPC 时遇到了一个错误,因为之前 NAT 设置中遗留的 Cloud Router 仍然连接在上面,这教会了我当子资源引用父资源时,GCP 会阻止删除该父资源。此外,我还学会了将长 `gcloud` 命令作为单行干净的命令行运行,而不是依赖反斜杠行继续符,因为之前行中间多余的 `\ ` 一直在破坏我的参数。
*(在发布之前,请用你自己的语言重新表述这些内容——你的措辞比我的更好。)*
## 🔒 发布前——敏感信息遮挡检查清单
这是我从 Phase 1 中学到的:将每张屏幕截图都视为攻击面。在任何图片进入这个公开仓库之前,请涂黑(使用实心框,不要模糊处理):
- IP 地址(如果你愿意,包括负载均衡器的公网 IP)
- 项目 ID 和账号号码
- 电子邮件地址
## 本系列的下一步
- **Phase 3** — 安全加固(IAM 最小权限、Cloud Armor WAF、Secret Manager)
- **Phase 4** — 使用 Terraform 将所有内容重建为基础设施即代码
- **Phase 5** — 监控、日志记录与警报
- **Phase 6** — 毕业项目:完整的、安全的、高可用的云应用程序
*实验完成时间:2026-07-26 · 云服务提供商:Google Cloud Platform*
Served by: $(hostname)
" > /var/www/html/index.html' ``` *`$(hostname)` 技巧意味着每个实例都会显示自己的名字——因此,当你刷新负载均衡器时,你可以切实看到流量命中了不同的后端。* ### 3. 区域托管实例组(多可用区) ``` gcloud compute instance-groups managed create web-mig \ --template=web-template --size=2 --region=us-central1 # 告诉实例组哪个端口提供 HTTP 服务(LB 需要这个命名端口) gcloud compute instance-groups managed set-named-ports web-mig \ --named-ports=http:80 --region=us-central1 ``` ### 4. 健康检查 ``` gcloud compute health-checks create http web-health-check \ --port=80 --request-path=/ ``` ### 5. 组装负载均衡器 ``` # Backend service,已连接到健康检查 gcloud compute backend-services create web-backend \ --protocol=HTTP --port-name=http \ --health-checks=web-health-check --global # 将该 instance group 作为 backend 附加 gcloud compute backend-services add-backend web-backend \ --instance-group=web-mig --instance-group-region=us-central1 --global # URL map → target proxy → forwarding rule(公共入口点) gcloud compute url-maps create web-map --default-service=web-backend gcloud compute target-http-proxies create web-proxy --url-map=web-map gcloud compute forwarding-rules create web-forwarding-rule \ --global --target-http-proxy=web-proxy --ports=80 ``` ### 6. 获取负载均衡器的公网 IP ``` gcloud compute forwarding-rules describe web-forwarding-rule \ --global --format="get(IPAddress)" ``` 将该 IP 粘贴到浏览器中。*给它几分钟时间*——一个新的 LB 在开始提供服务之前可能需要 3-5 分钟。刷新几次,观察后端之间的主机名变化。 ### 7. (可选)自动扩缩容 ``` gcloud compute instance-groups managed set-autoscaling web-mig \ --region=us-central1 --min-num-replicas=2 --max-num-replicas=4 \ --target-cpu-utilization=0.6 --cool-down-period=60 ``` ## 验证与乐趣——证明高可用性 | 测试 | 预期结果 | |---|---| | 反复刷新 LB IP | 主机名发生改变 → 流量正在实例之间进行负载均衡 ✅ | | 控制台 → 检查后端健康状况 | 实例报告为 **健康** (Healthy) ✅ | | 手动删除一个实例 | MIG 检测到它并**自动重建**(自我修复) ✅ | | 检查实例的可用区 | 它们分布在 `us-central1-a/b/c` → 具备可用区弹性 ✅ | **尝试自我修复演示** —— 这是这个实验中最好的面试故事: ``` # 列出该组的实例,然后故意删除其中一个 gcloud compute instance-groups managed list-instances web-mig --region=us-central1 gcloud compute instances delete标签:Google Cloud, Nginx, 云计算, 架构设计, 自动化运维, 规则引擎, 负载均衡