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_definitionresource. - 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/awsto~> 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 | bashFor 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:
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, itsexecution_role_arn.<region>: Your SigNoz Cloud region.<your-ingestion-key>: Your SigNoz Cloud ingestion key.<DEPLOYMENT_ENVIRONMENT>: Your deployment environment, for examplestagingorproduction. It becomesdeployment.environmenton 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.yamlIt 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 applyWhen you apply, Terraform:
- creates the SSM parameter
signoz-collectionagent-ssm-collector-sidecarthat holds the collector config; - adds the
signoz-collectionagent-iam-exec-ssm-readpolicy 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-sidecarcontainer, 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 textVerify these values:
<aws-region>: The AWS region of your ECS cluster, for exampleus-east-1.<ecs-cluster>: The name or ARN of the cluster your task runs in.<task-family>: Thefamilyof your task definition,appin 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 RUNNINGIf 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, keyedcollector/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: 60sThe 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
tierinmain.tf.jsontoAdvanced, 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.patchesagainst the files undercollectionagent/collector/sidecar/, such asmain.tf.jsonfor the collector container and the SSM parameter. To find the path to patch, runfoundryctl forge -f casting.yamland look in the generated files underpours/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: 512Each run regenerates the files under
pours/, so keep every change incasting.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 textVerify 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>: Thefamilyof 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.