4. 模块化设计:Terraform Module 的创建、输入输出变量、模块注册中心与版本管理

在跨云资源池编排场景中,直接编写扁平化的 .tf 文件会导致代码膨胀、复用性差、维护成本激增。Terraform Module 是解决这一问题的核心抽象单元,它将一组相关的资源封装为可复用的“乐高积木”。本章将深入 Module 的创建规范、变量契约、注册中心发布流程以及语义化版本控制策略。

4.1 Module 的标准结构与创建规范

Terraform Module 本质上是一个包含 .tf 或 .tf.json 文件的目录。一个生产级 Module 必须遵循以下文件结构约定:

文件/目录 必需性 作用说明
main.tf 推荐 主资源定义逻辑,包含核心资源(如 AWS VPC、Azure AKS、GCP GKE)的声明。
variables.tf 推荐 声明所有输入变量(Input Variables),定义类型、描述与默认值。
outputs.tf 推荐 声明所有输出值(Output Values),供根模块或其他子模块消费。
versions.tf 推荐 声明 Terraform 版本约束与 Provider 版本约束。
README.md 强烈建议 模块用途、前置条件、使用示例与变更日志。
examples/ 建议 包含可直接运行的完整示例目录,用于验证模块功能。
最佳实践: 始终在 versions.tf 中锁定 Terraform 最低版本(如 required_version = ">= 1.5"),避免因 CLI 版本差异导致状态文件不兼容。

4.2 输入输出变量:定义契约接口

变量是 Module 与外部交互的唯一通道。设计良好的变量接口应遵循“最小暴露原则”与“强类型约束”。

4.2.1 输入变量(Input Variables)

在 variables.tf 中,每个变量应包含 type、description 和可选的 default 与 validation 块。

# variables.tf
variable "cluster_name" {
  description = "Kubernetes 集群名称,全局唯一"
  type        = string
}

variable "node_pool_config" {
  description = "节点池配置映射"
  type = object({
    machine_type = string
    min_count    = number
    max_count    = number
    disk_size_gb = optional(number, 100)
  })
  default = {
    machine_type = "e2-medium"
    min_count    = 1
    max_count    = 3
  }
}

variable "tags" {
  description = "资源标签集合"
  type        = map(string)
  default     = {}
}

4.2.2 输出变量(Output Values)

输出变量用于向调用方暴露关键属性,如集群端点、资源组 ID 等。敏感信息应标记为 sensitive = true。

# outputs.tf
output "cluster_endpoint" {
  description = "API Server 端点地址"
  value       = google_container_cluster.primary.endpoint
}

output "cluster_ca_certificate" {
  description = "集群 CA 证书(Base64 编码)"
  value       = google_container_cluster.primary.master_auth[0].cluster_ca_certificate
  sensitive   = true
}
避坑指南: 避免在输出中暴露 IAM 密钥或 Service Account 令牌。若必须输出,务必设置 sensitive = true,并在 CI/CD 流水线中配置日志脱敏规则。

4.3 模块注册中心与版本管理

企业级跨云资源池需要集中式的模块注册中心来管理模块的发现、发布与版本演进。Terraform 官方提供 Terraform Registry,而私有化场景通常使用 Git 标签 + 文件系统路径 或 私有 Registry(如 Terraform Cloud、HashiCorp Vault 集成方案)。

4.3.1 版本约束语法

在根模块中引用子模块时,必须通过版本约束锁定模块版本,防止意外升级导致资源漂移。

约束符号 示例 含义
= version = "1.2.0" 精确匹配版本 1.2.0
>= version = ">= 1.2.0" 允许 1.2.0 及以上任何版本
~> version = "~> 1.2" 允许 1.2.x 范围内的最新版本,禁止 1.3.0
!= version = "!= 1.2.5" 排除特定版本

4.3.2 私有 Registry 发布流程

对于使用 Git 仓库作为模块源的团队,推荐采用“语义化版本标签 + 目录路径”的引用方式:

# 根模块引用示例
module "gke_cluster" {
  source = "git::https://gitlab.internal.com/infra-modules/gke-cluster.git?ref=v1.3.1"

  cluster_name    = "prod-app-cluster"
  node_pool_config = {
    machine_type = "n1-standard-4"
    min_count    = 3
    max_count    = 10
  }
  tags = {
    Environment = "production"
    Team        = "platform"
  }
}
版本管理策略:
  • MAJOR:不兼容的 API 变更(如重命名输入变量、删除输出值)。
  • MINOR:向后兼容的功能新增(如增加可选变量、新增输出属性)。
  • PATCH:向后兼容的缺陷修复(如修正 Provider 版本下限、修复资源参数错误)。
每次发布前必须运行 terraform validate 和 terraform fmt -check,确保模块语法正确且格式统一。

4.4 模块化架构全景图

下图展示了从模块创建、注册到跨云消费的完整生命周期,重点突出输入/输出变量在模块间及模块与根配置之间的数据流。

Terraform Module 生命周期与变量数据流 模块创建 main.tf / variables.tf outputs.tf / versions.tf README.md / examples/ 模块注册中心 Terraform Registry Git Tags (v1.0.0) 私有 Registry 版本管理 MAJOR.MINOR.PATCH ~> 约束 / >= 约束 CHANGELOG.md 发布 打标签 根模块(Root Module)消费 输入变量赋值 cluster_name / node_pool_config 模块实例化 module "gke_cluster" { ... } 输出值消费 module.gke_cluster.cluster_endpoint source + version 引用 跨云资源池输出 AWS EKS 集群 | Azure AKS 集群 | GCP GKE 集群 统一标签体系 | 标准化输出接口

4.5 模块化设计检查清单

在将 Module 发布到注册中心前,请逐项核对以下清单,确保模块质量满足跨云资源池的复用要求:

  • 变量完整性:所有输入变量均包含 type、description,敏感变量标记 sensitive。
  • 输出最小化:只暴露调用方真正需要的属性,避免输出内部临时资源 ID。
  • 版本锁定:versions.tf 中指定 Terraform 与 Provider 的版本下限。
  • 示例可运行:examples/ 目录下的示例可通过 terraform init && terraform plan 验证。
  • 语义化标签:Git 标签严格遵循 vMAJOR.MINOR.PATCH 格式,并附带 CHANGELOG。
  • 跨云兼容:若模块支持多云,需在 README 中明确标注支持的 Provider 版本与 Region 限制。
推荐工具: 使用 terraform-docs 自动从 variables.tf 和 outputs.tf 生成 README 文档,确保文档与代码始终同步。在 CI/CD 流水线中集成 pre-commit 钩子,自动检查 terraform validate 和 tflint。