如何在CloudFormation中匹配指定前缀的ECS ServiceName创建CloudWatch告警
结论
原生CloudWatch告警的Dimension配置不支持通配符或正则匹配,没有直接语法可以在Dimension的Value字段直接实现前缀匹配,以下是两个无需修改底层架构CloudFormation模板的可行实现方案:
方案1:使用CloudWatch SEARCH函数构建告警(推荐,无需额外资源)
CloudWatch告警支持使用SEARCH搜索表达式批量匹配符合规则的指标,无需提前知道完整的ServiceName,直接在CloudFormation模板中配置即可:
SomeAlarm: Type: 'AWS::CloudWatch::Alarm' Properties: AlarmDescription: 匹配指定前缀ECS服务的告警 Metrics: - Id: m1 Expression: 'SEARCH(''{AWS/ECS,ClusterName,ServiceName} ClusterName="<替换为已知集群名>" AND ServiceName="<替换为已知前缀>*"'', "<替换为实际监控指标名,比如CPUUtilization>", "Average")' ReturnData: true EvaluationPeriods: 3 Threshold: 80 ComparisonOperator: GreaterThanThreshold # 其余告警配置按需补充
注意:单个SEARCH表达式最多匹配100个指标,超过限制时需要拆分多个表达式,该方案会自动匹配符合前缀规则的所有ECS服务,新增符合前缀的服务时无需修改告警模板自动覆盖。
方案2:使用CloudFormation自定义资源获取完整ServiceName
如果仅需要匹配单个ECS服务、不需要自动适配新增服务,可以在告警模板中新增Lambda backed自定义资源,模板部署时自动调用ECS API过滤出符合前缀的服务名,直接传给告警配置:
- 首先在模板中新增Lambda角色和自定义资源:
# Lambda执行角色,需包含ecs:ListServices权限 EcsServiceQueryRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: sts:AssumeRole Policies: - PolicyName: EcsListAccess PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: ecs:ListServices Resource: '*' - Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Resource: arn:aws:logs:*:*:* # 自定义资源,用于查询符合前缀的ECS服务名 EcsServiceQuery: Type: Custom::EcsServiceQuery Properties: ServiceToken: !GetAtt EcsServiceQueryFunction.Arn ClusterName: "<替换为已知集群名>" ServicePrefix: "<替换为已知前缀>" # 实现查询逻辑的Lambda函数 EcsServiceQueryFunction: Type: AWS::Lambda::Function Properties: Runtime: python3.9 Code: ZipFile: | import boto3 import cfnresponse ecs = boto3.client('ecs') def handler(event, context): if event['RequestType'] == 'Delete': cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) return cluster = event['ResourceProperties']['ClusterName'] prefix = event['ResourceProperties']['ServicePrefix'] services = ecs.list_services(cluster=cluster)['serviceArns'] matched = [s.split('/')[-1] for s in services if s.split('/')[-1].startswith(prefix)] if matched: cfnresponse.send(event, context, cfnresponse.SUCCESS, {'ServiceName': matched[0]}) else: cfnresponse.send(event, context, cfnresponse.FAILED, {'Error': 'No matched service found'}) Handler: index.handler Role: !GetAtt EcsServiceQueryRole.Arn
- 告警配置中直接引用自定义资源返回的服务名:
SomeAlarm: Type: 'AWS::CloudWatch::Alarm' Properties: Dimensions: - Name: ClusterName Value: <已知集群名> - Name: ServiceName Value: !GetAtt EcsServiceQuery.ServiceName # 其余告警配置按需补充
内容的提问来源于stack exchange,提问作者MJ211
相关产品推荐
相关产品推荐

