跳转至

Ch 23 业务仓库设计与同构模式

项目第 1 年 · 核心建设期——业务仓同构


本章你将学到

  • 业务 IaC 仓的同构目录:代码在 regional/,参数在 environments/,CI 只调用平台 workflow
  • 同构如何换来 CI 复用、模板开仓与合规可归属;特例如何标注
  • 始祖仓治理债、冻结机制与按域拆分;monorepo vs polyrepo 在医药合规下的取舍

23.1 业务 IaC 仓的同构目录结构设计

Ch 22 把地基放进 core-infra。业务域要的是可复制的铺面图纸,别让每个域自己发明一种目录方言。

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#edf5ff','primaryTextColor':'#161616','primaryBorderColor':'#0f62fe','lineColor':'#697077','secondaryColor':'#d9fbfb','tertiaryColor':'#f2f4f8','fontSize':'14px'}}}%%
flowchart TB
 subgraph 同构结构["所有业务仓的统一目录结构"]
 TF[terraform/]
 TF --> ETL[regional/etl/<br/>Glue Job 资源]
 TF --> ORCH[regional/orchestration/<br/>Step Functions 资源]
 TF --> DDB[regional/dynamodb/<br/>DynamoDB 配置表]
 TF --> ENV[environments/<br/>dev / qa / prod]
 ENV --> ENV_TF["env-all.tfvars"]
 ENV --> ENV_BE["env.tfbackend"]
 CI[.github/workflows/<br/>CI 文件(所有仓相同)]
 end
classDef bpProcess fill:#edf5ff,stroke:#0f62fe,stroke-width:2px,color:#161616
class CI,DDB,ENV,ENV_BE,ENV_TF,ETL,ORCH,TF bpProcess
linkStyle default stroke:#697077,stroke-width:2px

图 23-1 业务 IaC 仓的同构目录结构设计

目录 内容 同构性
terraform/regional/etl/ Glue / Lambda / S3 事件等 ETL 资源 结构相同,内容按域不同
terraform/regional/orchestration/ Step Functions + state_files/ 模板 结构相同
terraform/regional/dynamodb/ 域内配置表(若有) 结构相同
terraform/environments/{dev,qa,prod}/ {env}-all + 按服务 *-all.tfvars + .tfbackend 结构相同
.github/workflows/ci.yml uses: 调用平台 reusable workflow 完全相同(差在输入参数)

表 23-1 业务 IaC 仓的同构目录结构设计

# 示意:aurora-domain-ma 同构骨架
terraform/
├── main.tf / providers.tf
├── aurora-generic-modules/          # submodule
├── regional/
│   ├── etl/          # glue.tf lambda.tf s3_event.tf
│   ├── orchestration/# stepfunctions.tf + process_state_files/
│   └── dynamodb/
└── environments/{dev,qa,prod}/
    ├── {env}.tfbackend
    ├── {env}-all.tfvars
    ├── glue-all.tfvars | lambda-all.tfvars | step-functions-all.tfvars
    └── state_files/*.state.json     # ASL 模板,见 Ch 26

这个结构不是我一开始就定好的。前三个月 domain-a 用 glue/+sf/,domain-b 用 etl/+orchestration/,排障先要翻译目录方言。我停下开发花一天统一成图 23-1。同构是痛出来的(M4)。

开新域的标准动作:复制模板仓,改 domain 名与 repo_type=develop,在三套 environments/ 填 tfvars,且不加 iam-all(IAM 仍归 foundation)。加一个 Glue Job 也固定:在 regional/etl 声明模块调用,三环境 glue-all.tfvars 补条目,PR 触发 CI。下一节解释为什么我宁可牺牲一点灵活性,也要钉死这张图纸。


23.2 为什么刻意保持结构同构

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#edf5ff','primaryTextColor':'#161616','primaryBorderColor':'#0f62fe','lineColor':'#697077','secondaryColor':'#d9fbfb','tertiaryColor':'#f2f4f8','fontSize':'14px'}}}%%
flowchart LR
 subgraph 同构的价值["结构同构的四大价值"]
 V1[ CI 复用<br/>一份 workflow 服务所有仓]
 V2[ 模板复制<br/>新业务仓从模板秒级创建]
 V3[ 人员轮岗<br/>熟悉一个仓即可操作所有仓]
 V4[ 工具通用<br/>脚本/工具跨仓复用]
 end
classDef bpProcess fill:#edf5ff,stroke:#0f62fe,stroke-width:2px,color:#161616
class V1,V2,V3,V4 bpProcess
linkStyle default stroke:#697077,stroke-width:2px

图 23-2 为什么刻意保持结构同构

价值 说明
CI 复用 所有仓调用同一 reusable workflow;路径过滤假设目录约定存在
模板复制 新建域 = 复制模板 + 改名,不重写流水线
人员轮岗 工程师换域不换心智模型
工具通用 变更检测、排障脚本跨仓同一套

表 23-2 为什么刻意保持结构同构

同构和 Ch 27 绑在一起:workflow 里写死 environments/${env}/glue-all.tfvars 这类路径,是因为所有仓都遵守表 23-1。异构一天,平台 CI 就要长出 if domain == … 的特例树。

Trade-off

同构的代价是不够灵活,个别域的特殊拓扑可能别扭。策略是同构为主、特例标注:特例必须在 README 写明差异,并尽量用模块输入表达,别另起目录。仓从 3 个涨到 6 个时,改一处安全扫描、六仓同时生效,复利才看得见(M4 / M11)。


23.3 始祖仓的遗产:新旧标准混合的治理债与拆分决策

始祖仓的演化

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#edf5ff','primaryTextColor':'#161616','primaryBorderColor':'#0f62fe','lineColor':'#697077','secondaryColor':'#d9fbfb','tertiaryColor':'#f2f4f8','fontSize':'14px'}}}%%
flowchart LR
 subgraph 演化历程["仓库演化历程"]
 T1@{ icon: "logos:aws-step-functions", form: "rounded", label: 初期:单一始祖仓<br/>所有业务线混在一起<br/>100+ Step Functions, pos: "b", h: 40 }
 T2[中期:标准演进<br/>新框架/新标准出现<br/>始祖仓混入新旧代码]
 T3[后期:拆分<br/>新业务线独立建仓<br/>始祖仓只承载历史任务]
 end

 T1 --> T2 --> T3
classDef bpProcess fill:#edf5ff,stroke:#0f62fe,stroke-width:2px,color:#161616
class T1,T2,T3 bpProcess
linkStyle default stroke:#697077,stroke-width:2px

图 23-3 始祖仓的演化

治理债的形成

问题 原因 影响
新旧标准混合 始祖仓承载了 v1 和 v2 两代框架 新人不知道该遵循哪套
旧代码不再维护 大量旧 connector/state machine 仍在跑 不敢改、不敢删
仓库过大 100+ 资源定义在一个仓 CI 慢、PR review 困难

表 23-3 治理债的形成

拆分决策

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#edf5ff','primaryTextColor':'#161616','primaryBorderColor':'#0f62fe','lineColor':'#697077','secondaryColor':'#d9fbfb','tertiaryColor':'#f2f4f8','fontSize':'14px'}}}%%
flowchart TB
 ANCESTOR[始祖仓<br/>100+ SF / 混合新旧标准] --> SPLIT[拆分决策]
 SPLIT --> NEW1[business-domain-a<br/>新标准]
 SPLIT --> NEW2[business-domain-b<br/>新标准]
 SPLIT --> NEW3[business-domain-c<br/>新标准]
 SPLIT --> KEEP[始祖仓<br/>冻结新增,仅维护历史任务]
classDef bpProcess fill:#edf5ff,stroke:#0f62fe,stroke-width:2px,color:#161616
class ANCESTOR,KEEP,NEW1,NEW2,NEW3,SPLIT bpProcess
linkStyle default stroke:#697077,stroke-width:2px

图 23-4 拆分决策

拆分时我定了三条冻结运营规则,否则"始祖仓"会继续膨胀:

  1. CODEOWNERS:新增 regional/** 资源仅允许平台架构组例外合并。
  2. CI 策略:validation_type=freeze。plan 若出现 create 计数 > 0 则失败,只允许 in-place update / destroy 迁移。
  3. 文档:README 置顶"禁止新接入;新需求去同构域仓"。

引申

拆分是对的,但遗留两套标准的双轨成本真实存在(M5)。更好的预防是第一天就按域拆仓,哪怕每域只有两三个任务。同构帮我复用流水线,也拦住了再长出一个始祖垃圾场。


23.4 引申:monorepo vs polyrepo 的 IaC 治理对比

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#edf5ff','primaryTextColor':'#161616','primaryBorderColor':'#0f62fe','lineColor':'#697077','secondaryColor':'#d9fbfb','tertiaryColor':'#f2f4f8','fontSize':'14px'}}}%%
flowchart TB
 subgraph 两种模式["两种 IaC 仓库模式"]
 MONO[Monorepo<br/>所有 IaC 在一个仓<br/>目录划分业务域]
 POLY[Polyrepo<br/>每个业务域独立仓<br/>本书方案]
 end
classDef bpProcess fill:#edf5ff,stroke:#0f62fe,stroke-width:2px,color:#161616
class MONO,POLY bpProcess
linkStyle default stroke:#697077,stroke-width:2px

图 23-5 引申:monorepo vs polyrepo 的 IaC 治理对比

维度 Monorepo Polyrepo(本书)
CI 一次 CI 覆盖所有(慢但全面) 每仓独立 CI(快,靠同构复用)
权限 粗粒度或复杂 CODEOWNERS 按仓授权,变更可归属
变更协调 跨域一个 PR 跨域 N 个 PR(例:改平台 Role + 六域引用)
发布节奏 易被绑成统一节奏 各域独立;与 Glue/Lambda 发布流解耦
适合规模 小团队、强耦合 多域、合规要求强

表 23-4 引申:monorepo vs polyrepo 的 IaC 治理对比

Trade-off

我选 polyrepo,决定性因素是权限隔离与变更可归属(M10),其次才是 IaC 与运行时代码发布节奏不同。代价是一次改 foundation 输出名,可能要开 1+6 个 PR。我们用契约双写窗口加域仓批量升级脚本对冲,不退回 monorepo。

下一章进入同构仓共同依赖的积木 generic-modules:中国区子集、SemVer,以及我拆过的胖模块教训。


本章小结

  • 同构目录:regional/{etl,orchestration,dynamodb} + environments/* + 极简 CI 调用
  • 同构服务平台工程:一份 workflow、一套变更检测、模板开仓(M4 / M7)
  • 始祖仓用冻结规则止血,新域走同构;polyrepo 用仓边界换合规可归属

下一章

Ch 24 通用 Terraform 模块设计 —— 接下来看通用模块库如何设计,让业务仓能"搭积木"式组装资源。

评论