使用 Amazon CDK 在 Amazon ECS 上启用 Application Signals
要使用 Amazon 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 的服务相关角色权限。
-
使用 Amazon CDK 中的 AWS::ApplicationSignals 构造库
来检测您的应用程序。本文档中的代码片段为 TypeScript 格式。有关其他特定语言的备选方案,请参阅 Amazon CDK 支持的编程语言。 使用附加模式在 Amazon ECS 上启用 Application Signals
配置
instrumentation
,以使用 Amazon Distro for OpenTelemetry(ADOT)SDK Agent 检测应用程序。以下是检测 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 EC2 的 Amazon ECS 上受支持。
以
HOST
网络模式将 CloudWatch 代理作为守护进程服务运行。配置
instrumentation
,以使用 ADOT Python 代理检测应用程序。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 代理与相关服务之间的连接正确。
使用服务连接将 CloudWatch 代理作为副本服务运行。
配置
instrumentation
,以使用 ADOT Python 代理检测应用程序。配置
overrideEnvironments
来使用服务连接端点与 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'; 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.
更新任务定义。
将其他配置添加到您的应用程序容器。
Configure
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
命令。要在您的 Amazon 账户中部署服务,请在应用程序的主目录中运行cdk deploy
命令。如果您使用的是挎斗策略,则会看到创建了一个服务:
APPLICATION_SERVICE
是您应用程序的服务。该服务包含以下三个容器:init
– Application Signals 初始化所必需的容器。ecs-cwagent
– 运行 CloudWatch 代理的容器
– 这是我们文档中的示例应用程序容器。在实际工作负载中,此特定的容器可能不存在,或者可能被您自己的服务容器所取代。my-app
如果您使用的是进程守护程序策略,则会看到创建了两个服务:
CloudWatchAgentDaemon
是 CloudWatch 代理进程守护程序服务。APPLICATION_SERVICE
是您应用程序的服务。该服务包含以下两个容器:init
– Application Signals 初始化所必需的容器。
– 这是我们文档中的示例应用程序容器。在实际工作负载中,此特定的容器可能不存在,或者可能被您自己的服务容器所取代。my-app
如果您使用的是进程守护程序策略,则会看到创建了两个服务:
CloudWatchAgentService
是 CloudWatch 代理进程守护程序服务。APPLICATION_SERVICE
是您应用程序的服务。该服务包含以下两个容器:init
– Application Signals 初始化所必需的容器。
– 这是我们文档中的示例应用程序容器。在实际工作负载中,此特定的容器可能不存在,或者可能被您自己的服务容器所取代。my-app