Habilitación de Application Signals en Amazon ECS con AWS CDK
Para habilitar Application Signals en Amazon ECS con AWS CDK, haga lo siguiente.
Habilitación de Application Signals para sus aplicaciones: si aún no ha habilitado Application Signals en esta cuenta, debe conceder a Application Signals los permisos que necesita para detectar los servicios.
import { aws_applicationsignals as applicationsignals } from 'aws-cdk-lib'; const cfnDiscovery = new applicationsignals.CfnDiscovery(this, 'ApplicationSignalsServiceRole', { } );
El recurso Discovery de CloudFormation otorga a Application Signals los siguientes permisos:
-
xray:GetServiceGraph
-
logs:StartQuery
-
logs:GetQueryResults
-
cloudwatch:GetMetricData
-
cloudwatch:ListMetrics
-
tag:GetResources
Para obtener más información acerca de este rol, consulte Permisos de roles vinculados a un servicio para CloudWatch Application Signals.
-
Instrumente su aplicación con la biblioteca AWS::ApplicationSignals Construct
en el AWS CDK. Los fragmentos de código de este documento se proporcionan en TypeScript. Para ver alternativas específicas para otros lenguajes, consulte Lenguajes de programación admitidos para el AWS CDK. Habilitar Application Signals en Amazon ECS con el modo sidecar
Configure
instrumentation
para instrumentar la aplicación con el agente del SDK de AWS Distro para OpenTelemetry (ADOT). El siguiente es un ejemplo de instrumentación de una aplicación Java. Consulte InstrumentationVersion para ver todas las versiones de lenguajes compatibles.Especifique
cloudWatchAgentSidecar
para configurar el agente de CloudWatch como un contenedor sidecar.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, }); } }
Habilitar Application Signals en Amazon ECS con el modo daemon
nota
La estrategia de implementación de daemon no es compatible con Amazon ECS Fargate y solo es compatible con Amazon ECS en Amazon EC2.
Ejecute el agente de CloudWatch como un servicio daemon con el modo de red
HOST
.Configure
instrumentation
para instrumentar la aplicación con el agente de ADOT de 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, }); } }
Habilitar Application Signals en Amazon ECS con el modo de réplica
nota
La ejecución del servicio del agente de CloudWatch mediante el modo de réplica requiere configuraciones de grupos de seguridad específicas para permitir la comunicación con otros servicios. Para la funcionalidad de Application Signals, configure el grupo de seguridad con las reglas de entrada mínimas: Puerto 2000 (HTTP) y Puerto 4316 (HTTP). Esta configuración garantiza una conectividad adecuada entre el agente de CloudWatch y los servicios dependientes.
Ejecute el agente de CloudWatch como un servicio de réplica con Service Connect.
Configure
instrumentation
para instrumentar la aplicación con el agente de ADOT de Python.Anule las variables de entorno configurando
overrideEnvironments
para usar puntos de conexión de service connect para comunicarse con el servidor del agente de 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, }); } }
Configuración de una aplicación Node.js con el formato de módulo ESM. La compatibilidad para las aplicaciones Node.js con el formato de módulo ESM es limitada. Para obtener más información, consulte Limitaciones conocidas de Node.js con ESM.
La habilitación de Application Signals mediante el uso del contenedor
init
para inyectar el SDK de instrumentación de Node.js no aplica para el formato de módulo ESM. Omita el paso 2 de este procedimiento y siga estos pasos:Instale en su aplicación Node.js las dependencias pertinentes para la instrumentación automática.
npm install @aws/aws-distro-opentelemetry-node-autoinstrumentation npm install @opentelemetry/instrumentation@0.54.
Actualice TaskDefinition.
Añada configuración adicional a su contenedor de aplicaciones.
Configuración
NODE_OPTIONS
.(Opcional) Añada el agente de CloudWatch si elige el modo sidecar.
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, }); }
Implementación de la pila actualizada: ejecute el comando
cdk synth
en el directorio principal de la aplicación. Para implementar el servicio en su cuenta de AWS, ejecute el comandocdk deploy
en el directorio principal de la aplicación.Si ha utilizado la estrategia de sidecar, verá que se ha creado un servicio:
APPLICATION_SERVICE
es el servicio de la aplicación. Incluye los tres contenedores siguientes:init
: contenedor necesario para inicializar Application Signals.ecs-cwagent
: contenedor que ejecuta el agente de CloudWatch.
: este es el ejemplo de contenedor de aplicaciones de nuestra documentación. En las cargas de trabajo reales, es posible que no exista este contenedor específico, o que se sustituya por sus propios contenedores de servicio.my-app
Si ha utilizado la estrategia de daemon, verá que se han creado dos servicios:
CloudWatchAgentDaemon
es el servicio de daemon del agente de CloudWatch.APPLICATION_SERVICE
es el servicio de la aplicación. Incluye los dos contenedores siguientes:init
: contenedor necesario para inicializar Application Signals.
: este es el ejemplo de contenedor de aplicaciones de nuestra documentación. En las cargas de trabajo reales, es posible que no exista este contenedor específico, o que se sustituya por sus propios contenedores de servicio.my-app
Si utilizó la estrategia de réplica, verá que se crearon dos servicios:
CloudWatchAgentService
es el servicio de réplica del agente de CloudWatch.APPLICATION_SERVICE
es el servicio de la aplicación. Incluye los dos contenedores siguientes:init
: contenedor necesario para inicializar Application Signals.
: este es el ejemplo de contenedor de aplicaciones de nuestra documentación. En las cargas de trabajo reales, es posible que no exista este contenedor específico, o que se sustituya por sus propios contenedores de servicio.my-app