---
title: "Application Signalsの導入手順｜ECS・EKS・EC2・Lambda別の有効化設定と表示されないときの確認"
url: "https://www.issoh.co.jp/tech/details/7452/"
published: 2025-06-26
updated: 2026-10-02
categories: ["AWS"]
publisher: "株式会社一創"
---

# Application Signalsの導入手順｜ECS・EKS・EC2・Lambda別の有効化設定と表示されないときの確認

Application Signalsは、CloudWatchに組み込まれたAWSのAPM（アプリケーション性能監視）機能です。AWS Distro for OpenTelemetry（ADOT）の自動計装でアプリケーションのリクエストを拾い、サービスごとのレイテンシー・障害・エラーとサービス間の依存関係をCloudWatchに表示します。コードを書き換える必要はありませんが、**どこまで自動でやってくれるかは実行基盤で大きく違います**。EKSならアドオン1つでほぼ終わる一方、ECSとEC2ではCloudWatchエージェントとADOTを自分で組み込み、サービス名も自分で指定します。

この記事では、ECS・EKS・EC2・Lambdaそれぞれの有効化手順を、タスク定義・Pod注釈・エージェント設定の実際の記述で示し、最後にデータが表示されないときの確認順をまとめます。設定値はAWS公式ドキュメント「[Enable your applications on Amazon ECS](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Application-Signals-Enable-ECSMain.html)」ほか各プラットフォームの有効化ページ（2026年10月時点）に基づきます。料金の試算とSLOの設計は[CloudWatch Application Signalsの料金・SLO設計の解説](/tech/details/3413/)で扱っています。

## まとめ｜Application Signalsを有効化するための要点

- ECS・EKS・EC2・Kubernetesでは、アカウントでの初回有効化（サービスリンクロールの作成）、CloudWatchエージェントの`application_signals`設定、ADOTによる計装の3段階が要る。Lambdaはエージェントを使わず、レイヤーが計装を担う。
- EKSはCloudWatch Observabilityアドオンを入れて、Podか名前空間に注釈を付ければ計装まで終わる。v5.0.0以降のアドオンは既定で自動監視が有効になるため、既存のOpenTelemetry計装があるクラスターでは先に設定を確認する。
- ECSはサイドカー方式かデーモン方式を選ぶ。Fargateならサイドカー方式しか選べない。サービス名は`OTEL_RESOURCE_ATTRIBUTES`の`service.name`で自分で付け、付け忘れると`UnknownService`と表示される。
- EC2とオンプレミスは、2023年11月30日以降に公開されたCloudWatchエージェントとADOTエージェントを手で入れる。オンプレミスはIAMユーザーのアクセスキーで認証する。
- Lambdaはコンソールのチェックボックス1つで有効化できる。データが出ないときは、最後の変更から15分待ってから、検出の有効化・エージェントの稼働・権限・計装の順に確認する。

## Application Signalsの導入に共通する3段階と基盤ごとの違い

ECS・EKS・EC2・Kubernetesでは、手順の見た目は違っても中身は次の3段階に分かれます。EKSのアドオンは、このうち2と3をまとめて肩代わりしているだけです。Lambdaは例外で、1のあとはCloudWatchエージェントを置かず、ADOTを含むLambdaレイヤーが計装と送信を担います。

1. **アカウントでの初回有効化**：リージョンごとに1回。サービスリンクロール`AWSServiceRoleForCloudWatchApplicationSignals`が作られ、X-Rayのサービスグラフ、CloudWatch Logsのクエリ、CloudWatchメトリクスの読み取りなどの権限がApplication Signalsに渡る。
2. **CloudWatchエージェントの設定**：アプリケーションからOTLPでメトリクスとトレースを受ける窓口。ポート4316で受け、2000番はX-Rayのサンプリング設定の取得に使う。
3. **ADOTによる計装**：言語ごとのADOTエージェントをアプリケーションに読み込ませ、環境変数で送信先とサービス名を指定する。

1はコンソールの「Application Signals」→「サービス」→「サービスの検出を開始」でも実行できますが、CLIなら次の1行です。CloudFormationでは`AWS::ApplicationSignals::Discovery`リソースが同じ役割を持ちます。

```
aws application-signals start-discovery --region ap-northeast-1
```

2のエージェント設定は、ECS・EC2・Kubernetesのいずれでも次のJSONが最小構成です。`traces`と`logs`の両方に`application_signals`を書くのがポイントで、片方だけだとトレースかメトリクスのどちらかが欠けます。

```
{
  "traces": {
    "traces_collected": {
      "application_signals": {}
    }
  },
  "logs": {
    "metrics_collected": {
      "application_signals": {}
    }
  }
}
```

基盤ごとの違いは次の表のとおりです。**サービス名を自動で拾ってくれるのはEKS（アドオン経由）とLambdaだけ**で、ECS・EC2・EKS以外のKubernetesはカスタムセットアップ扱いになり、指定した名前がそのままダッシュボードに出ます。

| 基盤               | エージェントの置き方        | 計装の入れ方        | サービス名 |
| ---------------- | ----------------- | ------------- | ----- |
| EKS              | アドオンがDaemonSetで配置 | Pod・名前空間の注釈   | 自動    |
| ECS（Fargate）     | タスクごとのサイドカー       | initコンテナ＋環境変数 | 手動指定  |
| ECS（EC2起動タイプ）    | サイドカーかデーモン        | initコンテナ＋環境変数 | 手動指定  |
| EC2・オンプレミス       | ホストにインストール        | 起動コマンド＋環境変数   | 手動指定  |
| EKS以外のKubernetes | Helmチャート          | Pod・名前空間の注釈   | 手動指定  |
| Lambda           | 不要                | Lambdaレイヤー    | 関数名   |

計装できる言語は、AWSのサポート表でJava（JVM 8・11・17・21・23・25）、Python（3.10〜3.14）、Node.js（18・20・22・24）、.NET（8・9・10と.NET Framework 4.6.2以降）です。Go・PHP・RubyはADOTの自動計装が無く、標準のOpenTelemetry SDKで送る構成になります。この場合の課金上の注意は[Application Signalsの料金・対応言語の解説](/tech/details/3413/)を参照してください。

## ECSでの有効化｜サイドカー方式とデーモン方式

ECSでは、CloudWatchエージェントをどこで動かすかで2つの方式があります。どちらもADOTの計装はアプリケーションのタスク定義側に書くので、違うのはエージェントの置き場所と、アプリケーションから見た送信先アドレスです。

### サイドカーとデーモンを分ける判断基準

| 観点          | サイドカー方式     | デーモン方式              |
| ----------- | ----------- | ------------------- |
| Fargate     | 対応          | 非対応                 |
| EC2起動タイプ    | 対応          | 対応                  |
| ネットワークモード   | awsvpcのみ    | host・bridge・awsvpc  |
| エージェントの設定回数 | タスク定義ごと     | クラスターで1回            |
| 送信先アドレス     | 常にlocalhost | hostモード以外はインスタンスのIP |

Fargateならサイドカー方式一択です。EC2起動タイプでも、awsvpcのタスクならサイドカー方式を勧めます。bridgeのタスクはサイドカー方式に対応していないため、awsvpcへ移すか、デーモン方式を選ぶかのどちらかになります。デーモン方式はエージェントが1か所で済む代わりに、bridgeとawsvpcではアプリケーションの環境変数にコンテナインスタンスのプライベートIPを書く必要があり、インスタンスが入れ替わるたびに値が変わる問題を自分で解決しなければなりません。デーモン方式が素直に使えるのは、アプリケーションもhostネットワークモードで動かしている場合です。

### サイドカー方式のタスク定義（Javaの例）

まず、エージェント設定のJSONをSSMパラメータストアに置きます。タスク定義からは`secrets`の`valueFrom`で読み込むため、タスク実行ロールにパラメータの読み取り権限（`ssm:GetParameters`）が必要です。タスクロールには、アプリケーション自身の権限に加えて`CloudWatchAgentServerPolicy`を付けます。

```
aws ssm put-parameter \
  --name "ecs-cwagent" \
  --type "String" \
  --value "`cat /tmp/ecs-cwagent.json`" \
  --region ap-northeast-1
```

タスク定義には、共有ボリューム、エージェントのサイドカー、ADOTのjarをコピーする`init`コンテナ、アプリケーションの環境変数の4つを足します。公式手順をJavaアプリケーション1つの形にまとめると次のとおりです。イメージのタグは、ECR Publicの[cloudwatch-agent](https://gallery.ecr.aws/cloudwatch-agent/cloudwatch-agent)と[adot-autoinstrumentation-java](https://gallery.ecr.aws/aws-observability/adot-autoinstrumentation-java)で最新を確認して固定してください（2026年10月2日時点のGitHubリリースはADOT Java v2.31.0、CloudWatchエージェント1.300073.0）。

```
{
  "family": "orders-api",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "volumes": [{ "name": "opentelemetry-auto-instrumentation" }],
  "containerDefinitions": [
    {
      "name": "init",
      "image": "public.ecr.aws/aws-observability/adot-autoinstrumentation-java:v2.31.0",
      "essential": false,
      "command": ["cp", "/javaagent.jar", "/otel-auto-instrumentation/javaagent.jar"],
      "mountPoints": [{
        "sourceVolume": "opentelemetry-auto-instrumentation",
        "containerPath": "/otel-auto-instrumentation",
        "readOnly": false
      }]
    },
    {
      "name": "ecs-cwagent",
      "image": "public.ecr.aws/cloudwatch-agent/cloudwatch-agent:latest",
      "essential": false,
      "secrets": [{ "name": "CW_CONFIG_CONTENT", "valueFrom": "ecs-cwagent" }]
    },
    {
      "name": "app",
      "image": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/orders-api:1.4.0",
      "dependsOn": [{ "containerName": "init", "condition": "SUCCESS" }],
      "mountPoints": [{
        "sourceVolume": "opentelemetry-auto-instrumentation",
        "containerPath": "/otel-auto-instrumentation",
        "readOnly": false
      }],
      "environment": [
        { "name": "OTEL_RESOURCE_ATTRIBUTES", "value": "service.name=orders-api,deployment.environment=prod" },
        { "name": "OTEL_AWS_APPLICATION_SIGNALS_ENABLED", "value": "true" },
        { "name": "OTEL_METRICS_EXPORTER", "value": "none" },
        { "name": "OTEL_LOGS_EXPORTER", "value": "none" },
        { "name": "OTEL_EXPORTER_OTLP_PROTOCOL", "value": "http/protobuf" },
        { "name": "OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT", "value": "http://localhost:4316/v1/metrics" },
        { "name": "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", "value": "http://localhost:4316/v1/traces" },
        { "name": "OTEL_TRACES_SAMPLER", "value": "xray" },
        { "name": "OTEL_PROPAGATORS", "value": "tracecontext,baggage,b3,xray" },
        { "name": "JAVA_TOOL_OPTIONS", "value": " -javaagent:/otel-auto-instrumentation/javaagent.jar" }
      ]
    }
  ]
}
```

見落としやすいのは2点です。`dependsOn`の`SUCCESS`条件が無いと、jarのコピーが終わる前にアプリケーションが起動して`-javaagent`の読み込みに失敗します。`deployment.environment`を省くとECSクラスター名が環境名として使われるので、同じクラスターにステージングと本番を同居させているなら明示してください。実際のタスク定義では、ここで省いた`cpu`・`memory`・`executionRoleArn`・`taskRoleArn`・ログ設定も必要です。

### Python・Node.js・.NETで変わる設定

言語が変わると、initコンテナのイメージとコピー元、アプリケーションにADOTを読み込ませる環境変数が変わります。送信先の4316番と`OTEL_AWS_APPLICATION_SIGNALS_ENABLED=true`は共通です。

| 言語      | initのイメージ                       | コピー元                   | 読み込ませる環境変数             |
| ------- | ------------------------------- | ---------------------- | ---------------------- |
| Java    | adot-autoinstrumentation-java   | /javaagent.jar         | JAVA\_TOOL\_OPTIONS    |
| Python  | adot-autoinstrumentation-python | /autoinstrumentation/. | PYTHONPATH             |
| Node.js | adot-autoinstrumentation-node   | /autoinstrumentation/. | NODE\_OPTIONS          |
| .NET    | adot-autoinstrumentation-dotnet | autoinstrumentation/.  | CORECLR\_\*・DOTNET\_\* |

Pythonは追加の変数が多く、`OTEL_PYTHON_DISTRO=aws_distro`と`OTEL_PYTHON_CONFIGURATOR=aws_configurator`でADOTの設定を使わせ、`PYTHONPATH`にはADOTの自動計装ディレクトリとアプリケーションの作業ディレクトリの両方を並べます。作業ディレクトリを入れ忘れると、計装以前にアプリケーションが起動しないことがあり、公式のトラブルシューティングにも既知の問題として載っています。Djangoは`--noreload`と`DJANGO_SETTINGS_MODULE`も必要です。

```
PYTHONPATH=/otel-auto-instrumentation-python/opentelemetry/instrumentation/auto_instrumentation:/app:/otel-auto-instrumentation-python
OTEL_PYTHON_DISTRO=aws_distro
OTEL_PYTHON_CONFIGURATOR=aws_configurator
OTEL_TRACES_SAMPLER=xray
OTEL_TRACES_SAMPLER_ARG=endpoint=http://localhost:2000
```

Node.jsは`NODE_OPTIONS=--require /otel-auto-instrumentation-node/autoinstrumentation.js`で読み込みます。この方法はCommonJS前提で、ESM形式のアプリケーションは別手順になります（後述のEKSの節と同じ制約）。.NETはプロファイラーの仕組みを使うため、`CORECLR_ENABLE_PROFILING=1`、`CORECLR_PROFILER`（CLSID）、`CORECLR_PROFILER_PATH`、`DOTNET_STARTUP_HOOKS`などを公式手順どおりに並べます。プロファイラーのパスはLinuxなら`linux-x64/OpenTelemetry.AutoInstrumentation.Native.so`、Windows Serverなら`win-x64/OpenTelemetry.AutoInstrumentation.Native.dll`で、Windowsコンテナではinitのコマンドも変わります。

### デーモン方式でエンドポイントを書き換える箇所

デーモン方式では、エージェント用のタスク定義（公式例のファミリー名は`ecs-cwagent-daemon`、bridgeモード）を作り、ECSサービスのスケジューリング戦略をDAEMONにしてクラスターに1回だけ配置します。エージェントはホストの4316番と2000番を使うため、同じホストでこの2つのポートを使う別サービスがあると衝突します。

アプリケーション側の変更は送信先だけです。hostモードならサイドカー方式と同じ`localhost`のまま動きます。bridgeかawsvpcの場合は、次の3つの変数の`localhost`を、インスタンスメタデータサービス（IMDS）から取ったコンテナインスタンスのプライベートIPに置き換えます。

```
OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT=http://10.0.12.34:4316/v1/metrics
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://10.0.12.34:4316/v1/traces
OTEL_TRACES_SAMPLER_ARG=endpoint=http://10.0.12.34:2000
```

タスク定義の環境変数は静的な値なので、インスタンスごとに違うIPを入れるにはエントリポイントでIMDSを引いて書き換えるなどの工夫が要ります。この手間を許容できないなら、サイドカー方式を選ぶ方が運用は単純です。

## EKSでの有効化｜CloudWatch Observabilityアドオンと注釈

EKSでは、Amazon CloudWatch Observability EKSアドオンがCloudWatchエージェントとADOTの注入の仕組みをまとめて入れます。このアドオンはContainer Insights（拡張オブザーバビリティ）も同時に有効にします。アプリケーション側で書くのは注釈だけです。

### アドオンの導入とIAM権限

CloudWatchコンソールの「Application Signals」で「EKS」を選び、対象クラスターを指定すると、アドオンが無ければEKSコンソールでの追加に誘導されます。IAMロールに「ノードから継承」を選んだ場合は、ワーカーノードのロールに次の2つのポリシーを付けます。

```
aws iam attach-role-policy --role-name my-worker-node-role \
  --policy-arn arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy
aws iam attach-role-policy --role-name my-worker-node-role \
  --policy-arn arn:aws:iam::aws:policy/AWSXRayWriteOnlyAccess
```

ノードロールに権限を付けると、PodからIMDSへのアクセスを制限していない限り、そのノードで動くPodが同じ権限を使えてしまいます。アドオンv3.1.0以降では、公式がEKS Pod Identityを推奨しており、`cloudwatch-agent`サービスアカウントだけに`CloudWatchAgentServerPolicy`付きのロールを関連付けられます（IRSAも利用可）。なお、WindowsノードではContainer Insightsは動きますが、Application Signalsは対応していません。

### Pod注釈と名前空間注釈の書き方

計装は、Deploymentの`PodTemplate`か、名前空間のメタデータに注釈を付けて有効にします。注釈名は言語ごとに分かれています。

```
# 抜粋（selector・replicas などは省略）
apiVersion: apps/v1
kind: Deployment
metadata:
  name: orders-api
spec:
  template:
    metadata:
      annotations:
        instrumentation.opentelemetry.io/inject-java: "true"
        # Python: inject-python / Node.js: inject-nodejs / .NET: inject-dotnet
    spec:
      containers:
        - name: orders-api
          image: 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/orders-api:1.4.0
```

名前空間に付けると、その名前空間の既存と今後のワークロードがすべて対象になります。注釈は次にPodが作られるときに効くので、適用後は`kubectl rollout restart deployment -n <名前空間>`で再起動します。コンソールの「Console」方式でワークロードを選んだ場合は即座にPodが再起動されるため、本番クラスターでは注釈方式で再起動のタイミングを自分で決める方が安全です。.NETをAlpine Linuxベースのイメージで動かすときは、注釈`instrumentation.opentelemetry.io/otel-dotnet-auto-runtime: "linux-musl-x64"`を足します。

### アドオンv5.0.0以降の自動監視と無効化の設定

アドオン（とHelmチャート）のv5.0.0から、OpenTelemetryベースのAPMがApplication Signals経由で既定で有効になりました。設定の`manager.applicationSignals.autoMonitor`にある`monitorAllServices`の既定値は`true`で、Kubernetes Serviceに紐づくDeployment・DaemonSet・StatefulSetが、新規作成時か次の再起動時に自動で計装されます。`kube-system`と`amazon-cloudwatch`の名前空間は既定で除外されます。

注意したいのは、**既にDatadogやNew Relic、自前のOpenTelemetry Collectorで計装しているクラスターでアドオンを更新すると、次の再起動でADOTが注入される**点です。公式ドキュメントも、OpenTelemetryベースのAPMを使っている場合は既存の構成に影響すると明記しています。さらに、アプリケーションのコード内に直書きしたOTLPの送信先はアドオンに上書きされることがあり、メトリクスとトレースが本来の送信先に届かなくなります（コンテナの環境変数や`envFrom`のConfigMapで指定した送信先は上書きされません）。アドオンを更新する前に、詳細設定で次のように無効化しておきます。

```
{
  "manager": {
    "applicationSignals": {
      "autoMonitor": {
        "monitorAllServices": false
      }
    }
  }
}
```

逆に対象を絞って自動化したい場合は、言語と名前空間を指定します。次は`pet-warehouse`名前空間のJavaワークロードだけを自動計装し、設定保存時にPodを再起動する例です（`restartPods`の既定は`false`）。`monitorAllServices`は既定で`true`なので、明示的に`false`にしないと他のサービスも対象に残ります。除外したいワークロードは`exclude`に`名前空間/Deployment名`の形式で書き、除外は対象指定より優先されます。

```
manager:
  applicationSignals:
    autoMonitor:
      monitorAllServices: false
      restartPods: true
      customSelector:
        java:
          namespaces: ["pet-warehouse"]
```

2026年10月2日時点のHelmチャートの最新はamazon-cloudwatch-observability 6.7.0（2026年9月21日公開）です。

### Node.jsのESMアプリケーションの手動計装

ESM形式のNode.jsアプリケーションは、コンソールでの有効化も注釈も効きません。`@aws/aws-distro-opentelemetry-node-autoinstrumentation`を依存関係に入れ、DockerfileでApplication Signals用の環境変数を設定してイメージを作り直します。このときinject-nodejsの注釈は付けたままにしないよう、公式手順でも注意されています。送信先はクラスター内のエージェントのサービス名`cloudwatch-agent.amazon-cloudwatch:4316`です。

### EKS以外のKubernetesへのHelm導入

EKS以外のKubernetes（EC2上の自前クラスターやオンプレミス）では、アドオンの代わりにHelmチャートでエージェントのオペレーターを入れ、その後は注釈で計装します。`clusterName`に指定した名前がダッシュボードに表示されます。オンプレミスの場合は、`CloudWatchAgentServerPolicy`を付けたIAMユーザーのアクセスキーをクラスターに渡す手順が加わります。

```
helm repo add aws-observability https://aws-observability.github.io/helm-charts
helm install amazon-cloudwatch-operator aws-observability/amazon-cloudwatch-observability \
  --namespace amazon-cloudwatch --create-namespace \
  --set region=ap-northeast-1 \
  --set clusterName=onprem-k8s-01
```

## EC2・オンプレミスでの有効化｜CloudWatchエージェントとADOTの手動導入

EC2とオンプレミスのサーバーでは、CloudWatchエージェントをホストに入れ、アプリケーションの起動コマンドにADOTを組み込みます。Application Signalsに対応するのは2023年11月30日以降に公開されたエージェントなので、古いエージェントが入っているホストは更新が先です。

エージェントの設定は前述の最小構成のJSONを`/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json`に置き、インスタンスのIAMロールに`CloudWatchAgentServerPolicy`を付けてから起動します。`-c`の値には`file:`の接頭辞が必須です。

```
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \
  -a fetch-config -m ec2 -s \
  -c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json
```

Javaは[ADOT Javaのリリース](https://github.com/aws-observability/aws-otel-java-instrumentation/releases)から`aws-opentelemetry-agent.jar`を取得し、環境変数を付けて起動します。

```
JAVA_TOOL_OPTIONS=" -javaagent:/opt/adot/aws-opentelemetry-agent.jar" \
OTEL_METRICS_EXPORTER=none \
OTEL_LOGS_EXPORTER=none \
OTEL_AWS_APPLICATION_SIGNALS_ENABLED=true \
OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT=http://localhost:4316/v1/metrics \
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf \
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://localhost:4316/v1/traces \
OTEL_RESOURCE_ATTRIBUTES="service.name=billing-batch,deployment.environment=prod" \
java -jar billing-batch.jar
```

Pythonは`pip install aws-opentelemetry-distro`（2026年10月2日時点のPyPI最新は0.20.0、Python 3.10以上）で入れ、`opentelemetry-instrument python app.py`の形で起動します。環境変数はECSのPythonと同じく`OTEL_PYTHON_DISTRO`と`OTEL_PYTHON_CONFIGURATOR`が要ります。

オンプレミスのサーバーにはインスタンスロールが無いため、`CloudWatchAgentServerPolicy`を付けたIAMユーザーを作り、そのアクセスキーを`aws configure`でホストに設定します。長期のアクセスキーを置くことになるので、キーのローテーションと権限をこのポリシーだけに絞る運用を前提にしてください。

## Lambdaでの有効化｜コンソール設定と手動・IaCで必要な3項目

Lambdaはエージェントを置かず、ADOTを含むAWS Lambda Layer for OpenTelemetryが計装を担います。Lambdaコンソールなら、関数の「設定」→「モニタリングおよび運用ツール」→「編集」で、Application Signalsによるトレースと標準メトリクスの自動収集にチェックを入れて保存するだけです。CloudWatchコンソールの「Application Signals」から「Lambda」を選び、複数の関数をまとめて有効にすることもできます。

手動やIaCで設定する場合は、レイヤーの追加、環境変数`AWS_LAMBDA_EXEC_WRAPPER=/opt/otel-instrument`、実行ロールへの`CloudWatchLambdaApplicationSignalsExecutionRolePolicy`の付与の3点です。既定の計装範囲を広げる環境変数や、コンテナイメージでデプロイした関数にレイヤーの中身を取り込む手順は、[Application SignalsのLambda最小構成の解説](/tech/details/3413/)に載せています。

## CDKで有効化するときの注意｜ECS用の構成はexperimental

アカウントでの初回有効化は、安定版の`aws-cdk-lib`に含まれるL1リソース`CfnDiscovery`で書けます。

```
import { aws_applicationsignals as applicationsignals } from 'aws-cdk-lib';

new applicationsignals.CfnDiscovery(this, 'ApplicationSignalsDiscovery', {});
```

ECSのタスク定義にサイドカーとinitコンテナを組み込む作業は、別パッケージ`@aws-cdk/aws-applicationsignals-alpha`の`ApplicationSignalsIntegration`がまとめて引き受けます。ただし、このパッケージはREADMEで「experimental」と明示され、将来の版で後方互換の無い変更や削除がありうるとされています（2026年10月2日時点の最新は2.272.0-alpha.0）。

もう一つの落とし穴が、ADOTの版を指定する列挙です。ソースに定義されている版はJavaが`V2_10_0`、Pythonが`V0_9_0`、Node.jsが`V0_6_0`、.NETが`V1_7_0`までで、ADOTの現行版（Java v2.31.0、Python v0.20.0）からかなり遅れています。列挙をそのまま使うと古い計装エージェントで動かすことになります。コンストラクタは公開されているので、版を直接指定できます。指定する版はADOTのリリースノートで変更点を確認してから固定してください。

```
import * as appsignals from '@aws-cdk/aws-applicationsignals-alpha';

new appsignals.ApplicationSignalsIntegration(this, 'AppSignals', {
  taskDefinition: fargateTaskDefinition,
  serviceName: 'orders-api',
  instrumentation: {
    sdkVersion: new appsignals.JavaInstrumentationVersion(
      appsignals.JavaInstrumentationVersion.IMAGE_REPO,
      'v2.31.0',
      appsignals.JavaInstrumentationVersion.DEFAULT_MEMORY_LIMIT_MIB,
    ),
  },
  cloudWatchAgentSidecar: {
    containerName: 'cloudwatch-agent',
    enableLogging: true,
    cpu: 256,
    memoryLimitMiB: 512,
  },
});
```

experimentalのパッケージをCDKのバージョン更新のたびに追いかける体制が無いなら、本番ではタスク定義をL1や素のJSONで書き、前述の4要素を自分で管理する方を選びます。

## データが表示されないときの確認順

有効化してもダッシュボードにサービスが出ない場合、公式のトラブルシューティングは**最後の変更から15分待ってから**調べるよう求めています。それを過ぎても出ないときは、外側から順に次を確認します。

### 15分待っても何も出ないときの確認項目

1. **検出の有効化**：CloudWatchコンソールの「Application Signals」→「サービス」で、手順1が「完了」になっているか。未完了なら「サービスの検出を開始」を実行すると、5分ほどでデータが流れ始める。リージョンごとに必要。
2. **エージェントの稼働**：EKSなら`kubectl -n amazon-cloudwatch get pods`で全Podが`Running`か。エージェント設定の`agent`に`"debug": true`を足して再起動し、エラーを探す。
3. **権限**：エージェントのログに`Access Denied`があれば、導入後にロールのポリシーが外されていないか確認する。
4. **計装の注入**：EKSでは注釈の値が`"true"`か、`init`コンテナが`Ready`になっているか。ECSではinitコンテナが`SUCCESS`で終了しているか。
5. **送信の失敗**：アプリケーションのログに`Failed to export`が出ていないか。Javaは`OTEL_JAVAAGENT_DEBUG=true`、Pythonは`OTEL_PYTHON_LOG_LEVEL=debug`で詳細ログを出せる。エージェント側のスロットリングのログも確認する。

### UnknownServiceやUnknownRemoteServiceの表示原因

サービス一覧に`UnknownService`が出るのは、`OTEL_SERVICE_NAME`も`OTEL_RESOURCE_ATTRIBUTES`の`service.name`も設定されていないときです。ECSとEC2はサービス名を自動で拾わないので、まずここを疑います。`UnknownOperation`はリモート呼び出しを起こした操作名が特定できないか、操作名にIDなど値の種類が多すぎる文字列が含まれる場合に出ます。依存先が`UnknownRemoteService`になるのは、計装ライブラリが呼び出し先の種類を判別できない場合で、デプロイの時刻と重なっていないかも確認します。

### Gunicorn・uWSGI・Uvicornのワーカーからの未送信

プリフォーク型のサーバーでは、親プロセスで初期化したOpenTelemetry SDKのバックグラウンドスレッドがフォーク後のワーカーに引き継がれず、ワーカーからデータが送られません。対処は2段階で、ワーカー側で計装を初期化したうえで、環境変数`OTEL_AWS_PYTHON_DEFER_TO_WORKERS_ENABLED=true`で親プロセスの初期化を飛ばします。Gunicornなら設定ファイルの`post_fork`フックで初期化します。

```
# gunicorn.conf.py
def post_fork(server, worker):
    from opentelemetry.instrumentation.auto_instrumentation import sitecustomize
```

uWSGIは`enable-threads = true`と`lazy-apps = true`と`import = opentelemetry.instrumentation.auto_instrumentation.sitecustomize`、複数ワーカーのUvicornはアプリケーションをimportする前に`initialize()`を呼びます。この対処にはADOT PythonとEKSアドオンの最新版が前提です。

## よくある質問

### Application Signalsとは何ですか？

CloudWatchのAPM機能です。ADOTでアプリケーションを自動計装し、サービスごとのレイテンシー・障害・エラーの指標、サービス間の依存関係、SLOをCloudWatch上で扱えます。料金とSLOの設計は[CloudWatch Application Signalsの解説](/tech/details/3413/)で詳しく説明しています。

### ECSのFargateでもApplication Signalsは使えますか？

使えます。ただしサイドカー方式に限られ、ネットワークモードはawsvpcです。デーモン方式はFargateに対応していません。

### Lambdaでは何を設定すればApplication Signalsが有効になりますか？

Lambdaコンソールの「モニタリングおよび運用ツール」でApplication Signalsの自動収集にチェックを入れれば有効になります。手動ならレイヤーの追加、`AWS_LAMBDA_EXEC_WRAPPER=/opt/otel-instrument`、実行ロールへの`CloudWatchLambdaApplicationSignalsExecutionRolePolicy`の付与の3点です。

### EKSで既存のOpenTelemetry計装と共存できますか？

アドオンv5.0.0以降は自動監視が既定で有効なため、そのまま更新すると次の再起動でADOTが注入されます。既存の計装を残したいワークロードは、`autoMonitor`の`monitorAllServices`を`false`にするか、`exclude`で外してから更新してください。

### Application SignalsでGoやRubyのアプリケーションは計装できますか？

ADOTの自動計装はJava・Python・Node.js・.NETの4言語です。Go・PHP・Rubyは標準のOpenTelemetry SDKで計装し、Transaction Searchを有効にしてトレースを送る構成になります。

## 関連記事

- [Amazon CloudWatch Application Signalsとは｜料金・SLO設計・対応言語を実装目線で解説【2026年版】](/tech/details/3413/)
- [AWSオブザーバビリティの実装｜ADOT・CloudWatch・Container Insightsで計装する構成【2026年時点】](/tech/details/15297/)
- [AWS X-Rayとは｜CloudWatchとの違いとOpenTelemetry移行後の使い方【2026年版】](/tech/details/6812/)
- [Amazon EKSとは？仕組み・ノード提供形態と料金モデル・ECSとの使い分けを実装者目線で解説](/tech/details/15437/)
- [APM（アプリケーション性能監視）とは｜仕組み・3種の監視データ・OpenTelemetry計装と導入判断を実装目線で解説](/tech/details/15414/)

---

出典: [Application Signalsの導入手順｜ECS・EKS・EC2・Lambda別の有効化設定と表示されないときの確認](<https://www.issoh.co.jp/tech/details/7452/>)（株式会社一創）
