综合项目进阶:入口、调度、私网与恢复

验证:未记录
适用版本
未记录
验证范围
尚未登记验证记录。

前置:订单处理项目已验收。本篇接入新增服务;每节完成后记录证据,可分次执行,不要求所有计费资源长期同时保留。

1. 最终结构#

自有域名 → Cloud DNS → HTTPS LB + Certificate Manager
                         ├→ Cloud Armor → IAM 私有的订单 API
                         └→ Cloud CDN → 独立公开静态桶

Cloud Tasks → 订单 API → orders-created topic → 原 Worker
Cloud Scheduler ──────→ orders-created topic → 原 Worker
Eventarc ← 独立 Pub/Sub topic ───────────────→ 原 Worker
                                               ↓
                         Direct VPC → 私网 Cloud SQL + Storage 归档
                                               ↓
                     查询投影 → Firestore / Redis;审计导出 → KMS 加密

Scheduler 与 Eventarc 的 topic 都使用合成测试订单;不会把一次真实订单同时从多条路径重复发布。SQL 是订单权威数据,Firestore/Redis 是独立练习的查询投影。

2. DNS、证书、CDN 与 WAF#

  1. 按 Cloud DNS创建并委派实验子域,按项目篇把 API 接到 HTTPS LB。
  2. 按 Certificate Manager将证书 map 绑定到该 LB;主机名与公开 DNS 保持一致。
  3. 按 Cloud Armor将策略绑定到 API 的 backend service;保持 API 的 IAM 认证和 ingress 限制。
  4. 按 CDN创建 lab-cdn-backend,桶只放公开静态内容,不放订单数据。

将 CDN 后端加到现有 lab-map,API 路由保持原默认 backend:

export STATIC_DOMAIN='替换为static.自有实验域'
gcloud dns record-sets create "$STATIC_DOMAIN." --zone=lab-public --type=A --ttl=300 --rrdatas="$LB_IP"
gcloud compute url-maps add-path-matcher lab-map --path-matcher-name=static --global --new-hosts="$STATIC_DOMAIN" --default-backend-bucket=lab-cdn-backend

STATIC_DOMAIN 需要自己的有效证书:按证书篇重复 DNS authorization 与 certificate 创建,使用不同资源名(例如 lab-static-auth、lab-static-cert),再在原 map 添加主机名条目:

gcloud certificate-manager maps entries create lab-static-entry --map=lab-cert-map --hostname="$STATIC_DOMAIN" --certificates=lab-static-cert
curl --fail "https://$STATIC_DOMAIN/asset.txt"

迁到共享入口后,不要照抄独立 CDN 实验的整套清理命令。 先验证新入口,仅回收旧 HTTP proxy、forwarding rule、IP 和 URL map;保留仍被引用的 Backend bucket。

验收:静态域无需登录且能命中缓存;API 域仍要求 ID token;带 WAF 测试 header 的 API 请求被拒绝。后台 worker 继续私有,不加 allUsers。

3. Cloud Tasks 提交订单#

先完成 Tasks 实验,保留队列 lab-http 和 SA lab-tasks。本节在项目第 8 节收紧 API ingress 之前执行;若已经收紧,通过上面的 HTTPS LB 域名调用,token audience 仍使用 API 默认服务 URL。

export TASK_SA="lab-tasks@$PROJECT_ID.iam.gserviceaccount.com"
export API_URL=$(gcloud run services describe orders-api --region="$REGION" --format='value(status.url)')
export API_ENTRY="$API_URL"  # 已限制 ingress 时,改为 https://你的API域名
export ORDER_ID=$(python3 -c 'import uuid; print(uuid.uuid4())')
gcloud run services add-iam-policy-binding orders-api --region="$REGION" --member="serviceAccount:$TASK_SA" --role=roles/run.invoker
printf '{"id":"%s","amount":880}\n' "$ORDER_ID" > task-order.json
gcloud tasks create-http-task "orders-$(date +%s)" --queue=lab-http --location="$REGION" --url="$API_ENTRY/orders" --method=POST --header=Content-Type:application/json --body-file=task-order.json --oidc-service-account-email="$TASK_SA" --oidc-token-audience="$API_URL"

验收:任务成功、API 返回 202、worker 完成、出现对应归档。任务完成仅代表 API 接受消息,不代表订单事务已完成;最终状态要查订单 ID。

4. Cloud Scheduler 发合成巡检事件#

创建一条固定 ID 的测试订单,每次调度重投同一个事件,以验证消息链路和幂等;它不会每分钟创建真实新订单。

export PROBE_ID=$(python3 -c 'import uuid; print(uuid.uuid4())')
export PROBE_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ)
gcloud services enable cloudscheduler.googleapis.com
gcloud scheduler jobs create pubsub orders-probe --location="$REGION" --schedule='*/5 * * * *' --time-zone=UTC --topic=orders-created --message-body="{\"id\":\"$PROBE_ID\",\"amount\":1,\"created_at\":\"$PROBE_TIME\"}"
gcloud scheduler jobs run orders-probe --location="$REGION"

Scheduler 的 service agent 通过其系统角色发布同项目 topic;保留 service agent 默认角色。此 Pub/Sub target 不使用 HTTP 实验中的 OIDC 调用 SA。

验收:多次手动执行后 SQL 只有一行、归档只有一个对象,worker 有多次 completed 日志。按 Monitoring查询处理错误和消息积压;若要检测“完全没有巡检结果”,还需单独的缺失数据告警,不能依赖错误计数。

5. 事件路由、数据库权限与私网#

  • 按 Eventarc把独立测试 topic 路由到原 Worker,验证原应用能处理该 CloudEvent;无需重复创建业务数据库。
  • 先按 SQL 权限收敛切换到只允许 SELECT/INSERT 的运行用户,建表交给迁移身份。
  • 按 私网连接将原 Worker 改为 Direct VPC + PostgreSQL TLS,验收后关闭 SQL 公共 IP。
  • 再分别提交一条 API、Tasks、Eventarc 测试订单,证明入口变化未破坏下游处理。

6. Firestore / Redis 查询投影#

先完成 Firestore和 Memorystore,保留 lab-docs、lab-redis、lab-vm。这是手动刷新查询投影的实验,不宣称实现了实时数据库同步。

终端 A 通过 IAP/SSH 建本机端口转发到 Redis 私有 IP,保持运行:

export REDIS_HOST=$(gcloud redis instances describe lab-redis --region="$REGION" --format='value(host)')
gcloud compute ssh lab-vm --zone="$ZONE" --tunnel-through-iap -- -N -L "127.0.0.1:6380:$REDIS_HOST:6379" -o ExitOnForwardFailure=yes

终端 B 创建独立虚拟环境,安装 google-cloud-storage google-cloud-firestore redis,执行 gcloud auth application-default login;该本地操作者需订单桶 Object Viewer、Firestore 数据写权限,以及进入 VM 的权限。

source lab.env
export ORDERS_BUCKET="${PROJECT_ID}-orders"
export ORDER_ID='替换为已完成的订单UUID'

保存 project_order.py 并运行两次:

import json
import os
import redis
from google.cloud import firestore, storage

project = os.environ['PROJECT_ID']
order_id = os.environ['ORDER_ID']
cache = redis.Redis(host='127.0.0.1', port=6380, decode_responses=True,
                    socket_connect_timeout=2, socket_timeout=2)
key = f'order:{order_id}'
try:
    cached = cache.get(key)
except redis.RedisError:
    cached = None
if cached:
    print('cache_hit', json.loads(cached))
else:
    obj = storage.Client(project=project).bucket(os.environ['ORDERS_BUCKET']).blob(f'orders/{order_id}.json')
    record = json.loads(obj.download_as_text())
    db = firestore.Client(project=project, database='lab-docs')
    db.collection('order_views').document(order_id).set(record)
    try:
        cache.set(key, json.dumps(record), ex=60)
    except redis.RedisError:
        pass  # 缓存故障不阻止返回可靠源中的结果
    print('source_read', record)

验收:首次 source_read,第二次 cache_hit;Firestore 有同 ID 投影。停止隧道后再次执行,仍可从 Storage 读取,说明缓存不是唯一数据源。TTL 过期可重新加载;实时更新、删除和访问隔离需要后续设计。

7. KMS 加密审计导出#

完成 KMS 实验且尚未清理 key/SA;仅导出一条合成订单,不更改 Worker 的 JSON 归档格式,避免影响 BigQuery。

gcloud storage cp "gs://$ORDERS_BUCKET/orders/$ORDER_ID.json" audit-order.json
gcloud kms encrypt --key=lab-key --keyring=lab-ring --location="$REGION" --plaintext-file=audit-order.json --ciphertext-file=audit-order.enc --impersonate-service-account="lab-kms@$PROJECT_ID.iam.gserviceaccount.com"
gcloud storage cp audit-order.enc "gs://$ORDERS_BUCKET/audit/$ORDER_ID.enc"

验证有密钥权限能解密,没有对应权限时失败;它是客户端加密实验,不等于订单桶已启用 CMEK。清理密钥前先处理需要保留的密文。

8. 函数与员工后台入口#

完成 Cloud Run functions的源码部署,再用 Scheduler 的 OIDC HTTP 调用它,作为独立轻量巡检函数;订单事务仍走原服务。完成 IAP为独立后台演示服务开启员工登录,并验证撤权。不要给处理 Pub/Sub 的 Worker 套用员工登录流程。

9. 治理、恢复与收尾#

完成 资源治理盘点成本与公开授权;用 PITR在独立 SQL 实例验证恢复,按订单 ID 对账 SQL/对象/投影。

清理顺序:暂停 Scheduler → 停止任务入队 → 删除 Eventarc trigger → 清理静态域路由/证书 → 删除边缘资源 → 停止本地隧道 → 删除缓存与投影 → 清理业务资源(含新增 orders-runtime-password Secret)→ SQL 释放后清理 PSA/VPC。

gcloud scheduler jobs delete orders-probe --location="$REGION"
gcloud run services remove-iam-policy-binding orders-api --region="$REGION" --member="serviceAccount:$TASK_SA" --role=roles/run.invoker
rm task-order.json audit-order.json audit-order.enc

其他资源按各篇清理段操作。静态域需要先删除其 DNS A/CNAME、certificate map entry 和专用证书/authorization;在删除证书 map 前清完所有 entry。最终再执行主项目清理。

生产场景参考工程#

继续 企业项目:包含业务源码、私网区域 HA SQL、身份分离和验收脚本;完整云端集成与恢复结果仍需实际演练。本篇保留逐服务实验定位。

搜索文档

输入关键词,搜索所有文档。

↑ ↓ 选择 · Enter 打开 · Esc 关闭