Deploy using the AWS Cloud Development Kit (AWS CDK) - Amazon CloudWatch

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
  1. Open the CloudWatch console at https://console.aws.amazon.com/cloudwatch/.

  2. In the navigation pane, choose Services.

  3. Choose Start discovering your Services.

  4. 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
  1. In your application task definition, specify a bind mount. Replace MOUNT_VOLUME according to the language your application uses. For example use opentelemetry-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, }] );
  2. 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-agent on 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-agent on 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, });
  3. 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 and INIT_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 });
  4. Add the environment variables ENVIRONMENT_VARIABLES to your application container according to the language your application uses. And mount the volume MOUNT_VOLUME in the application container.

    Note

    For language-specific setup instructions that specify values for MOUNT_VOLUME>, MOUNT_CONTAINER_PATH>, INIT_CONTAINER_COMMAND>, and ENVIRONMENT_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
  1. 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
  2. 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

    • my-app– 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.

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.

    • my-app– 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.