模块仓库架构设计:仓库目录结构设计原则、版本控制策略、模块命名规范
模块仓库是服务目录的物理载体,其架构设计直接决定了模块的可发现性、可维护性和团队协作效率。一个设计良好的仓库应当让开发者无需查阅文档就能快速定位所需模块,并理解其版本关系和依赖约束。本节从目录结构、版本控制和命名规范三个维度展开。
2.1 仓库目录结构设计原则
目录结构是模块仓库的骨架,遵循以下四项核心原则可确保仓库随模块数量增长而保持清晰:
- 扁平优先:模块嵌套不超过三级,避免深层路径导致引用路径过长。
- 按功能域聚合:将同一业务域或基础设施层的模块放在同一父目录下。
- 显式版本目录:每个模块版本使用独立目录,支持并行维护多个主版本。
- 元数据与模块分离:仓库根目录存放全局配置、CI/CD 脚本和文档,不混入模块代码。
推荐标准布局:以下是一个同时支持 Terraform Registry 和 Git 标签双模式发布的仓库结构。
terraform-modules/
├── modules/ # 模块源码目录
│ ├── networking/
│ │ ├── vpc/
│ │ │ ├── v1.0.0/
│ │ │ │ ├── main.tf
│ │ │ │ ├── variables.tf
│ │ │ │ ├── outputs.tf
│ │ │ │ └── README.md
│ │ │ └── v2.0.0/
│ │ │ ├── main.tf
│ │ │ ├── variables.tf
│ │ │ ├── outputs.tf
│ │ │ └── README.md
│ │ └── subnet/
│ │ └── v1.0.0/
│ ├── compute/
│ │ ├── ec2-instance/
│ │ └── auto-scaling-group/
│ └── security/
│ ├── iam-role/
│ └── security-group/
├── examples/ # 使用示例(每个模块至少一个)
│ ├── networking/
│ │ └── vpc-example/
│ └── compute/
│ └── ec2-example/
├── tests/ # 自动化测试(Terratest / OPA)
├── docs/ # 全局文档、贡献指南、变更日志
├── .github/ # CI/CD 工作流、PR 模板
├── Makefile # 统一构建与测试入口
├── .terraform-docs.yml # 文档生成配置
└── README.md # 仓库总览
下表对比了三种常见目录策略的适用场景:
| 策略 | 结构示例 | 适用场景 | 注意事项 |
|---|---|---|---|
| 单层扁平 | modules/vpc/ |
模块数量 < 30,团队规模小 | 模块名需全局唯一,无域隔离 |
| 功能域分组 | modules/networking/vpc/ |
模块数量 30–100,多团队协作 | 域目录名使用复数名词 |
| 服务/产品分组 | modules/product-a/vpc/ |
大型组织,产品线独立发布 | 跨产品复用需额外治理 |
实践建议:从功能域分组起步,当单个域内模块超过 20 个时再考虑拆分子域或独立仓库。避免过早引入多仓库带来的引用和发布复杂度。
2.2 版本控制策略
模块版本控制需要同时解决两个问题:模块自身的版本演进和消费者如何锁定版本。推荐采用 SemVer 2.0 + Git 标签 的组合策略。
2.2.1 语义化版本(SemVer)
每个模块版本号格式为 MAJOR.MINOR.PATCH,变更规则如下:
- MAJOR:不兼容的 API 变更(如移除必填变量、修改输出名称)。
- MINOR:向下兼容的新功能(如新增可选变量、增加输出)。
- PATCH:向下兼容的缺陷修复或文档更新。
常见陷阱:Terraform 模块的“API”由
variables.tf 和 outputs.tf 共同定义。修改变量默认值属于 PATCH,但修改变量类型或移除变量必须升级 MAJOR 版本。
2.2.2 Git 标签与目录版本双模式
为同时支持 Terraform Registry 和直接 Git 引用,采用双模式版本管理:
| 模式 | 标签格式 | 目录结构 | 引用方式示例 |
|---|---|---|---|
| Registry 模式 | modules/networking/vpc/v1.0.0 |
modules/networking/vpc/v1.0.0/ |
source = "hashicorp/aws//modules/networking/vpc" |
| Git 标签模式 | vpc-v1.0.0 |
modules/networking/vpc/(最新) |
source = "git::https://...//modules/networking/vpc?ref=vpc-v1.0.0" |
两种模式同步维护:每次发布新版本时,同时创建 Git 标签和版本目录。版本目录保留历史版本,允许消费者在无法访问 Git 历史时仍能锁定特定版本。
2.2.3 版本约束最佳实践
消费者在 terraform.tf 中使用 version 参数锁定模块版本:
# 推荐:宽松锁定 MINOR 版本,自动获取 PATCH 修复
module "vpc" {
source = "git::https://github.com/org/terraform-modules.git//modules/networking/vpc"
version = "~> 1.2.0"
}
# 严格锁定:仅用于生产环境关键模块
module "database" {
source = "git::https://github.com/org/terraform-modules.git//modules/database/rds"
version = "= 2.0.1"
}
版本约束速查表:
~> 1.2.0→ 允许 1.2.x,禁止 1.3.0~> 1.2→ 允许 1.x,禁止 2.0>= 1.2, < 2.0→ 允许 1.2 到 1.x 最新= 1.2.3→ 仅允许精确版本
2.3 模块命名规范
统一的命名规范降低认知负荷,使模块名称自描述。规范覆盖模块名、变量名、输出名和文件名四个层面。
2.3.1 模块命名规则
| 元素 | 规则 | 正确示例 | 错误示例 |
|---|---|---|---|
| 模块目录名 | 小写字母 + 连字符,描述资源用途 | vpc, ec2-instance, iam-role |
VPC, ec2_instance, my_module |
| 模块 source 引用 | 与目录名一致,不额外加前缀 | //modules/networking/vpc |
//modules/networking/aws-vpc-module |
| 变量名 | snake_case,名词或名词短语 | instance_type, subnet_ids |
instanceType, subnetIDs |
| 输出名 | snake_case,动词+名词 | vpc_id, public_subnet_ids |
vpcID, publicSubnets |
| 文件名 | 全小写,按职责命名 | main.tf, variables.tf, outputs.tf |
VPC.tf, variables.tf.bak |
2.3.2 变量与输出命名约定
- 必填变量:不加默认值,名称以资源核心属性开头,如
vpc_cidr、instance_type。 - 可选变量:提供合理默认值,名称以
enable_、use_、custom_前缀标识开关或自定义行为,如enable_nat_gateway。 - 标签变量:统一命名为
tags,类型为map(string),由调用方传入全局标签。 - 输出命名:使用
资源_属性格式,如vpc_id、subnet_arns。避免缩写歧义,如sg_id应写为security_group_id。
2.3.3 模块内文件组织规范
# 每个模块版本目录下至少包含以下文件:
v1.0.0/
├── main.tf # 核心资源定义
├── variables.tf # 所有输入变量声明
├── outputs.tf # 所有输出值声明
├── versions.tf # Terraform 与 Provider 版本约束
├── README.md # 模块文档(由 terraform-docs 自动生成)
└── locals.tf # (可选)本地变量与数据源
命名检查清单:在 CI 中集成
tflint 和自定义命名规则检查,确保 PR 合入前所有模块名、变量名、输出名符合规范。推荐使用 terraform-compliance 或 conftest 进行策略即代码验证。
2.4 架构设计决策矩阵
以下矩阵帮助团队根据自身规模和组织结构快速选择仓库架构方案:
| 决策维度 | 单体仓库(Monorepo) | 多仓库(Polyrepo) | 混合模式 |
|---|---|---|---|
| 模块数量 | < 50 | > 100 | 50–100 |
| 团队规模 | 1–3 个团队 | 5+ 独立团队 | 3–5 个团队 |
| 跨模块重构频率 | 高 | 低 | 中 |
| CI/CD 复杂度 | 低(单管道) | 高(多管道协调) | 中(按域拆分管道) |
| 版本一致性 | 容易保证 | 需额外工具协调 | 域内一致,域间松散 |
| 推荐场景 | 初创团队、平台工程初期 | 大型企业、产品线完全独立 | 中型组织、有明确域边界 |
起步建议:无论最终选择哪种模式,初期都从单体仓库 + 功能域分组开始。当单个仓库的 CI 构建时间超过 10 分钟或模块数超过 80 个时,再评估是否拆分。迁移成本远低于一开始就设计过度复杂的多仓库架构。