4、Terraform模块化设计SLI配置:创建可复用的SLI模块、输入变量与输出值设计、模块版本管理

在SLI配置管理中,直接编写扁平化的Terraform配置会导致大量重复代码、维护困难且难以统一口径。模块化设计是解决这些问题的核心手段。本章将深入讲解如何将SLI配置抽象为可复用的Terraform模块,涵盖模块结构设计、输入输出变量规范以及版本管理策略。

4.1 SLI模块化设计原则

SLI模块的核心目标是封装“指标口径定义”与“告警规则绑定”的逻辑,使其在不同服务、不同环境间可复用。设计时应遵循以下原则:

  • 单一职责:一个模块只负责一种SLI类型(如延迟、错误率、饱和度)的配置。
  • 参数化口径:将SLI的阈值、窗口大小、聚合方式等作为输入变量暴露。
  • 输出标准化:模块输出SLI的ID、URN或监控端点,供上层调用方消费。
  • 无状态:模块不依赖外部状态文件,所有依赖通过变量传递。
最佳实践:将SLI模块与基础设施模块(如Kubernetes、数据库)解耦。SLI模块只关心“如何计算指标”,不关心“指标来自哪个具体资源”。

4.2 创建可复用的SLI模块

一个标准的SLI模块目录结构如下:

modules/
└── sli-http-latency/
    ├── main.tf          # 核心资源定义
    ├── variables.tf     # 输入变量声明
    ├── outputs.tf       # 输出值定义
    ├── README.md        # 模块使用文档
    └── versions.tf      # Terraform与Provider版本约束

main.tf 示例:定义一个基于Prometheus的HTTP延迟SLI:

# modules/sli-http-latency/main.tf
resource "prometheus_rule_group" "sli" {
  name     = var.rule_group_name
  interval = var.evaluation_interval

  rule {
    record = "${var.sli_name}:latency:p99"
    expr   = <

4.3 输入变量与输出值设计

输入变量是模块的“接口”,必须清晰定义类型、描述与默认值。输出值则是模块的“契约”,供其他配置引用。

4.3.1 输入变量设计规范

变量名 类型 描述 是否必填 默认值示例
sli_name string SLI唯一标识名称 是 api-checkout
job_name string Prometheus job标签值 是 checkout-service
route_pattern string 匹配的路由正则 否 "/api/v1/checkout/.*"
threshold_seconds number P99延迟告警阈值 是 0.5
window string 指标聚合窗口 否 "5m"
severity string 告警严重级别 否 "critical"

variables.tf 声明示例:

# modules/sli-http-latency/variables.tf
variable "sli_name" {
  description = "Unique name for this SLI"
  type        = string
}

variable "job_name" {
  description = "Prometheus job label to filter metrics"
  type        = string
}

variable "threshold_seconds" {
  description = "P99 latency threshold in seconds"
  type        = number

  validation {
    condition     = var.threshold_seconds > 0 && var.threshold_seconds <= 10
    error_message = "Threshold must be between 0 and 10 seconds."
  }
}

variable "window" {
  description = "Evaluation window for rate calculation"
  type        = string
  default     = "5m"
}

variable "severity" {
  description = "Alert severity level"
  type        = string
  default     = "warning"

  validation {
    condition     = contains(["critical", "warning", "info"], var.severity)
    error_message = "Severity must be one of: critical, warning, info."
  }
}

4.3.2 输出值设计

输出值应包含模块创建的核心资源标识,便于上层模块或根配置进行关联:

# modules/sli-http-latency/outputs.tf
output "sli_rule_group_name" {
  description = "Name of the created Prometheus rule group"
  value       = prometheus_rule_group.sli.name
}

output "sli_alert_name" {
  description = "Name of the high latency alert rule"
  value       = "${var.sli_name}_HighLatency"
}

output "sli_metric_name" {
  description = "Recorded SLI metric name"
  value       = "${var.sli_name}:latency:p99"
}
设计要点:输出值尽量使用description字段说明用途,方便模块消费者通过terraform-docs自动生成文档。

4.4 模块版本管理

当SLI模块被多个团队或环境引用时,版本管理至关重要。Terraform Registry原生支持语义化版本控制(SemVer)。

4.4.1 版本约束策略

场景 版本约束写法 说明
锁定主版本 version = "~> 1.0" 允许1.x范围内的任何升级,禁止2.0
精确锁定 version = "= 1.2.0" 仅使用该精确版本,用于生产环境
允许补丁升级 version = "~> 1.2.0" 允许1.2.1、1.2.2,但不允许1.3.0
最低版本要求 version = ">= 1.2.0, < 2.0.0" 确保功能可用,同时避免大版本破坏

4.4.2 模块发布与版本标记

在Git仓库中管理模块代码,通过Git Tag进行版本标记:

# 标记版本 v1.2.0
git tag v1.2.0
git push origin v1.2.0

# 标记预发布版本
git tag v1.3.0-rc.1
git push origin v1.3.0-rc.1

在根配置中引用模块时,通过source参数指定版本:

# environments/production/main.tf
module "checkout_sli" {
  source = "git::https://gitlab.example.com/sre/sli-modules.git//sli-http-latency?ref=v1.2.0"

  sli_name          = "checkout-api"
  job_name          = "checkout-service"
  threshold_seconds = 0.5
  severity          = "critical"
}
注意:使用Git源时,ref参数必须指向具体的Tag或Commit SHA,避免使用main或master分支,否则会导致不可控的配置漂移。

4.5 SLI模块调用关系图

下图展示了根配置如何通过模块化设计,将不同SLI口径组合到同一服务监控中:

SLI模块化调用关系 SLI模块化调用关系 根配置 (main.tf) sli-http-latency P99延迟模块 sli-http-error-rate 错误率模块 sli-saturation 饱和度模块 输出: latency_metric 输出: error_rate_alert 输出: saturation_metric 版本管理:每个模块独立标记 SemVer Tag 根配置通过 source 参数指定 ref=v1.2.0 锁定版本

4.6 模块版本生命周期管理

在实际团队协作中,SLI模块的版本演进应遵循清晰的流程:

  1. 开发阶段:在feature分支上修改模块代码,使用ref=feature-branch进行测试。
  2. 预发布:合并到main分支后,打v1.2.0-rc.1标签,集成到预发布环境验证。
  3. 正式发布:验证通过后,打v1.2.0标签,更新生产环境配置。
  4. 废弃与迁移:当模块需要重大变更时,发布v2.0.0,并在旧版本README中标注废弃说明。
CI/CD集成提示:在CI流水线中,可以自动检测模块目录的变更,当modules/sli-*/有提交时,自动执行terraform validate并推送新版本Tag。这将在第7章详细展开。

4.7 本章小结

通过模块化设计,SLI配置从“硬编码的脚本”转变为“可组合的乐高积木”。关键收获包括:

  • 使用variables.tf定义清晰的口径参数,使用outputs.tf暴露标准化接口。
  • 通过Git Tag和语义化版本控制,确保不同环境使用一致的模块版本。
  • 模块的单一职责原则让每个SLI类型独立演进,降低变更风险。