核心摘要
- 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应用、NGINX及NGINX 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_CONTENT和CloudWatch_CONFIG_CONTENT配置,Agent抓取指标并转换为EMF(Embedded Metric Format)格式
- 存储与展示:EMF数据写入CloudWatch Logs,随后自动转换为CloudWatch Metrics在控制台面板中呈现
Container Insights对Prometheus指标的支持覆盖了主流的启动类型与网络模式组合:
- EC2 (Linux)启动类型:支持bridge、host和awsvpc网络模式
- 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_name和log_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服务使用需求,欢迎了解我们的服务。