For the complete documentation index, see llms.txt. Markdown versions are available by appending .md to documentation URLs.

ECS Serverless (Fargate) - Install

SigNoz Cloud - This page applies to SigNoz Cloud editions.
Self-Host - This page applies to self-hosted SigNoz editions.

This guide explains how to install the ECS Serverless Collection Agent in your Amazon ECS tasks on Fargate with Foundry and Terraform.

Prerequisites

  • A task definition for AWS Fargate that you manage with Terraform as an aws_ecs_task_definition resource.
  • Terraform 1.4 or newer and the AWS CLI on the same machine, with AWS credentials that can create SSM parameters and IAM roles.
  • AWS provider 5.x in the Terraform for your task definition, because the module that Foundry generates pins hashicorp/aws to ~> 5.0.
  • A SigNoz to send data to: SigNoz Cloud or a self-hosted SigNoz.

Install the Collection Agent

Step 1: Install foundryctl

Run this on the machine where you run Terraform:

curl -fsSL https://signoz.io/foundry.sh | bash

For manual install (Windows PowerShell, air-gapped, etc.) or PATH setup, see the foundry getting-started guide.

Step 2: Create casting.yaml

In the directory that holds the Terraform for your task definition, create a file named casting.yaml with one document for the collector described in How it works. collector.kind: sidecar selects that collector:

casting.yaml
apiVersion: v1alpha1
kind: CollectionAgent
metadata:
  name: signoz
  annotations:
    foundry.signoz.io/ecs-task-execution-role-arn: <execution-role-arn>
spec:
  deployment:
    platform: aws
    mode: ecs-serverless
    flavor: terraform
  collector:
    kind: sidecar
    spec:
      env:
        SIGNOZ_INGESTION_ENDPOINT: https://ingest.<region>.signoz.cloud:443
        SIGNOZ_INGESTION_KEY: <your-ingestion-key>
        OTEL_RESOURCE_ATTRIBUTES: deployment.environment=<DEPLOYMENT_ENVIRONMENT>
      config:
        data:
          collector/sidecar/sidecar.yaml: |
            exporters:
              otlphttp/signoz:
                headers:
                  signoz-ingestion-key: ${env:SIGNOZ_INGESTION_KEY}

Verify these values:

  • <execution-role-arn>: The ARN of your task definition's execution role, its execution_role_arn.
  • <region>: Your SigNoz Cloud region.
  • <your-ingestion-key>: Your SigNoz Cloud ingestion key.
  • <DEPLOYMENT_ENVIRONMENT>: Your deployment environment, for example staging or production. It becomes deployment.environment on the collected telemetry.

For every option of this casting, see the ECS Serverless Terraform example.

Step 3: Forge the Terraform module

Run this from the directory that contains casting.yaml:

foundryctl forge -f casting.yaml

It writes the Terraform module to pours/collectionagent/collector/sidecar/: main.tf.json, outputs.tf.json, versions.tf.json, and the collector config, sidecar.yaml.

Step 4: Add the module to your task definition

Add the module to your Terraform and use its outputs in your task definition, as in this example:

module "signoz_collector_sidecar" {
  source = "./pours/collectionagent/collector/sidecar"
}
 
resource "aws_ecs_task_definition" "app" {
  family                   = "app"
  network_mode             = "awsvpc"
  requires_compatibilities = ["FARGATE"]
  cpu                      = 1024
  memory                   = 2048
  execution_role_arn       = module.signoz_collector_sidecar.execution_role_arn
 
  container_definitions = jsonencode(concat(module.signoz_collector_sidecar.container_definitions, [
    {
      name             = "app"
      image            = "<your-application-image>"
      essential        = true
      logConfiguration = module.signoz_collector_sidecar.log_configuration
    },
  ]))
}

Verify these values:

  • <your-application-image>: Your application's image. Keep your own container definitions in place of the example's.

Raise the task's cpu and memory by the collector's 256 CPU units and 256 MiB, to a Fargate task size.

The logConfiguration line sends the app container's stdout and stderr to the collector instead of CloudWatch Logs. For the rules on which containers use it, see Collect Container Logs.

Step 5: Deploy

Deploy the task definition with your usual Terraform workflow. For example, run this from your Terraform root:

terraform init
terraform plan
terraform apply

When you apply, Terraform:

  • creates the SSM parameter signoz-collectionagent-ssm-collector-sidecar that holds the collector config;
  • adds the signoz-collectionagent-iam-exec-ssm-read policy to the execution role, so the task can read that parameter when it starts;
  • registers a new revision of your task definition with the signoz-collector-sidecar container, which a service that uses the task definition rolls out.

Step 6: Verify the Collection Agent

Run this on the machine where you use the AWS CLI to check that the collector runs in a task:

aws ecs describe-tasks --region <aws-region> --cluster <ecs-cluster> \
  --tasks $(aws ecs list-tasks --region <aws-region> --cluster <ecs-cluster> --family <task-family> --query 'taskArns[0]' --output text) \
  --query 'tasks[0].containers[].[name,lastStatus]' --output text

Verify these values:

  • <aws-region>: The AWS region of your ECS cluster, for example us-east-1.
  • <ecs-cluster>: The name or ARN of the cluster your task runs in.
  • <task-family>: The family of your task definition, app in the example.

The output should look similar to the following, with signoz-collector-sidecar as RUNNING. Your container names and their order vary:

signoz-collector-sidecar	RUNNING
app	RUNNING

If the collector shows STOPPED, see View the Collector's Logs.

In SigNoz, import the Container Metrics - ECS dashboard to see the task metrics. Check Logs Explorer to confirm your containers' logs are flowing, each under its container name as service.name.

Customize the Collection Agent

Every change follows the same loop: edit casting.yaml, run foundryctl forge -f casting.yaml, then apply with your usual Terraform workflow.

  • Collector settings (image, environment): set them in the collector's spec (see spec fields). For example, to pin the collector image:

    spec:
      collector:
        spec:
          image: otel/opentelemetry-collector-contrib:0.139.0
  • Collector config (receivers, processors, pipelines): add it under spec.collector.spec.config.data, keyed collector/sidecar/sidecar.yaml. It merges into the generated config (see custom config files). For example, to collect task metrics every 60s:

    spec:
      collector:
        spec:
          config:
            data:
              collector/sidecar/sidecar.yaml: |
                receivers:
                  awsecscontainermetrics:
                    collection_interval: 60s

    The module stores the collector config in a Standard-tier SSM parameter, which holds up to 4 KB. For a larger config, patch the parameter's tier in main.tf.json to Advanced, which holds 8 KB, is charged, and cannot go back to Standard, as parameter tiers describes.

  • Terraform (collector container, SSM parameter): add patches under spec.patches against the files under collectionagent/collector/sidecar/, such as main.tf.json for the collector container and the SSM parameter. To find the path to patch, run foundryctl forge -f casting.yaml and look in the generated files under pours/collectionagent/collector/sidecar/. For example, to reserve more memory for the collector:

    spec:
      patches:
        - target: collectionagent/collector/sidecar/main.tf.json
          operations:
            - op: replace
              path: /locals/container_collector_sidecar/memoryReservation
              value: 512

    Each run regenerates the files under pours/, so keep every change in casting.yaml.

Troubleshooting

foundryctl forge stops with unsupported collector kind "agent"

In Step 3, foundryctl forge -f casting.yaml stops before it writes anything, with the message unsupported collector kind "agent".

Cause: the casting has no collector.kind, so the collector kind defaults to agent, and on Fargate the collector runs as a sidecar in your task.

Fix: add kind: sidecar under spec.collector, as in Step 2, then run Step 3 again.

After the fix, foundryctl forge writes the module under pours/collectionagent/collector/sidecar/, and you can go on to Step 4.

foundryctl forge rejects replicas

In Step 3, foundryctl forge -f casting.yaml stops with the message spec.collector.spec.cluster.replicas is 2, a sidecar runs once in every task it joins.

Cause: the casting sets spec.collector.spec.cluster.replicas, and the sidecar runs once in each task.

Fix: remove replicas from casting.yaml, then run Step 3 again. To run more collectors, run more tasks.

After the fix, foundryctl forge writes the module under pours/collectionagent/collector/sidecar/, and you can go on to Step 4.

foundryctl forge rejects a patch

After you add a patch from Customize the Collection Agent, foundryctl forge -f casting.yaml stops before it writes anything, with the message failed to apply patch for target "<target>". Its cause ends with doc is missing key: <path>: missing value or doc is missing path: <path>: missing value, or, when no generated file matches the target, patch target "<target>" did not match any generated material.

Cause: the patch's target or path does not exist in what Foundry generates.

Fix: remove the patch and forge again. Then take the target and the path from the generated files under pours/collectionagent/collector/sidecar/, add the patch back, and forge again.

After the fix, foundryctl forge writes the module with the patch applied, and you can apply it with your usual Terraform workflow.

terraform plan stops on an interpolation in env

In Step 5, terraform plan stops on pours/collectionagent/collector/sidecar/main.tf.json, in locals.container_collector_sidecar.environment, with Error: Invalid reference for a value such as ${MY_KEY}, or Error: Extra characters after interpolation expression for a value such as ${env:MY_KEY}.

Cause: a value under spec.collector.spec.env contains ${, which Terraform reads as one of its own expressions.

Fix: replace the expression with the literal value in casting.yaml, run Step 3 again, then run Step 5 again.

After the fix, terraform plan lists the resources to create or change.

The task stops with ResourceInitializationError

After Step 5, your tasks stop before they reach RUNNING. Run this on the machine where you use the AWS CLI to read why the latest task stopped:

aws ecs describe-tasks --region <aws-region> --cluster <ecs-cluster> \
  --tasks $(aws ecs list-tasks --region <aws-region> --cluster <ecs-cluster> --family <task-family> --desired-status STOPPED --query 'taskArns[0]' --output text) \
  --query 'tasks[0].stoppedReason' --output text

Verify these values:

  • <aws-region>: The AWS region of your ECS cluster.
  • <ecs-cluster>: The name or ARN of the cluster your task runs in.
  • <task-family>: The family of your task definition.

The reason starts with ResourceInitializationError: unable to pull secrets or registry auth. Read the rest of it: AccessDeniedException points to the execution role, and dial tcp or i/o timeout points to the network.

Cause: with AccessDeniedException, the task's execution role cannot read the collector config parameter signoz-collectionagent-ssm-collector-sidecar. The module grants that read only to the role in the foundry.signoz.io/ecs-task-execution-role-arn annotation, and the task definition names another role. With dial tcp or i/o timeout, the task's subnets have no route to SSM, such as a NAT gateway or an SSM VPC endpoint. See Troubleshooting ResourceInitializationError errors.

Fix: for AccessDeniedException, set the annotation to the task's execution role ARN as in Step 2, and take the task definition's execution_role_arn from the module as in Step 4. Then run Step 3 and Step 5 again. For a timeout, give the task's subnets a route to SSM, as Verifying Amazon ECS stopped task connectivity describes, then run Step 5 again.

After the fix, the Step 6 command shows signoz-collector-sidecar as RUNNING.

The collector container stops

In Step 6, signoz-collector-sidecar shows STOPPED while your other containers keep running.

Cause: the collector exited soon after it started, for example on a config error, so ECS did not restart it.

Fix: read the collector's error as View the Collector's Logs shows, fix the config in casting.yaml, then run Step 3 and Step 5 again.

After the fix, the Step 6 command shows signoz-collector-sidecar as RUNNING.

Send data from your applications

Task metrics and container logs flow as soon as the collector is running. To send traces, metrics, and logs from your applications, see Send Data from Applications to the Collector.

Next Steps

Is this page helpful

Last updated—October 26, 2026

Edit on GitHub