CloudWatch收集ECS Task自定义Prometheus指标完整指南

核心摘要

  • CloudWatch Agent以Service模式运行,支持ECS集群内Task的自动发现,可收集JVM、Nginx等应用层Prometheus指标
  • 三种服务发现模式可组合使用:Docker Label、Task Definition ARN正则、Service Name正则,并支持基于IP:Port的自动去重
  • 通过jmx_exporter暴露Java应用指标,配合EMF Processor将数据转换为CloudWatch Metrics,实现与Container Insights深度集成
  • 完整方案涵盖CloudFormation部署、Parameter Store配置、Task Definition定义及安全组设置等关键环节

CloudWatch收集ECS Task自定义Prometheus指标完整指南

容器化监控的现实挑战

容器化技术已经成为现代应用部署的事实标准。当企业将工作负载迁移到Amazon ECS (Elastic Container Service)这类容器编排平台时,可观测性问题随之而来——如何有效收集分布式系统中的应用级指标?特别是JVM内存使用垃圾回收频率Nginx连接数等Prometheus格式的特定指标,传统的基础设施监控手段往往力不从心。

AWS提供了两种主流的Prometheus指标收集方案。ADOT(AWS Distro for OpenTelemetry)支持以Service方式运行在ECS集群中,但这种部署模式无法深入收集应用内部指标;虽然ADOT也支持SideCar部署方式来获取JVM等应用指标,但对现有应用架构存在一定侵入性。相比之下,Amazon CloudWatch Agent方案以Service模式运行,既能收集应用内部指标,又能与Container Insights及整个AWS生态系统深度集成。

CloudWatch Agent方案的核心优势

采用CloudWatch Agent收集Prometheus指标,能够为运维团队带来多维度的可观测性提升:

  • 端到端可见性:从基础设施层面的CPU、内存利用率、网络流量,到应用层面的自定义业务指标,形成完整的监控视图
  • 微服务架构友好:在由数十甚至数百个服务组成的应用中,通过统一的Prometheus集成实现数据的集中收集与分析
  • 主动式告警能力:基于Prometheus指标设置告警规则,在问题影响终端用户之前完成识别和处置
  • 预构建Dashboard支持:针对EKS、EC2、ECS等不同计算环境,AWS已预置了丰富的监控面板模板

预构建的Dashboard覆盖了多种常见工作负载场景,包括AWS App Mesh服务网格、Java/JMX应用、NGINXNGINX Plus应用等。然而,当业务需要监控jvm_gc_collection等自定义指标时,就需要手动配置CloudWatch Agent的指标收集规则。

技术架构与工作原理

Amazon ECS Container Insights通过CloudWatch Agent实现Prometheus监控的自动发现与指标采集,整体数据流转过程如下:

  • 应用侧指标暴露:通过Prometheus各类exporter(如jmx_exporter)将应用内部指标以HTTP端点形式对外暴露
  • 服务自动发现:CloudWatch Agent定期调用ECS集群控制平面API,自动发现运行中的Task实例
  • 指标抓取与转换:根据PROMETHEUS_CONFIG_CONTENTCloudWatch_CONFIG_CONTENT配置,Agent抓取指标并转换为EMF(Embedded Metric Format)格式
  • 存储与展示:EMF数据写入CloudWatch Logs,随后自动转换为CloudWatch Metrics在控制台面板中呈现

Container Insights对Prometheus指标的支持覆盖了主流的启动类型与网络模式组合:

  • EC2 (Linux)启动类型:支持bridgehostawsvpc网络模式
  • Fargate启动类型:仅支持awsvpc网络模式

实施步骤详解

通过CloudFormation部署CloudWatch Agent

部署前需要设置必要的环境变量,这些变量将在后续的CloudFormation堆栈创建中被引用:

export AWS_PROFILE=your_aws_config_profile_eg_default
export AWS_DEFAULT_REGION=your_aws_region_eg_ap-southeast-1
export ECS_CLUSTER_NAME=your_ec2_ecs_cluster_name
export ECS_LAUNCH_TYPE=FARGATE
export CREATE_IAM_ROLES=True
export ECS_CLUSTER_SECURITY_GROUP=your_security_group_eg_sg-xxxxxxxxxx
export ECS_CLUSTER_SUBNET=your_subnet_eg_subnet-xxxxxxxxxx
export ECS_TASK_ROLE_NAME=ecsTaskExecutionRole
export ECS_EXECUTION_ROLE_NAME=ecsExecutionRole

下载官方提供的CloudFormation模板文件:

curl -O https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/latest/ecs-task-definition-templates/deployment-mode/replica-service/cwagent-prometheus/cloudformation-quickstart/cwagent-ecs-prometheus-metric-for-awsvpc.yaml

执行堆栈创建命令,注意–capabilities CAPABILITY_NAMED_IAM参数是必需的,因为模板会创建IAM角色:

aws cloudformation create-stack \
--stack-name CWAgent-Prometheus-ECS-${ECS_CLUSTER_NAME}-${ECS_LAUNCH_TYPE}-awsvpc \
--template-body file://cwagent-ecs-prometheus-metric-for-awsvpc.yaml \
--parameters \
ParameterKey=ECSClusterName,ParameterValue=${ECS_CLUSTER_NAME} \
ParameterKey=CreateIAMRoles,ParameterValue=${CREATE_IAM_ROLES} \
ParameterKey=ECSLaunchType,ParameterValue=${ECS_LAUNCH_TYPE} \
ParameterKey=SecurityGroupID,ParameterValue=${ECS_CLUSTER_SECURITY_GROUP} \
ParameterKey=SubnetID,ParameterValue=${ECS_CLUSTER_SUBNET} \
ParameterKey=TaskRoleName,ParameterValue=${ECS_TASK_ROLE_NAME} \
ParameterKey=ExecutionRoleName,ParameterValue=${ECS_EXECUTION_ROLE_NAME} \
--capabilities CAPABILITY_NAMED_IAM \
--region ${AWS_DEFAULT_REGION}

部署完成后,CloudFormation会自动创建两个IAM Role,分别用于Task执行和CloudWatch Agent的权限授予。

配置服务自动发现机制

CloudWatch Agent支持三种ECS Task自动发现模式,可根据实际需求灵活组合:

  • Container Docker Label:基于容器标签进行匹配
  • Task Definition ARN正则表达式:通过Task Definition的ARN模式匹配
  • Service Name正则表达式:基于ECS Service名称进行匹配

当同时启用多种发现模式时,CloudWatch Agent内置的de-duplicates机制会自动进行指标去重,去重依据为{private_ip}:{port}/{metrics_path}的组合标识。

在AWS Systems Manager Parameter Store中创建名为prometheus-config的参数,内容如下:

global:
  scrape_interval: 1m
  scrape_timeout: 10s
scrape_configs:
  - job_name: cwagent-ecs-file-sd-config
    sample_limit: 10000
    file_sd_configs:
      - files: [ "/tmp/cwagent_ecs_auto_sd.yaml" ]

这里的job_name需要与后续cwagent-config中的label_matcher保持一致,files路径也需要与sd_result_file配置匹配。

CloudWatch Agent核心配置

在Parameter Store中创建cwagent-config参数,这是整个方案的核心配置文件:

{
  "agent": {
    "debug": true
  },
  "logs": {
    "metrics_collected": {
      "prometheus": {
        "cluster_name": "testecs",
        "log_group_name": "/aws/ecs/containerinsights/testecs/prometheus",
        "prometheus_config_path": "env:PROMETHEUS_CONFIG_CONTENT",
        "ecs_service_discovery": {
          "sd_frequency": "1m",
          "sd_result_file": "/tmp/cwagent_ecs_auto_sd.yaml",
          "task_definition_list": [
            {
              "sd_task_definition_arn_pattern": ".*:task-definition/*"
            }
          ]
        },
        "emf_processor": {
          "metric_declaration_dedup": true,
          "metric_declaration": [
            {
              "source_labels": ["job"],
              "label_matcher": "cwagent-ecs-file-sd-config",
              "dimensions": [["ClusterName","TaskDefinitionFamily"]],
              "metric_selectors": [
                "^jvm_threads_current$",
                "^jvm_threads_peak$",
                "^jvm_gc_collection_seconds_count$",
                "^jvm_gc_collection_seconds_sum$",
                "^jvm_classes_currently_loaded$",
                "^jvm_memory_max_bytes$",
                "^jvm_memory_used_bytes$"
              ]
            },
            {
              "source_labels": ["job"],
              "label_matcher": "cwagent-ecs-file-sd-config",
              "dimensions": [["ClusterName","TaskDefinitionFamily","pool"]],
              "metric_selectors": [
                "^jvm_memory_pool_max_bytes$",
                "^jvm_memory_pool_used_bytes$",
                "^jvm_memory_pool_committed_bytes$"
              ]
            }
          ]
        }
      }
    },
    "force_flush_interval": 5
  }
}

配置要点说明:

  • cluster_namelog_group_name是必填项,用于指标过滤和日志归档
  • sd_task_definition_arn_pattern支持正则表达式,可根据业务需求精确控制Task发现范围
  • metric_declaration_dedup设为true启用自动去重功能
  • metric_selectors中的指标名称必须与jmx_exporter暴露的名称完全一致
  • 不同指标可能需要不同的dimensions配置,如内存池指标需要额外的pool维度

构建测试用Java应用

准备一个集成了jmx_exporter的Java应用镜像,Dockerfile配置如下:

# 使用OpenJDK 17作为基础镜像
FROM openjdk:17-jre-slim
LABEL description="Simple Java Web Application with JMX Exporter for ECS"

# 创建应用目录
RUN mkdir -p /opt/app
WORKDIR /opt/app

# 复制JMX Exporter jar文件
COPY jmx_prometheus_javaagent-0.20.0.jar /opt/app/

# 复制Web应用程序jar文件
COPY simple-web-app.jar /opt/app/

# 复制JMX配置文件
COPY config.yaml /opt/app/

# 安装curl用于健康检查
RUN apt-get update && \
    apt-get install -y curl && \
    rm -rf /var/lib/apt/lists/* && \
    apt-get clean

# 创建非root用户
RUN groupadd -r appuser && useradd -r -g appuser appuser
RUN chown -R appuser:appuser /opt/app
USER appuser

# 暴露端口:80为应用端口,9404为Prometheus指标端口
EXPOSE 80 9404

# 设置健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
    CMD curl -f http://localhost/health || exit 1

# 启动命令
CMD ["java", "-javaagent:jmx_prometheus_javaagent-0.20.0.jar=9404:config.yaml", "-jar", "simple-web-app.jar"]

其中config.yaml是jmx_exporter的配置文件,使用pattern: “.*”可暴露所有JMX指标。如需进行指标重命名或过滤,可在此文件中添加相应规则。需要注意的是,jmx_prometheus_javaagent不同版本的指标命名可能存在差异,建议从Prometheus官网下载与文档匹配的版本。

构建完成后,将镜像推送至AWS ECR仓库备用。

创建Task Definition并运行Task

Task Definition的完整JSON配置示例:

{
  "taskDefinitionArn": "arn:aws:ecs:ap-southeast-1:your-id:task-definition/simple-web-app-task:3",
  "containerDefinitions": [
    {
      "name": "jmxsample-container",
      "image": "your-id.dkr.ecr.ap-southeast-1.amazonaws.com/simple-web-app",
      "cpu": 0,
      "portMappings": [
        {
          "containerPort": 80,
          "hostPort": 80,
          "protocol": "tcp"
        },
        {
          "containerPort": 9404,
          "hostPort": 9404,
          "protocol": "tcp"
        }
      ],
      "essential": true,
      "environment": [],
      "mountPoints": [],
      "volumesFrom": [],
      "dockerLabels": {
        "Java_EMF_Metrics": "true"
      },
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/simple-web-app",
          "awslogs-region": "ap-southeast-1",
          "awslogs-stream-prefix": "ecs"
        }
      },
      "systemControls": []
    }
  ],
  "family": "simple-web-app-task",
  "executionRoleArn": "arn:aws:iam::your-id:role/ecsTaskExecutionRole",
  "networkMode": "awsvpc",
  "revision": 3,
  "volumes": [],
  "status": "ACTIVE",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "256",
  "memory": "512"
}

关键配置说明:

  • portMappings必须同时映射应用端口(80)和Prometheus指标端口(9404)
  • dockerLabels可用于基于Label的服务发现模式
  • networkMode设为awsvpc以支持Fargate启动类型
  • Task关联的安全组必须放开80和9404端口的入站规则

运行Task后,在ECS控制台找到Task实例的私网IP,通过curl http://{private_ip}:9404/metrics可验证指标是否正常暴露。

CloudWatch控制台验证

指标收集成功后,在CloudWatch控制台的Metrics页面会出现新的ECS/ContainerInsights/Prometheus namespace。进入该namespace,可按不同维度(ClusterName、TaskDefinitionFamily等)浏览已收集的JVM指标数据。

实施要点与注意事项

  • 配置一致性:prometheus-config中的job_name、files路径必须与cwagent-config中的对应配置严格匹配
  • 指标命名:metric_selectors中的指标名称需与exporter实际暴露的名称完全一致,建议先通过curl验证
  • 维度设计:不同类型的指标可能需要不同的dimensions配置,如内存池指标需要pool维度
  • 安全组配置:确保CloudWatch Agent所在Task能够访问目标Task的Prometheus端口
  • 费用考量:自定义指标会产生CloudWatch Metrics费用,具体定价请参考AWS官方文档

对于需要在多云环境中统一管理监控成本的团队,可以考虑通过多云账单代付解决方案来优化整体云支出。

方案价值与应用场景

通过CloudWatch Agent收集ECS Task的自定义Prometheus指标,企业能够在不改变现有应用架构的前提下,实现对容器化工作负载的深度可观测性。这套方案已在实际生产环境中得到验证——某制造业头部客户成功基于此方案优化了其在Amazon ECS上的Prometheus指标监控体系。

该方案特别适用于以下场景:需要监控Java应用JVM性能、希望统一Prometheus与CloudWatch监控体系、追求低侵入性的监控集成方式,以及需要利用Container Insights预构建Dashboard的团队。

AWS/GCP/多云账单代付 – 免实名 & 支持 USDT 支付 | Payment 解决方案为企业提供灵活的云服务费用管理方式。如果您正在规划ECS容器监控方案或有其他AWS服务使用需求,欢迎了解我们的服务。

AWS51

AWS/阿里云/谷歌云官方认证架构师,专注云计算解决方案。