在使用 AWS Elastic Container Service (ECS) 时,我们可能需要监控服务的运行状况,及时发现和处理任务失败的情况。虽然 AWS CloudWatch 提供了一些预定义的 ECS 指标,但有时我们需要自定义指标和告警,以满足特定的监控需求。本文将介绍如何使用 Python 代码自定义 ECS 服务的失败任务指标,并在 CloudWatch 中设置相应的告警。

1. 获取 ECS 服务的失败任务数

首先,我们需要获取 ECS 服务的失败任务数。AWS 提供了 Boto3 库,让我们可以通过 Python 代码与 AWS 服务进行交互。以下代码展示了如何获取指定集群中所有服务的失败任务数:

import boto3
from datetime import datetime, timezone
from botocore.exceptions import ClientError

# 创建 ECS 客户端
ecs_client = boto3.client('ecs')

# 创建 CloudWatch 客户端
cloudwatch_client = boto3.client('cloudwatch')

# 定义集群名称列表
cluster_names = ['pro-cluster1', 'pro-cluster2', 'pro-cluster3', 'pro-cluster4', 'frontend-pro']

# 定义指标名称和命名空间
metric_name = 'FailedTasks'
namespace = 'ECS'

def get_service_arns(cluster_name):
    """获取指定集群中所有服务的 ARN"""
    service_arns = []
    next_token = ''
    while True:
        try:
            if next_token:
                response = ecs_client.list_services(cluster=cluster_name, nextToken=next_token)
            else:
                response = ecs_client.list_services(cluster=cluster_name)

            service_arns.extend(response['serviceArns'])

            if 'nextToken' in response:
                next_token = response['nextToken']
            else:
                break
        except ClientError as e:
            print(f"Error listing services in cluster {cluster_name}: {e}")
            break

    return service_arns

def upload_metric_data(service_name, cluster_name, failed_tasks):
    """上传指标数据到 CloudWatch"""
    metric_data = {
        'MetricName': metric_name,
        'Dimensions': [
            {
                'Name': 'ServiceName',
                'Value': service_name
            },
            {
                'Name': 'ClusterName',
                'Value': cluster_name
            }
        ],
        'Value': failed_tasks,
        'Unit': 'Count',
        'Timestamp': datetime.now(timezone.utc)
    }

    try:
        cloudwatch_client.put_metric_data(
            Namespace=namespace,
            MetricData=[metric_data]
        )
        print(f"Metric data uploaded to CloudWatch for service {service_name} in cluster {cluster_name} successfully.")
    except ClientError as e:
        print(f"Error uploading metric data to CloudWatch: {e}")

# 遍历集群列表
for cluster_name in cluster_names:
    service_arns = get_service_arns(cluster_name)

    # 遍历服务列表
    for service_arn in service_arns:
        service_name = service_arn.split('/')[-1]

        # 调用 describe_services 方法
        try:
            response = ecs_client.describe_services(
                cluster=cluster_name,
                services=[service_name]
            )
        except ClientError as e:
            print(f"Error describing service {service_name} in cluster {cluster_name}: {e}")
            continue

        # 从响应中获取最新部署的 failedTasks 值
        services = response.get('services', [])
        if services:
            service = services[0]
            deployments = service.get('deployments', [])
            if deployments:
                latest_deployment = deployments[0]  # 假设部署列表按时间顺序排列
                failed_tasks = latest_deployment.get('failedTasks', 0)
                print(f"Failed tasks for service {service_name} in cluster {cluster_name}: {failed_tasks}")

                # 上传指标数据到 CloudWatch
                upload_metric_data(service_name, cluster_name, failed_tasks)
        else:
            print(f"No services found in cluster {cluster_name}.")

在这段代码中,我们首先创建了 ECS 和 CloudWatch 客户端。然后,我们定义了要监控的集群名称列表和指标名称及命名空间。

接下来,我们定义了两个辅助函数:

  1. get_service_arns 函数用于获取指定集群中所有服务的 ARN。它处理了 list_services 方法的分页结果,并返回一个包含所有服务 ARN 的列表。
  2. upload_metric_data 函数用于将指标数据上传到 CloudWatch。它接受服务名称、集群名称和失败任务数作为参数,构建指标数据并上传到 CloudWatch。

在主循环中,我们遍历集群列表。对于每个集群,我们首先调用 get_service_arns 函数获取该集群中所有服务的 ARN。然后,对于每个服务 ARN,我们调用 describe_services 方法获取服务详情。如果获取成功,我们从响应中提取最新部署的 failedTasks 值,打印出来,并调用 upload_metric_data 函数将指标数据上传到 CloudWatch。

通过这段代码,我们可以获取每个 ECS 服务的失败任务数,并将其作为自定义指标上传到 CloudWatch。接下来,我们需要在 CloudWatch 中设置告警。

2. 在 CloudWatch 中设置告警

在 AWS 管理控制台中,进入 CloudWatch 服务,选择 "Alarms" -> "All alarms" -> "Create alarm"。

在创建告警页面,选择 "ECS" 作为指标命名空间,然后选择 "FailedTasks" 作为指标名称。接下来,选择要监控的维度,例如 "ClusterName" 和 "ServiceName"。

设置告警阈值,例如当失败任务数大于 0 时触发告警。然后,选择告警状态持续时间,例如 1 个周期。最后,设置告警通知方式,例如发送电子邮件或调用 AWS Lambda 函数。

完成上述步骤后,每当 ECS 服务的失败任务数大于 0 时,CloudWatch 就会触发告警,并通过设置的通知方式通知我们。

总结

通过编写 Python 代码获取 ECS 服务的失败任务数,并将其作为自定义指标上传到 CloudWatch,我们可以更好地监控 ECS 服务的运行状况。结合在 CloudWatch 中设置的告警,我们可以及时发现和处理任务失败的情况,提高应用程序的可靠性和可用性。