Deploy using the AWS Cloud Development Kit (AWS CDK)
Step 1: Enable Application Signals in your account
If you haven't enabled Application Signals in this account yet, you must grant Application Signals the permissions it needs to discover your services. To do so, do the following. You need to do this only once for your account.
To enable Application Signals for your applications
Open the CloudWatch console at https://console.aws.amazon.com/cloudwatch/
. In the navigation pane, choose Services.
Choose Start discovering your Services.
Select the check box and choose Start discovering Services.
Completing this step for the first time in your account creates the AWSServiceRoleForCloudWatchApplicationSignals service-linked role. This role grants Application Signals the following permissions:
-
xray:GetServiceGraph
-
logs:StartQuery
-
logs:GetQueryResults
-
cloudwatch:GetMetricData
-
cloudwatch:ListMetrics
-
tag:GetResources
For more information about this role, see Service-linked role permissions for CloudWatch Application Signals.
-
Step 2: Create IAM roles
You must create an IAM role. If you already have created this role, you might need to add permissions to it.
-
ECS task role— Containers use this role to run. The permissions should be whatever your applications need, plus CloudWatchAgentServerPolicy.
For more information about creating IAM roles, see Creating IAM Roles.
Step 3: Instrument your application with the CloudWatch agent in AWS CDK
To enable Application Signals for Amazon ECS using the AWS CDK, follow the steps outlined below. The code snippets in this document are provided in TypeScript. For other language-specific alternatives, see Supported programming languages for the AWS CDK cloudwatch-agent
Note
This document provides an overview of the Application Signals setup process using the AWS CDK, see Step 4:
Instrument your application with the CloudWatch agent for language-specific setup instructions that
specify values for MOUNT_VOLUME
>, MOUNT_CONTAINER_PATH
>, INIT_CONTAINER_COMMAND
>, and
ENVIRONMENT_VARIABLES
To instrument your application with the CloudWatch agent
In your application task definition, specify a bind mount. Replace
MOUNT_VOLUME
according to the language your application uses. For example useopentelemetry-auto-instrumentation
in Java. The volume will be used to share files across containers in the next steps. You will use this bind mount later in this procedure:const taskDefinition = new ecs.FargateTaskDefinition(this, 'MyTaskDefinition', { ... volumes: [{ name:
MOUNT_VOLUME
, }] );Next, you add the CloudWatch agent. There are two possible methods to use add CloudWatch agent: sidecar strategy and daemon strategy. For information about the pros and cons for each method, see Use a custom setup to enable Application Signals on Amazon ECS and choose the best method for your environment.
Sidecar strategy– Append a new container called
ecs-cwagent
to your application's task definition. Replace$IMAGE
with the path to the latest CloudWatch container image on Amazon Elastic Container Registry. For more information, see cloudwatch-agenton Amazon ECR. const cwAgentContainer = taskDefinition.addContainer('ecs-cwagent', { image: ecs.ContainerImage.fromRegistry("
$IMAGE
"), environment: { CW_CONFIG_CONTENT: '{"agent": {"debug": true}, "traces": {"traces_collected": {"application_signals": {"enabled": true}}}, "logs": {"metrics_collected": {"application_signals": {"enabled": true}}}}', }, logging: new ecs.AwsLogDriver({ streamPrefix: 'ecs', logGroup: new logs.LogGroup(this, 'CwAgentLogGroup', { logGroupName: '/ecs/ecs-cwagent', }), }), });Daemon strategy– Create a new service called
ecs-cwagent
in your stack. Replace$TASK_ROLE_ARN
and$EXECUTION_ROLE_ARN
with the IAM roles that you prepared in Step 2: Create IAM roles. Replace$IMAGE
with the path to the latest CloudWatch container image on Amazon Elastic Container Registry. For more information, see cloudwatch-agenton Amazon ECR. Note
The daemon service exposes two ports on the host, with 4316 used as the endpoint for receiving metrics and traces and 2000 as the CloudWatch trace sampler endpoint. This setup allows the agent to collect and transmit telemetry data from all application tasks running on the host. Ensure that these ports are not used by other services on the host to avoid conflicts.
const cwAgentTaskDefinition = new ecs.Ec2TaskDefinition(this, 'CwAgentDaemonTaskDef', { taskRole: "
$TASK_ROLE_ARN
", executionRole: "$EXECUTION_ROLE_ARN
", }); // Add the CloudWatch agent container const cwAgentContainer = cwAgentTaskDefinition.addContainer('ecs-cwagent', { image: ecs.ContainerImage.fromRegistry("$IMAGE
"), cpu: 128, memoryLimitMiB: 64, portMappings: [ { containerPort: 4316, hostPort: 4316, }, { containerPort: 2000, hostPort: 2000, }, ], logging: new ecs.AwsLogDriver({ streamPrefix: 'ecs', logGroup: new logs.LogGroup(this, 'CwAgentLogGroup', { logGroupName: '/ecs/ecs-cwagent-daemon', }), }), environment: { CW_CONFIG_CONTENT: '{"agent": {"debug": true}, "traces": {"traces_collected": {"application_signals": {"enabled": true}}}, "logs": {"metrics_collected": {"application_signals": {"enabled": true}}}}', }, }); // Add the CloudWatch agent service running as a daemon const cwAgentService = new ecs.Ec2Service(this, 'CwAgentDaemonService', { cluster, taskDefinition: cwAgentTaskDefinition, daemon: true, });
Append a new container init to your application's task definition. Replace
$IMAGE
with the latest image from the AWS Distro for OpenTelemetry Amazon ECR image repository. Replace MOUNT_CONTAINER_PATH
andINIT_CONTAINER_COMMAND
according to the language your application uses.For example, in Java use
INIT_CONTAINER_COMMAND
=["cp", "/javaagent.jar", "/otel-auto-instrumentation/javaagent.jar"],MOUNT_CONTAINER_PATH
='/otel-auto-instrumentation'const initContainer = taskDefinition.addContainer('init', { image: ecs.ContainerImage.fromRegistry("
$IMAGE
"), essential: false, command:INIT_CONTAINER_COMMAND
}); initContainer.addMountPoints({ sourceVolume:MOUNT_VOLUME
, containerPath:MOUNT_CONTAINER_PATH
, readOnly: false });Add the environment variables
ENVIRONMENT_VARIABLES
to your application container according to the language your application uses. And mount the volumeMOUNT_VOLUME
in the application container.Note
For language-specific setup instructions that specify values for
MOUNT_VOLUME
>,MOUNT_CONTAINER_PATH
>,INIT_CONTAINER_COMMAND
>, andENVIRONMENT_VARIABLES
, see Step 4: Instrument your application with the CloudWatch agent.The following is an example:
const appContainer = taskDefinition.addContainer('my-app', { ... environment: { ...
ENVIRONMENT_VARIABLES
}, }); appContainer.addMountPoints({ sourceVolume:MOUNT_VOLUME
, containerPath:MOUNT_CONTAINER_PATH
, readOnly: false });
Setting up a Node.js application with the ESM module format
We provide limited support for Node.js applications with the ESM module format. For details, see Known limitations about Node.js with ESM.
For the ESM module format, enabling Application Signals by using the init
container to inject the Node.js instrumentation SDK
doesn't apply. Skip steps 1 and 3
of the previous procedure, and do the following instead.
To enable Application Signals for a Node.js application with ESM
Install the relevant dependencies to your Node.js application for autoinstrumentation:
npm install @aws/aws-distro-opentelemetry-node-autoinstrumentation npm install @opentelemetry/instrumentation@0.54.0
In step 4 in the previous procedure, remove the mounting of the volume:
appContainer.addMountPoints({ sourceVolume: MOUNT_VOLUME, containerPath: MOUNT_CONTAINER_PATH, readOnly: false });
And set the environmental variable
NODE_OPTIONS
to be--import @aws/aws-distro-opentelemetry-node-autoinstrumentation/register --experimental-loader=@opentelemetry/instrumentation/hook.mjs
Step 4: Deploy the updated stack
Run the cdk synth
command in your application's main directory.
To deploy the service in your AWS account, run the cdk deploy
command in your application's main directory.
If you used the sidecar strategy, you'll see one service created:
APPLICATION_SERVICE
is the service of your application. It includes the three following containers:init
– A required container for initializing Application Signals.ecs-cwagent
– A container running the CloudWatch agent
– This is the example application container in our documentation. In your actual workloads, this specific container might not exist or might be replaced with your own service containers.my-app
If you used the daemon strategy, you'll see two services created:
CWAgentDaemonService
is the CloudWatch agent daemon service.APPLICATION_SERVICE
is the service of your application. It includes the two following containers:init
– A required container for initializing Application Signals.
– This is the example application container in our documentation. In your actual workloads, this specific container might not exist or might be replaced with your own service containers.my-app