如何通过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
相关产品推荐
相关产品推荐

