OpenTelemetry Collector Contribをサイドカーコンテナとしてデプロイすることで、AWS Fargateで実行されているAmazon ECSタスクをモニターします。この包括的なガイドでは、サーバーレスECSワークロード向けのタスク定義の作成、コレクターの設定、および監視の設定について説明します。
インストレーション手順
ECS Fargateタスクの監視を設定するには、以下の手順に従ってください。
あなたが始める前に
環境が次の要件を満たしていることを確認してください。
New Relicライセンスキーを保存する
OpenTelemetry Collectorの認証情報を安全に保存するために、ライセンスキーをSystems Manager(SSM)パラメーターとして保存します:
$aws ssm put-parameter \> --name "/newrelic-infra/ecs/license-key" \> --type SecureString \> --description 'New Relic license key for ECS monitoring' \> --value "YOUR_NEW_RELIC_LICENSE_KEY"IAMポリシーと実行ロールの作成
ECSコンテナがNew Relicライセンスキーを安全に取得できるように、IAMポリシーを作成します:
$aws iam create-policy \> --policy-name "NewRelicSSMLicenseKeyReadAccess" \> --policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["ssm:GetParameters"],"Resource":["arn:aws:ssm:*:*:parameter/newrelic-infra/ecs/license-key"]}]}' \> --description "Provides read access to the New Relic SSM license key parameter"タスク実行ロールとして使用するIAMロールを作成します。
$aws iam create-role \> --role-name "NewRelicECSTaskExecutionRole" \> --assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"ecs-tasks.amazonaws.com"},"Action":"sts:AssumeRole"}]}' \> --description "ECS task execution role for New Relic infrastructure"必要なマネージドポリシーをロールにアタッチします:
$# Attach the standard ECS task execution policy$aws iam attach-role-policy \> --role-name "NewRelicECSTaskExecutionRole" \> --policy-arn "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"$
$# Attach the New Relic SSM license key read access policy$aws iam attach-role-policy \> --role-name "NewRelicECSTaskExecutionRole" \> --policy-arn "arn:aws:iam::$(aws sts get-caller-identity --query Account --output text):policy/NewRelicSSMLicenseKeyReadAccess"コレクターの設定を保存する
コンテナイメージを再ビルドせずに設定を管理および更新できるように、OpenTelemetry Collector の設定を AWS Systems Manager Parameter Store に保存します:
$aws ssm put-parameter \> --name "/ecs/otel-collector/fargate-config" \> --type "String" \> --value "$(cat <<EOF$receivers:$ awsecscontainermetrics:$ collection_interval: <COLLECTION_INTERVAL>$
$processors:$ metricstransform/base:$ transforms:$ - include: container.cpu.utilized$ action: insert$ new_name: container.cpu.utilization$ - include: container.memory.usage$ action: insert$ new_name: container.memory.usage.total$ - include: container.storage.read_bytes$ action: insert$ new_name: container.blockio.io_service_bytes_recursive$ operations:$ - action: add_label$ new_label: operation$ new_value: read$ - include: container.storage.write_bytes$ action: insert$ new_name: container.blockio.io_service_bytes_recursive$ operations:$ - action: add_label$ new_label: operation$ new_value: write$ transform/promote_cluster_keys:$ metric_statements:$ - context: datapoint$ statements:$ - set(attributes["aws.ecs.cluster.name"], resource.attributes["aws.ecs.cluster.name"]) where resource.attributes["aws.ecs.cluster.name"] != nil$ - set(attributes["cloud.account.id"], resource.attributes["cloud.account.id"]) where resource.attributes["cloud.account.id"] != nil$ - set(attributes["cloud.region"], resource.attributes["cloud.region"]) where resource.attributes["cloud.region"] != nil$ - set(attributes["aws.ecs.task.arn"], resource.attributes["aws.ecs.task.arn"]) where resource.attributes["aws.ecs.task.arn"] != nil$ metricstransform/cluster_aggregation:$ transforms:$ - include: container.cpu.utilization$ action: insert$ new_name: ecs.cluster.cpu.utilization$ operations:$ - action: aggregate_labels$ label_set: [aws.ecs.cluster.name, cloud.account.id, cloud.region]$ aggregation_type: mean$ - include: container.memory.usage.total$ action: insert$ new_name: ecs.cluster.memory.usage$ operations:$ - action: aggregate_labels$ label_set: [aws.ecs.cluster.name, cloud.account.id, cloud.region]$ aggregation_type: sum$ - include: container.network.io.usage.rx_bytes$ action: insert$ new_name: ecs.cluster.network.rx_bytes$ operations:$ - action: aggregate_labels$ label_set: [aws.ecs.cluster.name, cloud.account.id, cloud.region]$ aggregation_type: sum$ - include: container.network.io.usage.tx_bytes$ action: insert$ new_name: ecs.cluster.network.tx_bytes$ operations:$ - action: aggregate_labels$ label_set: [aws.ecs.cluster.name, cloud.account.id, cloud.region]$ aggregation_type: sum$ - include: container.cpu.utilization$ action: insert$ new_name: ecs.cluster.running_task_count$ operations:$ - action: aggregate_labels$ label_set: [aws.ecs.cluster.name, cloud.account.id, cloud.region, aws.ecs.task.arn]$ aggregation_type: mean$ - action: aggregate_labels$ label_set: [aws.ecs.cluster.name, cloud.account.id, cloud.region]$ aggregation_type: count$ - include: container.memory.usage.limit$ action: insert$ new_name: ecs.cluster.memory.limit$ operations:$ - action: aggregate_labels$ label_set: [aws.ecs.cluster.name, cloud.account.id, cloud.region]$ aggregation_type: sum$ transform/running_task_count_one:$ metric_statements:$ - context: datapoint$ statements:$ - set(value_double, 1.0) where metric.name == "ecs.cluster.running_task_count"$ metricstransform/running_task_count_sum:$ transforms:$ - include: ecs.cluster.running_task_count$ action: update$ operations:$ - action: aggregate_labels$ label_set: [aws.ecs.cluster.name, cloud.account.id, cloud.region]$ aggregation_type: sum$ filter/cluster_metrics:$ metrics:$ include:$ match_type: regexp$ metric_names:$ - ^ecs\.cluster\..*$
$ metricstransform/task_metrics:$ transforms:$ - include: ecs.task.cpu.utilized$ action: insert$ new_name: ecs.task.cpu.utilization$ - include: container.memory.usage.total$ action: insert$ new_name: ecs.task.memory.usage$ filter/task_metrics:$ metrics:$ include:$ match_type: strict$ metric_names: $ - "ecs.task.cpu.utilization" $ - "ecs.task.cpu.utilized" $ - "ecs.task.memory.utilized" $ - "ecs.task.memory.usage" $ - "ecs.task.memory.usage.limit" $ - "ecs.task.network.io.usage.rx_bytes" $ - "ecs.task.network.io.usage.tx_bytes"$ $ filter/container_metrics:$ metrics:$ include:$ match_type: regexp$ metric_names:$ - ^container\..*$ transform/cluster_identifier:$ metric_statements:$ - context: resource$ statements:$ - set(attributes["aws.arn"], resource.attributes["aws.ecs.task.arn"]) where resource.attributes["aws.ecs.task.arn"] != nil and resource.attributes["aws.ecs.cluster.name"] != nil$ - replace_pattern(attributes["aws.arn"], ":task/.*", "") where attributes["aws.arn"] != nil$ - set(attributes["aws.arn"], Concat([attributes["aws.arn"], ":cluster/", resource.attributes["aws.ecs.cluster.name"]], "")) where attributes["aws.arn"] != nil and resource.attributes["aws.ecs.cluster.name"] != nil$ transform/task_identifier:$ metric_statements:$ - context: resource$ statements:$ - set(attributes["TaskArn"], resource.attributes["aws.ecs.task.arn"]) where resource.attributes["aws.ecs.task.arn"] != nil$
$ batch:$ send_batch_size: <SEND_BATCH_SIZE>$ timeout: <BATCH_TIMEOUT>$ $ resource/cluster:$ attributes:$ - key: ClusterName$ from_attribute: aws.ecs.cluster.name$ action: insert$ - key: cloud.platform$ value: "aws_ecs"$ action: upsert$
$ resource/task:$ attributes:$ - key: ClusterName$ from_attribute: aws.ecs.cluster.name$ action: insert$ - key: ServiceName$ from_attribute: aws.ecs.service.name$ action: insert$ - key: TaskId$ from_attribute: aws.ecs.task.id$ action: insert$ - key: TaskArn$ from_attribute: aws.ecs.task.arn$ action: insert$ - key: TaskDefinitionFamily$ from_attribute: aws.ecs.task.family$ action: insert$ - key: LaunchType$ from_attribute: aws.ecs.launch_type$ action: insert$ - key: cloud.platform$ value: "aws_ecs"$ action: upsert$ - key: docker.host$ from_attribute: aws.ecs.task.id$ action: insert$ - key: docker.imageName$ from_attribute: container.image.name$ action: insert$ - key: docker.containerId$ from_attribute: container.id$ action: insert$ - key: docker.state$ from_attribute: aws.ecs.container.know_status$ action: insert$
$exporters:$ otlphttp:$ endpoint: https://otlp.nr-data.net:443$ headers:$ api-key: \${NEW_RELIC_LICENSE_KEY}$
$ debug:$ verbosity: basic$
$service:$ pipelines:$ metrics/clusters:$ receivers: [awsecscontainermetrics]$ processors: [$ metricstransform/base,$ transform/promote_cluster_keys, $ metricstransform/cluster_aggregation,$ transform/running_task_count_one,$ metricstransform/running_task_count_sum, $ filter/cluster_metrics,$ transform/cluster_identifier,$ resource/cluster,$ batch$ ]$ exporters: [otlphttp, debug]$
$ metrics/tasks:$ receivers: [awsecscontainermetrics]$ processors: [$ metricstransform/base,$ metricstransform/task_metrics,$ filter/task_metrics,$ transform/task_identifier,$ resource/task,$ batch$ ]$ exporters: [otlphttp, debug]$
$ metrics/containers:$ receivers: [awsecscontainermetrics]$ processors: [$ metricstransform/base,$ filter/container_metrics,$ resource/task,$ batch$ ]$ exporters: [otlphttp, debug]$EOF$)"設定パラメーター
OpenTelemetry Collectorの設定では、以下のパラメーターをカスタマイズできます:
パラメータ | 説明 |
|---|---|
| ECSコンテナメトリクスエンドポイントからメトリクスを収集する間隔(秒単位)。 |
| MiB単位のOpenTelemetry Collectorのメモリ制限 |
| New Relicに送信する前にバッチ処理するメトリクスの数 |
| バッチを送信するまでの最大待ち時間 |
| リソース検出プロセッサのタイムアウト |
タスク定義を作成
Create a new ECS task definition for Fargate that includes the collector sidecar container. Choose between NRDOT Collector (New Relic's distribution) or OpenTelemetry Collector, then select the task definition for your container platform:
ヒント
NRDOT Collector is New Relic's distribution of the OpenTelemetry Collector with New Relic support for assistance. It bundles the awsecscontainermetrics receiver used by this configuration, so it runs with the same collector config you stored in the previous step.
重要
NRDOT Collector publishes Linux container images only. To monitor Windows containers, use the OpenTelemetry Collector tab.
{ "family": "otel-ecs-fargate-metrics", "networkMode": "awsvpc", "requiresCompatibilities": ["FARGATE"], "cpu": "<TASK_CPU>", "memory": "<TASK_MEMORY>", "executionRoleArn": "arn:aws:iam::YOUR_ACCOUNT:role/NewRelicECSTaskExecutionRole", "runtimePlatform": { "cpuArchitecture": "X86_64", "operatingSystemFamily": "LINUX" }, "containerDefinitions": [ { "name": "busybox", "image": "busybox:latest", "cpu": <APP_CPU>, "memory": <APP_MEMORY>, "essential": true, "command": [ "sh", "-c", "while true; do echo 'Hello from BusyBox'; sleep 30; done" ], "portMappings": [ { "containerPort": 80, "hostPort": 80, "protocol": "tcp" } ], "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-group": "<APP_LOG_GROUP>", "awslogs-create-group": "true", "awslogs-region": "<AWS_REGION>", "awslogs-stream-prefix": "<APP_LOG_STREAM_PREFIX>" } } }, { "name": "otel-collector", "image": "newrelic/nrdot-collector:latest", "cpu": <COLLECTOR_CPU>, "memoryReservation": <COLLECTOR_MEMORY_RESERVATION>, "essential": true, "command": ["--config=env:OTEL_CONFIG"], "environment": [ { "name": "NRIA_IS_FORWARD_ONLY", "value": "true" }, { "name": "NRIA_PASSTHROUGH_ENVIRONMENT", "value": "ECS_CONTAINER_METADATA_URI,ECS_CONTAINER_METADATA_URI_V4,FARGATE" }, { "name": "FARGATE", "value": "true" }, { "name": "NRIA_OVERRIDE_HOST_ROOT", "value": "" } ], "secrets": [ { "name": "OTEL_CONFIG", "valueFrom": "arn:aws:ssm:us-east-1:YOUR_ACCOUNT:parameter/ecs/otel-collector/fargate-config" }, { "name": "NEW_RELIC_LICENSE_KEY", "valueFrom": "arn:aws:ssm:us-east-1:YOUR_ACCOUNT:parameter/newrelic-infra/ecs/license-key" } ], "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-group": "<COLLECTOR_LOG_GROUP>", "awslogs-create-group": "true", "awslogs-region": "<AWS_REGION>", "awslogs-stream-prefix": "<COLLECTOR_LOG_STREAM_PREFIX>" } } } ]}タスク定義パラメーター
ECS Fargateタスク定義では、以下のパラメーターをカスタマイズできます:
パラメータ | 説明 |
|---|---|
| Fargateタスクの合計CPUユニット |
| MiB単位のFargateタスクの合計メモリ |
| アプリケーションコンテナに割り当てられたCPUユニット |
| アプリケーションコンテナに割り当てられたメモリ(MiB単位) |
| OpenTelemetry Collectorに割り当てられたCPUユニット |
| MiB単位でのOpenTelemetry Collectorのメモリ予約 |
| アプリケーションコンテナのCloudWatchロググループ名 |
| OpenTelemetry Collector 用の CloudWatch ロググループ名 |
| CloudWatchログ用のAWSリージョン |
| アプリケーションコンテナのログストリームプレフィックス |
| OpenTelemetry Collector 用のログストリームプレフィックス |
ヒント
LinuxおよびWindows Fargateコンテナの主な違い:
- ランタイムプラットフォーム:Windowsでは明示的な指定が必要です
operatingSystemFamily: "WINDOWS_SERVER_2022_FULL" - イメージ:Windowsは特定のWindowsコンテナイメージを使用します
- エントリーポイント:Windowsコレクターは
C:\\otelcol-contrib.exeをエントリーポイントとして指定します - メモリ割り当て:柔軟なメモリ管理に
memoryReservationを使用します
重要
YOUR_ACCOUNTとリージョンの値を、実際のAWSアカウントIDとAWSリージョンに置き換えてください。
タスクをデプロイして実行する
タスク定義をECSクラスタにデプロイします:
タスク定義を登録します。
bash$aws ecs register-task-definition --cli-input-json file://task-definition.jsonサービスの作成:
bash$aws ecs create-service \>--cluster your-cluster-name \>--service-name otel-monitoring-service \>--task-definition otel-ecs-fargate-metrics:1 \>--desired-count 1 \>--launch-type FARGATE \>--network-configuration "awsvpcConfiguration={subnets=[subnet-12345,subnet-67890],securityGroups=[sg-abcdef],assignPublicIp=ENABLED}"
データ収集を確認する
データがNew Relicに取り込まれていることを確認します:
OpenTelemetry Collectorのステータスを確認する:コンテナのログを確認して、コレクターがエラーなしで実行され、New Relicに正常に接続されていることを確認します:
bash$aws logs get-log-events \>--log-group-name "/ecs/otel-collector-fargate" \>--log-stream-name "otel/otel-collector/TASK_ID"New Relic UIでデータを確認する:one.newrelic.com > All Capabilities > Infrastructureに移動して、ECSコンテナがメトリクスとともに表示されることを確認します。データの探索に関する詳細なガイダンスについては、ECS監視データを検索してクエリを実行するを参照してください。
EC2との設定の違い
Fargateで実行する場合の主な違い:
- ホストレベルのアクセスなし: EC2のように基盤となるホストのメトリクスにアクセスできません
- ネットワークモード:
awsvpcネットワークモードを使用する必要があります - リソース制約: FargateのCPU/メモリの組み合わせによる制限
- ストレージ: エフェメラルストレージのみ、永続ボリュームなし
- コンテナインサイト: コンテナの統計情報にはタスクメタデータエンドポイント v4 に依存します
次のステップ
監視を設定した後、次のことができます:
- Fargateメトリクスに対してカスタムダッシュボードを作成します
- コンテナおよびタスクレベルの問題に対するアラートの設定
- ECSメトリクスをアプリケーショントレースおよびログと関連付ける