

# Amazon ECS 集群上自动发现的详细指南
<a name="ContainerInsights-Prometheus-Setup-autodiscovery-ecs"></a>

Prometheus 提供了数十种动态服务发现机制，如 [<scrape\$1config>](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config) 中所述。但是，Amazon ECS 没有内置服务发现。CloudWatch 代理添加了此机制。

启用 Amazon ECS Prometheus 服务发现后，CloudWatch 代理会定期对 Amazon ECS 和 Amazon EC2 前端进行以下 API 调用，以检索目标 ECS 集群中正在运行的 ECS 任务的元数据。

```
EC2:DescribeInstances
ECS:ListTasks
ECS:ListServices
ECS:DescribeContainerInstances
ECS:DescribeServices
ECS:DescribeTasks
ECS:DescribeTaskDefinition
```

CloudWatch 代理使用元数据来扫描 ECS 集群内的 Prometheus 目标。CloudWatch 代理支持三种服务发现模式：
+ 基于容器 docker 标签的服务发现
+ 基于 ECS 任务定义 ARN 正则表达式的服务发现
+ 基于 ECS 服务名称正则表达式的服务发现

所有模式均可同时使用。CloudWatch 代理会根据 `{private_ip}:{port}/{metrics_path}` 对发现的目标进行重复去除。

所有发现的目标均写入由 CloudWatch 代理容器内的 `sd_result_file` 配置字段指定的结果文件。以下为示例结果文件：

```
- targets:
  - 10.6.1.95:32785
  labels:
    __metrics_path__: /metrics
    ECS_PROMETHEUS_EXPORTER_PORT: "9406"
    ECS_PROMETHEUS_JOB_NAME: demo-jar-ec2-bridge-dynamic
    ECS_PROMETHEUS_METRICS_PATH: /metrics
    InstanceType: t3.medium
    LaunchType: EC2
    SubnetId: subnet-123456789012
    TaskDefinitionFamily: demo-jar-ec2-bridge-dynamic-port
    TaskGroup: family:demo-jar-ec2-bridge-dynamic-port
    TaskRevision: "7"
    VpcId: vpc-01234567890
    container_name: demo-jar-ec2-bridge-dynamic-port
    job: demo-jar-ec2-bridge-dynamic
- targets:
  - 10.6.3.193:9404
  labels:
    __metrics_path__: /metrics
    ECS_PROMETHEUS_EXPORTER_PORT_SUBSET_B: "9404"
    ECS_PROMETHEUS_JOB_NAME: demo-tomcat-ec2-bridge-mapped-port
    ECS_PROMETHEUS_METRICS_PATH: /metrics
    InstanceType: t3.medium
    LaunchType: EC2
    SubnetId: subnet-123456789012
    TaskDefinitionFamily: demo-tomcat-ec2-bridge-mapped-port
    TaskGroup: family:demo-jar-tomcat-bridge-mapped-port
    TaskRevision: "12"
    VpcId: vpc-01234567890
    container_name: demo-tomcat-ec2-bridge-mapped-port
    job: demo-tomcat-ec2-bridge-mapped-port
```

您可以直接将此结果文件与基于 Prometheus 文件的服务发现集成。有关基于 Prometheus 文件的服务发现的更多信息，请参阅 [<file\$1sd\$1config>](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#file_sd_config)。

 假设将结果文件写入 `/tmp/cwagent_ecs_auto_sd.yaml`。以下 Prometheus 抓取配置将使用它。

```
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" ]
```

CloudWatch 代理还会为发现的目标添加以下附加标签。
+ `container_name`
+ `TaskDefinitionFamily`
+ `TaskRevision`
+ `TaskGroup`
+ `StartedBy`
+ `LaunchType`
+ `job`
+ `__metrics_path__`
+ Docker 标签

当集群具有 EC2 启动类型时，会添加以下三个标签。
+ `InstanceType`
+ `VpcId`
+ `SubnetId`

**注意**  
与正则表达式 `[a-zA-Z_][a-zA-Z0-9_]*` 不匹配的 Docker 标签将被筛选掉。这与 Prometheus 文档中[配置文件](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#labelname)的 `label_name` 中列出的 Prometheus 惯例相匹配。

## ECS 服务发现配置示例
<a name="ContainerInsights-Prometheus-Setup-autodiscovery-ecs-examples"></a>

本节包括演示 ECS 服务发现的示例。

**示例 1**

```
"ecs_service_discovery": {
  "sd_frequency": "1m",
  "sd_result_file": "/tmp/cwagent_ecs_auto_sd.yaml",
  "docker_label": {
  }
}
```

此示例启用基于 docker 标签的服务发现。CloudWatch 代理将每分钟查询一次 ECS 任务的元数据，并将发现的目标写入 CloudWatch 代理容器内的 `/tmp/cwagent_ecs_auto_sd.yaml` 文件中。

`docker_label` 部分中 `sd_port_label` 的默认值为 `ECS_PROMETHEUS_EXPORTER_PORT`。如果 ECS 任务中任何正在运行的容器具有 `ECS_PROMETHEUS_EXPORTER_PORT` docker 标签，CloudWatch 代理将其值作为 `container port` 来扫描容器的所有公开端口。如果匹配，则使用映射的主机端口和容器的私有 IP，以 `private_ip:host_port` 格式来构建 Prometheus 导出器目标。

`docker_label` 部分中 `sd_metrics_path_label` 的默认值为 `ECS_PROMETHEUS_METRICS_PATH`。如果容器具有此 docker 标签，则其值将用作 `__metrics_path__`。如果容器没有此标签，则使用默认值 `/metrics`。

`docker_label` 部分中 `sd_job_name_label` 的默认值为 `job`。如果容器具有此 docker 标签，则其值将作为一个目标标签附加，以替换 Prometheus 配置中指定的默认任务名称。此 docker 标签的值用作 CloudWatch Logs 日志组中的日志流名称。

**示例 2**

```
"ecs_service_discovery": {
  "sd_frequency": "15s",
  "sd_result_file": "/tmp/cwagent_ecs_auto_sd.yaml",
  "docker_label": {
    "sd_port_label": "ECS_PROMETHEUS_EXPORTER_PORT_SUBSET_A",
    "sd_job_name_label": "ECS_PROMETHEUS_JOB_NAME"  
  }
}
```

此示例启用基于 docker 标签的服务发现。CloudWatch 代理将每 15 秒查询一次 ECS 任务的元数据，并将发现的目标写入 CloudWatch 代理容器内的 `/tmp/cwagent_ecs_auto_sd.yaml` 文件中。带有 `ECS_PROMETHEUS_EXPORTER_PORT_SUBSET_A` 的 docker 标签的容器将被扫描。docker 标签 `ECS_PROMETHEUS_JOB_NAME` 的值用作任务名称。

**示例 3**

```
"ecs_service_discovery": {
  "sd_frequency": "5m",
  "sd_result_file": "/tmp/cwagent_ecs_auto_sd.yaml",
  "task_definition_list": [
    {
      "sd_job_name": "java-prometheus",
      "sd_metrics_path": "/metrics",
      "sd_metrics_ports": "9404; 9406",
      "sd_task_definition_arn_pattern": ".*:task-definition/.*javajmx.*:[0-9]+"
    },
    {
      "sd_job_name": "envoy-prometheus",
      "sd_metrics_path": "/stats/prometheus",
      "sd_container_name_pattern": "^envoy$", 
      "sd_metrics_ports": "9901",
      "sd_task_definition_arn_pattern": ".*:task-definition/.*appmesh.*:23"
    }
  ]
}
```

此示例启用基于 ECS 任务定义 ARN 正则表达式的服务发现。CloudWatch 代理将每五分钟查询一次 ECS 任务的元数据，并将发现的目标写入 CloudWatch 代理容器内的 `/tmp/cwagent_ecs_auto_sd.yaml` 文件中。

定义了两个任务定义 ARN 正则表达式部分：
+  对于第一部分，过滤 ECS 任务定义 ARN 中的 ECS 任务以及 `javajmx`，以进行容器端口扫描。如果这些 ECS 任务中的容器在 9404 或 9406 上公开容器端口，则映射的主机端口和容器的私有 IP 会用于创建 Prometheus 导出器目标。`sd_metrics_path` 的值将 `__metrics_path__` 设置为 `/metrics`。因此 CloudWatch 代理将从 `private_ip:host_port/metrics` 中抓取 Prometheus 指标，抓取的指标发送到日志组 `/aws/ecs/containerinsights/cluster_name/prometheus` 中 CloudWatch Logs 中的 `java-prometheus` 日志流。
+  对于第二部分，过滤 ECS 任务定义 ARN 中带有 `appmesh` 的 ECS 任务以及 `:23` 的 `version`，以进行容器端口扫描。对于在 `9901` 上公开容器端口的、名称为 `envoy` 的容器，映射的主机端口以及容器的私有 IP 用于创建 Prometheus 导出器目标。这些 ECS 任务中的值会公开 9404 或 9406 上的容器端口，映射的主机端口以及容器的私有 IP 用于创建 Prometheus 导出器目标。`sd_metrics_path` 的值将 `__metrics_path__` 设置为 `/stats/prometheus`。因此，CloudWatch 代理将从 `private_ip:host_port/stats/prometheus` 中抓取 Prometheus 指标，并将抓取的指标发送到日志组 `/aws/ecs/containerinsights/cluster_name/prometheus` 中的 CloudWatch Logs 中的 `envoy-prometheus` 日志流。

**示例 4**。

```
"ecs_service_discovery": {
  "sd_frequency": "5m",
  "sd_result_file": "/tmp/cwagent_ecs_auto_sd.yaml",
  "service_name_list_for_tasks": [
    {
      "sd_job_name": "nginx-prometheus",
      "sd_metrics_path": "/metrics",
      "sd_metrics_ports": "9113",
      "sd_service_name_pattern": "^nginx-.*"
    },
    {
      "sd_job_name": "haproxy-prometheus",
      "sd_metrics_path": "/stats/metrics",
      "sd_container_name_pattern": "^haproxy$",
      "sd_metrics_ports": "8404",
      "sd_service_name_pattern": ".*haproxy-service.*"
    }
  ]
}
```

本示例启用基于 ECS 服务名称正则表达式的服务发现。CloudWatch 代理将每五分钟查询一次 ECS 服务的元数据，并将发现的目标写入 CloudWatch 代理容器内的 `/tmp/cwagent_ecs_auto_sd.yaml` 文件中。

定义了两个服务名称正则表达式部分：
+  对于第一部分，过滤与 ECS 服务关联的 ECS 任务（名称与正则表达式 `^nginx-.*` 相匹配），以进行容器端口扫描。如果这些 ECS 任务中的容器在 9113 上公开容器端口，则映射的主机端口和容器的私有 IP 将用于创建 Prometheus 导出器目标。`sd_metrics_path` 的值将 `__metrics_path__` 设置为 `/metrics`。因此，CloudWatch 代理将从 `private_ip:host_port/metrics` 中抓取 Prometheus 指标，并将抓取的指标发送到日志组 `/aws/ecs/containerinsights/cluster_name/prometheus` 中 CloudWatch Logs 中的 `nginx-prometheus` 日志流。
+  或第二部分，过滤与 ECS 服务关联的 ECS 任务（名称与正则表达式 `.*haproxy-service.*` 匹配），以进行容器端口扫描。对于在 8404 上公开容器端口、名称为 `haproxy` 的容器，映射的主机端口以及容器的私有 IP 用于创建 Prometheus 导出器目标。`sd_metrics_path` 的值将 `__metrics_path__` 设置为 `/stats/metrics`。因此，CloudWatch 代理将从 `private_ip:host_port/stats/metrics` 中抓取 Prometheus 指标，并将抓取的指标发送到日志组 `/aws/ecs/containerinsights/cluster_name/prometheus` 中 CloudWatch Logs 中的 `haproxy-prometheus` 日志流。

**示例 5**

```
"ecs_service_discovery": {
  "sd_frequency": "1m30s",
  "sd_result_file": "/tmp/cwagent_ecs_auto_sd.yaml",
  "docker_label": {
    "sd_port_label": "MY_PROMETHEUS_EXPORTER_PORT_LABEL",
    "sd_metrics_path_label": "MY_PROMETHEUS_METRICS_PATH_LABEL",
    "sd_job_name_label": "MY_PROMETHEUS_METRICS_NAME_LABEL"  
  }
  "task_definition_list": [
    {
      "sd_metrics_ports": "9150",
      "sd_task_definition_arn_pattern": "*memcached.*"
    }
  ]
}
```

本示例启用了两种 ECS 服务发现模式。CloudWatch 代理将每 90 秒查询一次 ECS 任务的元数据，并将发现的目标写入 CloudWatch 代理容器内的 `/tmp/cwagent_ecs_auto_sd.yaml` 文件中。

对于基于 docker 的服务发现配置：
+ 过滤带有 docker 标签 `MY_PROMETHEUS_EXPORTER_PORT_LABEL` 的 ECS 任务，以进行 Prometheus 端口扫描。目标 Prometheus 容器端口由 label `MY_PROMETHEUS_EXPORTER_PORT_LABEL` 的值指定。
+ docker 标签 `MY_PROMETHEUS_EXPORTER_PORT_LABEL` 的值用于 `__metrics_path__`。如果容器没有此 docker 标签，则使用默认值 `/metrics`。
+ docker 标签 `MY_PROMETHEUS_EXPORTER_PORT_LABEL` 的值用作任务标签。如果容器没有此 docker 标签，则使用 Prometheus 配置中定义的任务名称。

对于基于 ECS 任务定义 ARN 正则表达式的服务发现配置：
+ 过滤 ECS 任务定义 ARN 中带 `memcached` 的 ECS 任务，以进行容器端口扫描。根据 `sd_metrics_ports` 定义，目标 Prometheus 容器端口是 9150。使用默认指标路径 `/metrics`。使用 Prometheus 配置中定义的任务名称。