You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Terraform自动创建AWS CloudWatch Windows EC2低磁盘空间告警

解决Windows EC2磁盘空间告警的Terraform配置问题

核心问题拆解

AWS EC2的API不会返回Windows实例的磁盘盘符(这是操作系统层面的配置),所以Terraform没法直接通过aws_instance数据块拿到盘符。另外,直接把所有实例和所有盘符嵌套遍历,会生成一堆对应实例不存在的盘符的无效告警,得先把实例和它实际有的盘符关联起来。

可行方案及代码修改

方案1:手动维护实例-盘符映射(适合实例不多的情况)

直接在本地定义每个实例对应的有效盘符,避免生成无效告警:

variable "windows_instances" {
  type = set(string)
  default = ["dc01", "dc02", "profile", "home"]
}

# 新增:给每个实例配实际存在的盘符
locals {
  instance_drives = {
    "dc01"    = ["C:", "D:"]
    "dc02"    = ["C:", "E:"]
    "profile" = ["C:"]
    "home"    = ["C:", "D:", "E:"]
  }
  # 生成「实例名-盘符」的唯一组合,用来遍历创建告警
  instance_drive_pairs = merge([
    for instance_name, drives in local.instance_drives : {
      for drive in drives : "${instance_name}-${drive}" => {
        instance_name = instance_name
        drive_letter  = drive
      }
    }
  ]...)
}

data "aws_instances" "all_windows_instances" {
  for_each = var.windows_instances
  instance_tags = {
    Name = "server-${each.key}-${tenant}"
  }
}

# 调整:通过实例名关联实例详情,不用实例ID绕一圈
data "aws_instance" "instance_details" {
  for_each = var.windows_instances
  instance_id = data.aws_instances.all_windows_instances[each.key].ids[0]
}

resource "aws_cloudwatch_metric_alarm" "windows_disk_alarm" {
  # 只遍历有效的实例-盘符组合
  for_each = local.instance_drive_pairs

  instance_name = each.value.instance_name
  drive_letter  = each.value.drive_letter
  instance_data = data.aws_instance.instance_details[instance_name]

  alarm_name          = "LowDiskSpace-${instance_data.tags["Name"]}-${drive_letter}"
  comparison_operator = "LessThanOrEqualToThreshold"
  threshold           = "20"
  evaluation_periods  = "1"
  statistic           = "Average"
  period              = "600"
  metric_name         = "LogicalDisk % Free Space"
  namespace           = "CWAgent"

  alarm_description = <<-EOT
    _______________________________________________
    # ${instance_data.tags["Name"]} (${drive_letter})
    磁盘空间不足,请及时排查!
    _______________________________________________
  EOT

  alarm_actions = [data.aws_sns_topic.sns_topic_arn.arn]

  dimensions = {
    InstanceId     = instance_data.id
    InstanceType   = instance_data.instance_type
    Instance       = drive_letter
    ImageId        = instance_data.ami
    objectname     = "LogicalDisk"
  }
}

方案2:通过实例标签传递盘符(适合动态创建实例的场景)

如果是用Terraform创建这些Windows实例,可以在创建实例时加个记录盘符的标签(比如Drives: C:,D:),然后在数据块里解析这个标签拿到盘符:

# 示例:创建实例时添加盘符标签
resource "aws_instance" "windows" {
  for_each = var.windows_instances
  # ...其他EC2配置(AMI、实例类型、子网等)
  tags = {
    Name   = "server-${each.key}-${tenant}"
    Drives = "C:,D:" # 根据实例实际磁盘配置填写
  }
}

# 读取实例详情并解析标签
data "aws_instance" "instance_details" {
  for_each = var.windows_instances
  instance_id = data.aws_instances.all_windows_instances[each.key].ids[0]
}

locals {
  # 从实例标签里解析出盘符列表
  instance_drives = {
    for instance_name, instance in data.aws_instance.instance_details : instance_name => split(",", instance.tags["Drives"])
  }
  # 生成有效的实例-盘符组合
  instance_drive_pairs = merge([
    for instance_name, drives in local.instance_drives : {
      for drive in drives : "${instance_name}-${drive}" => {
        instance_name = instance_name
        drive_letter  = drive
      }
    }
  ]...)
}

# 告警资源的配置和方案1完全一致

重点说明

  • 不要盲目遍历所有实例+所有盘符:通过instance_drive_pairs只生成有效的组合,确保每个告警对应实例真实存在的盘符,避免无效告警。
  • 实例维度信息直接拿:aws_instance数据块可以直接获取InstanceId、InstanceType、ImageId(也就是AMI ID),这些都是EC2 API返回的,不用从CloudWatch指标里读。
  • 告警维度要匹配:CloudWatch告警的维度必须和CW Agent上报的完全一致,其中Instance对应盘符,objectname固定为LogicalDisk,这样告警才能正确关联到指标。

内容的提问来源于stack exchange,提问作者Steve

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 07:42:45