AWS CDK を使用して Amazon ECS で Application Signals を有効にする
AWS CDK を使用して Amazon ECS で Application Signals を有効にするには、次の手順を実行します。
アプリケーション向けに Application Signals を有効にする – このアカウントで Application Signals をまだ有効にしていない場合は、サービスの検出に必要なアクセス権限を Application Signals に付与する必要があります。
import { aws_applicationsignals as applicationsignals } from 'aws-cdk-lib'; const cfnDiscovery = new applicationsignals.CfnDiscovery(this, 'ApplicationSignalsServiceRole', { } );
Discovery CloudFormation リソースは、Application Signals に次のアクセス許可を付与します。
-
xray:GetServiceGraph
-
logs:StartQuery
-
logs:GetQueryResults
-
cloudwatch:GetMetricData
-
cloudwatch:ListMetrics
-
tag:GetResources
このロールの詳細については、「CloudWatch Application Signals のサービスリンクロールのアクセス許可」を参照してください。
-
AWS CDK の AWS::ApplicationSignals コンストラクトライブラリ
を使用してアプリケーションを計測します。このドキュメントのコードスニペットは TypeScript で提供されています。その他の言語固有の代替については、「AWS CDK のサポートされているプログラミング言語」を参照してください。 サイドカーモードを使用して Amazon ECS で Application Signals を有効にする
AWS Distro for OpenTelemetry (ADOT) SDK エージェントを使用してアプリケーションを計測するように
instrumentation
を設定します。Java アプリケーションの計測例を次に示します。サポートされているすべての言語バージョンについては、「InstrumentationVersion」を参照してください。cloudWatchAgentSidecar
を指定して、CloudWatch エージェントをサイドカーコンテナとして設定します。import { Construct } from 'constructs'; import * as appsignals from '@aws-cdk/aws-applicationsignals-alpha'; import * as cdk from 'aws-cdk-lib'; import * as ec2 from 'aws-cdk-lib/aws-ec2'; import * as ecs from 'aws-cdk-lib/aws-ecs'; class MyStack extends cdk.Stack { public constructor(scope?: Construct, id?: string, props: cdk.StackProps = {}) { super(); const vpc = new ec2.Vpc(this, 'TestVpc', {}); const cluster = new ecs.Cluster(this, 'TestCluster', { vpc }); const fargateTaskDefinition = new ecs.FargateTaskDefinition(this, 'SampleAppTaskDefinition', { cpu: 2048, memoryLimitMiB: 4096, }); fargateTaskDefinition.addContainer('app', { image: ecs.ContainerImage.fromRegistry('test/sample-app'), }); new appsignals.ApplicationSignalsIntegration(this, 'ApplicationSignalsIntegration', { taskDefinition: fargateTaskDefinition, instrumentation: { sdkVersion: appsignals.JavaInstrumentationVersion.V2_10_0, }, serviceName: 'sample-app', cloudWatchAgentSidecar: { containerName: 'ecs-cwagent', enableLogging: true, cpu: 256, memoryLimitMiB: 512, } }); new ecs.FargateService(this, 'MySampleApp', { cluster: cluster, taskDefinition: fargateTaskDefinition, desiredCount: 1, }); } }
デーモンモードを使用して Amazon ECS で Application Signals を有効にする
注記
デーモンデプロイ戦略は Amazon ECS Fargate ではサポートされておらず、Amazon ECS on Amazon EC2 でのみサポートされています。
HOST
ネットワークモードを使用して CloudWatch エージェントをデーモンサービスとして実行します。ADOT Python エージェントを使用してアプリケーションを計測するように
instrumentation
を設定します。import { Construct } from 'constructs'; import * as appsignals from '@aws-cdk/aws-applicationsignals-alpha'; import * as cdk from 'aws-cdk-lib'; import * as ec2 from 'aws-cdk-lib/aws-ec2'; import * as ecs from 'aws-cdk-lib/aws-ecs'; class MyStack extends cdk.Stack { public constructor(scope?: Construct, id?: string, props: cdk.StackProps = {}) { super(scope, id, props); const vpc = new ec2.Vpc(this, 'TestVpc', {}); const cluster = new ecs.Cluster(this, 'TestCluster', { vpc }); // Define Task Definition for CloudWatch agent (Daemon) const cwAgentTaskDefinition = new ecs.Ec2TaskDefinition(this, 'CloudWatchAgentTaskDefinition', { networkMode: ecs.NetworkMode.HOST, }); new appsignals.CloudWatchAgentIntegration(this, 'CloudWatchAgentIntegration', { taskDefinition: cwAgentTaskDefinition, containerName: 'ecs-cwagent', enableLogging: false, cpu: 128, memoryLimitMiB: 64, portMappings: [ { containerPort: 4316, hostPort: 4316, }, { containerPort: 2000, hostPort: 2000, }, ], }); // Create the CloudWatch Agent daemon service new ecs.Ec2Service(this, 'CloudWatchAgentDaemon', { cluster, taskDefinition: cwAgentTaskDefinition, daemon: true, // Runs one container per EC2 instance }); // Define Task Definition for user application const sampleAppTaskDefinition = new ecs.Ec2TaskDefinition(this, 'SampleAppTaskDefinition', { networkMode: ecs.NetworkMode.HOST, }); sampleAppTaskDefinition.addContainer('app', { image: ecs.ContainerImage.fromRegistry('test/sample-app'), cpu: 0, memoryLimitMiB: 512, }); // No CloudWatch Agent sidecar is needed as application container communicates to CloudWatch Agent daemon through host network new appsignals.ApplicationSignalsIntegration(this, 'ApplicationSignalsIntegration', { taskDefinition: sampleAppTaskDefinition, instrumentation: { sdkVersion: appsignals.PythonInstrumentationVersion.V0_8_0 }, serviceName: 'sample-app' }); new ecs.Ec2Service(this, 'MySampleApp', { cluster, taskDefinition: sampleAppTaskDefinition, desiredCount: 1, }); } }
レプリカモードを使用して Amazon ECS で Application Signals を有効にする
注記
レプリカモードを使用して CloudWatch エージェントサービスを実行するには、他のサービスとの通信を有効にするために、特定のセキュリティグループ設定が必要です。Application Signals 機能の場合、最小インバウンドルールであるポート 2000 (HTTP) とポート 4316 (HTTP) を指定してセキュリティグループを設定します。この設定により、CloudWatch エージェントと依存サービスとの適切な接続が保証されます。
Service Connect を使用して CloudWatch エージェントをレプリカサービスとして実行します。
ADOT Python エージェントを使用してアプリケーションを計測するように
instrumentation
を設定します。Service Connect エンドポイントを使用して CloudWatch エージェントサーバーと通信するように
overrideEnvironments
を設定して、環境変数を上書きします。import { Construct } from 'constructs'; import * as appsignals from '@aws-cdk/aws-applicationsignals-alpha'; import * as cdk from 'aws-cdk-lib'; import * as ec2 from 'aws-cdk-lib/aws-ec2'; import * as ecs from 'aws-cdk-lib/aws-ecs'; import { PrivateDnsNamespace } from 'aws-cdk-lib/aws-servicediscovery'; class MyStack extends cdk.Stack { public constructor(scope?: Construct, id?: string, props: cdk.StackProps = {}) { super(scope, id, props); const vpc = new ec2.Vpc(this, 'TestVpc', {}); const cluster = new ecs.Cluster(this, 'TestCluster', { vpc }); const dnsNamespace = new PrivateDnsNamespace(this, 'Namespace', { vpc, name: 'local', }); const securityGroup = new ec2.SecurityGroup(this, 'ECSSG', { vpc }); securityGroup.addIngressRule(securityGroup, ec2.Port.tcpRange(0, 65535)); // Define Task Definition for CloudWatch agent (Replica) const cwAgentTaskDefinition = new ecs.FargateTaskDefinition(this, 'CloudWatchAgentTaskDefinition', {}); new appsignals.CloudWatchAgentIntegration(this, 'CloudWatchAgentIntegration', { taskDefinition: cwAgentTaskDefinition, containerName: 'ecs-cwagent', enableLogging: false, cpu: 128, memoryLimitMiB: 64, portMappings: [ { name: 'cwagent-4316', containerPort: 4316, hostPort: 4316, }, { name: 'cwagent-2000', containerPort: 2000, hostPort: 2000, }, ], }); // Create the CloudWatch Agent replica service with service connect new ecs.FargateService(this, 'CloudWatchAgentService', { cluster: cluster, taskDefinition: cwAgentTaskDefinition, securityGroups: [securityGroup], serviceConnectConfiguration: { namespace: dnsNamespace.namespaceArn, services: [ { portMappingName: 'cwagent-4316', dnsName: 'cwagent-4316-http', port: 4316, }, { portMappingName: 'cwagent-2000', dnsName: 'cwagent-2000-http', port: 2000, }, ], }, desiredCount: 1, }); // Define Task Definition for user application const sampleAppTaskDefinition = new ecs.FargateTaskDefinition(this, 'SampleAppTaskDefinition', {}); sampleAppTaskDefinition.addContainer('app', { image: ecs.ContainerImage.fromRegistry('test/sample-app'), cpu: 0, memoryLimitMiB: 512, }); // Overwrite environment variables to connect to the CloudWatch Agent service just created new appsignals.ApplicationSignalsIntegration(this, 'ApplicationSignalsIntegration', { taskDefinition: sampleAppTaskDefinition, instrumentation: { sdkVersion: appsignals.PythonInstrumentationVersion.V0_8_0, }, serviceName: 'sample-app', overrideEnvironments: [ { name: appsignals.CommonExporting.OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT, value: 'http://cwagent-4316-http:4316/v1/metrics', }, { name: appsignals.TraceExporting.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, value: 'http://cwagent-4316-http:4316/v1/traces', }, { name: appsignals.TraceExporting.OTEL_TRACES_SAMPLER_ARG, value: 'endpoint=http://cwagent-2000-http:2000', }, ], }); // Create ECS Service with service connect configuration new ecs.FargateService(this, 'MySampleApp', { cluster: cluster, taskDefinition: sampleAppTaskDefinition, serviceConnectConfiguration: { namespace: dnsNamespace.namespaceArn, }, desiredCount: 1, }); } }
ESM モジュール形式を使用する Node.js アプリケーションをセットアップする ESM モジュール形式を使用する Node.js アプリケーションには限定的なサポートが提供されます。詳細については、「ESM を使用した Node.js に関する既知の制限事項」を参照してください。
ESM モジュール形式の場合、
init
コンテナを使用して Node.js インストルメンテーション SDK を挿入することで Application Signals を有効にすることはできません。この手順のステップ 2 をスキップし、代わりに次の手順を実行します。自動計測のために、関連する依存関係を Node.js アプリケーションにインストールします。
npm install @aws/aws-distro-opentelemetry-node-autoinstrumentation npm install @opentelemetry/instrumentation@0.54.
TaskDefinition を更新します。
アプリケーションコンテナに設定を追加します。
NODE_OPTIONS
を設定します。(オプション) サイドカーモードを選択した場合は、CloudWatch エージェントを追加します。
import { Construct } from 'constructs'; import * as appsignals from '@aws-cdk/aws-applicationsignals-alpha'; import * as ecs from 'aws-cdk-lib/aws-ecs'; class MyStack extends cdk.Stack { public constructor(scope?: Construct, id?: string, props: cdk.StackProps = {}) { super(scope, id, props); const fargateTaskDefinition = new ecs.FargateTaskDefinition(stack, 'TestTaskDefinition', { cpu: 256, memoryLimitMiB: 512, }); const appContainer = fargateTaskDefinition.addContainer('app', { image: ecs.ContainerImage.fromRegistry('docker/cdk-test'), }); const volumeName = 'opentelemetry-auto-instrumentation' fargateTaskDefinition.addVolume({name: volumeName}); // Inject additional configurations const injector = new appsignals.NodeInjector(volumeName, appsignals.NodeInstrumentationVersion.V0_5_0); injector.renderDefaultContainer(fargateTaskDefinition); // Configure NODE_OPTIONS appContainer.addEnvironment('NODE_OPTIONS', '--import @aws/aws-distro-opentelemetry-node-autoinstrumentation/register --experimental-loader=@opentelemetry/instrumentation/hook.mjs') // Optional: add CloudWatch agent const cwAgent = new appsignals.CloudWatchAgentIntegration(stack, 'AddCloudWatchAgent', { containerName: 'ecs-cwagent', taskDefinition: fargateTaskDefinition, memoryReservationMiB: 50, }); appContainer.addContainerDependencies({ container: cwAgent.agentContainer, condition: ecs.ContainerDependencyCondition.START, }); }
更新済みスタックをデプロイする – アプリケーションのメインディレクトリで
cdk synth
コマンドを実行します。AWS アカウントでサービスをデプロイするには、cdk deploy
コマンドをアプリケーションのメインディレクトリで実行します。サイドカー戦略を使用した場合、次の 1 つのサービスが作成されます。
APPLICATION_SERVICE
はアプリケーションのサービスです。これには、次の 3 つのコンテナが含まれます。init
- Application Signals を初期化するために必要なコンテナ。ecs-cwagent
– CloudWatch エージェントを実行するコンテナ
– これは、ドキュメントのアプリケーションコンテナの例です。実際のワークロードでは、この特定のコンテナが存在しないか、独自のサービスコンテナに置き換えられる可能性があります。my-app
デーモン戦略を使用した場合、次の 2 つのサービスが作成されます。
CloudWatchAgentDaemon
は CloudWatch エージェントデーモンサービスです。APPLICATION_SERVICE
はアプリケーションのサービスです。これには、次の 2 つのコンテナが含まれます。init
- Application Signals を初期化するために必要なコンテナ。
– これは、ドキュメントのアプリケーションコンテナの例です。実際のワークロードでは、この特定のコンテナが存在しないか、独自のサービスコンテナに置き換えられる可能性があります。my-app
レプリカ戦略を使用した場合、次の 2 つのサービスが作成されます。
CloudWatchAgentService
は CloudWatch エージェントレプリカサービスです。APPLICATION_SERVICE
はアプリケーションのサービスです。これには、次の 2 つのコンテナが含まれます。init
- Application Signals を初期化するために必要なコンテナ。
– これは、ドキュメントのアプリケーションコンテナの例です。実際のワークロードでは、この特定のコンテナが存在しないか、独自のサービスコンテナに置き換えられる可能性があります。my-app