This guide runs the EKS Fargate Collection Agent through the OpenTelemetry Operator. Foundry generates each collector as an OpenTelemetryCollector resource, and the operator creates the deployment collector's workload and Service from it. For the sidecar, the operator's webhook injects the collector into each new pod whose template carries the sidecar.opentelemetry.io/inject annotation.
Prerequisites
- An EKS cluster with a Fargate profile that selects the collector's namespace and your applications' namespaces.
kubectlconfigured to reach the cluster, with the AWS CLI and Helm 3 installed on the same machine for the Fargate profile and cert-manager.- A SigNoz to send data to: SigNoz Cloud or a self-hosted SigNoz.
Install the Collection Agent
Step 1: Install the OpenTelemetry Operator
Install the OpenTelemetry Operator, which reconciles the OpenTelemetryCollector resources Foundry generates for the collectors, and cert-manager, which issues the certificate of the operator's admission webhook. Run these on the machine where you use kubectl, with the AWS CLI and Helm 3 installed:
-
Add a Fargate profile that selects the
cert-managerandopentelemetry-operator-systemnamespaces:aws eks create-fargate-profile --cluster-name <cluster-name> \ --fargate-profile-name opentelemetry-operator \ --pod-execution-role-arn <pod-execution-role-arn> \ --selectors namespace=cert-manager namespace=opentelemetry-operator-systemVerify these values:
<cluster-name>: Your EKS cluster's name.<pod-execution-role-arn>: The ARN of the pod execution role your other Fargate profiles use.
-
Install cert-manager with its webhook on port 10260, since on Fargate the kubelet holds the default port 10250, as cert-manager's AWS Fargate notes describe:
helm install cert-manager oci://quay.io/jetstack/charts/cert-manager \ --version v1.21.2 \ --namespace cert-manager \ --create-namespace \ --set crds.enabled=true \ --set webhook.securePort=10260 -
Wait until cert-manager's webhook is ready, so that it accepts the operator's certificate:
kubectl -n cert-manager rollout status deploy/cert-manager-webhook -
Install operator v0.139.0, which matches the OpenTelemetry Collector 0.139.0 that Foundry pins, and its CRDs:
kubectl apply -f https://github.com/open-telemetry/opentelemetry-operator/releases/download/v0.139.0/opentelemetry-operator.yaml -
Check the operator. It is ready when
READYshows1/1:kubectl get deployment opentelemetry-operator-controller-manager -n opentelemetry-operator-system
Step 2: Install foundryctl
Run this on the machine where you use kubectl:
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 3: Create casting.yaml
Create a file named casting.yaml with one document for the deployment collector described in How it works. collector.kind: deployment selects it:
apiVersion: v1alpha1
kind: CollectionAgent
metadata:
name: signoz
annotations:
foundry.signoz.io/kubernetes-collector-controller: opentelemetry-operator
spec:
deployment:
platform: aws
mode: kubernetes-serverless
flavor: kustomize
collector:
kind: deployment
spec:
env:
SIGNOZ_INGESTION_ENDPOINT: https://ingest.<region>.signoz.cloud:443
SIGNOZ_INGESTION_KEY: <your-ingestion-key>
K8S_CLUSTER_NAME: <CLUSTER_NAME>
OTEL_RESOURCE_ATTRIBUTES: deployment.environment=<DEPLOYMENT_ENVIRONMENT>
config:
data:
collector/deployment/deployment.yaml: |
exporters:
otlphttp/signoz:
headers:
signoz-ingestion-key: ${env:SIGNOZ_INGESTION_KEY}Verify these values:
<region>: Your SigNoz Cloud region.<your-ingestion-key>: Your SigNoz Cloud ingestion key.<CLUSTER_NAME>: A name for this cluster, unique across the clusters that send to the same SigNoz, which becomesk8s.cluster.nameand names the cluster in the SigNoz Kubernetes views.<DEPLOYMENT_ENVIRONMENT>: Your deployment environment, for examplestagingorproduction, which becomesdeployment.environmenton the collected telemetry.
For every option of this casting, see the EKS Fargate Kustomize example.
Step 4: Deploy
Run this from the directory that contains casting.yaml:
foundryctl cast -f casting.yamlThis command:
- writes the kustomize root
pours/collectionagent/collector/deployment; - applies it with
kubectl apply -kto the cluster of your currentkubectlcontext; - creates the collector's namespace on the first apply,
signozfrommetadata.namein this casting. The root holds the namespace, the collector's service account and RBAC, and theOpenTelemetryCollectorresourcesignoz-collector-deployment.
The operator then creates the collector's workload and Service, signoz-collector-deployment-collector, from the resource. Run the same command again after editing casting.yaml to apply the change.
Step 5: Verify the Collection Agent
Run this on the machine where you use kubectl to check that the deployment collector's pod is running on a Fargate node, in the namespace from metadata.name:
kubectl get pods -n signoz -o wideThe output should look similar to the following, with one signoz-collector-deployment-collector pod on a node whose name starts with fargate-. The operator names the workload after its OpenTelemetryCollector resource with a -collector suffix. Pod suffixes, IP addresses, and node names vary:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
signoz-collector-deployment-collector-6d9c7b8f5c-k2x9p 1/1 Running 0 2m 10.0.12.34 fargate-ip-10-0-12-34.ec2.internal <none> <none>In SigNoz, open the Kubernetes Monitoring views under Infrastructure Monitoring. The Clusters view lists your cluster under the name you set as <CLUSTER_NAME>, and the Pods and Nodes views fill in as data arrives. Check Logs Explorer to confirm Kubernetes events are flowing.
Add the sidecar to your workloads
The sidecar has its own casting.yaml, kept in your application's kustomization directory.
Step 1: Create casting.yaml
The sidecar's document carries the same foundry.signoz.io/kubernetes-collector-controller: opentelemetry-operator annotation as the deployment collector's.
Create a file named casting.yaml with this content:
apiVersion: v1alpha1
kind: CollectionAgent
metadata:
name: signoz
annotations:
foundry.signoz.io/kubernetes-collector-controller: opentelemetry-operator
spec:
deployment:
platform: aws
mode: kubernetes-serverless
flavor: kustomize
collector:
kind: sidecar
spec:
env:
SIGNOZ_INGESTION_ENDPOINT: https://ingest.<region>.signoz.cloud:443
SIGNOZ_INGESTION_KEY: <your-ingestion-key>
K8S_CLUSTER_NAME: <CLUSTER_NAME>
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:
<region>: Your SigNoz Cloud region.<your-ingestion-key>: Your SigNoz Cloud ingestion key.<CLUSTER_NAME>: The same value as in the deployment collector'scasting.yaml, which becomesk8s.cluster.nameon every signal.<DEPLOYMENT_ENVIRONMENT>: Your deployment environment, for examplestagingorproduction, which becomesdeployment.environmenton the collected telemetry.
Step 2: Generate the sidecar files
Keep casting.yaml in your application's kustomization directory, the one that holds its kustomization.yaml, so pours/ lands beside kustomization.yaml. Run this there to write the sidecar's files:
foundryctl forge -f casting.yamlFoundry generates the OpenTelemetryCollector resource signoz-collector-sidecar in sidecar mode. The operator injects the sidecar into each new pod whose template carries the sidecar.opentelemetry.io/inject annotation.
Step 3: Add the sidecar to your workloads
Add the sidecar's files to your application's kustomization.yaml, then annotate each workload that takes the sidecar.
The sidecar's permissions go to the namespace's default service account. If your workloads run under service accounts of their own, create signoz-rolebinding.yaml beside kustomization.yaml:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: signoz-collector-sidecar
subjects:
- kind: ServiceAccount
name: <your-service-account>
- kind: ServiceAccount
name: defaultVerify these values:
<your-service-account>: The service account of a workload that takes the sidecar, fromserviceAccountNamein its pod template; add one subject per account, and keepdefaultwhile any such workload runs under it.
Edit your application's kustomization.yaml to add the sidecar's directory and the rolebinding file:
namespace: <your-namespace>
resources:
+ - pours/collectionagent/collector/sidecar
patches:
+ - path: signoz-rolebinding.yamlVerify these values:
<your-namespace>: Your application's namespace.
Leave out the signoz-rolebinding.yaml entry if you did not create that file. The kustomization's namespace: places the sidecar's resource and permissions in your application's namespace.
Add the annotation to the pod template of each workload that takes the sidecar, whichever way you manage the template:
spec:
template:
metadata:
+ annotations:
+ sidecar.opentelemetry.io/inject: "signoz-collector-sidecar"A CronJob takes the annotation under spec.jobTemplate.spec.template.metadata.annotations.
The sidecar's resource must exist before your workloads' pods are created. On the first deploy, apply the sidecar's files on their own and check that the resource is listed. Run this from the directory that contains casting.yaml, with the same <your-namespace>:
kubectl -n <your-namespace> apply -k pours/collectionagent/collector/sidecar
kubectl -n <your-namespace> get opentelemetrycollector signoz-collector-sidecarThen run this on the machine where you use kubectl to apply your application:
kubectl apply -k <overlay>Verify these values:
<overlay>: The directory that holds your application'skustomization.yaml, relative to where you run the command.
The operator injects the sidecar into each new pod, so restart the workloads whose pods were already running, for example a Deployment:
kubectl -n <your-namespace> rollout restart deployment/<your-workload>Verify these values:
<your-workload>: The name of the workload, from its manifest.
Jobs and CronJob runs created before the resource ran without the sidecar; delete them and create them again.
Step 4: Verify the sidecar
Run this on the machine where you use kubectl to check that a workload's pods run the sidecar:
kubectl -n <your-namespace> get pods -l <your-pod-selector> -o jsonpath='{.items[*].spec.initContainers[*].name}'Verify these values:
<your-namespace>: Your application's namespace.<your-pod-selector>: A label selector for the workload's pods, fromspec.selector.matchLabelsin its manifest.
The output lists otc-container, the sidecar the operator injected, once per pod.
Once your application sends to the sidecar, as Send Data from Applications to the Collector shows, its traces, metrics, and logs appear in SigNoz with the k8s.pod.name and k8s.namespace.name resource attributes.
Apply Changes
After a change to the sidecar's casting.yaml, forge again, apply your application again, and restart the workloads that take the sidecar.
Customize the Collection Agent
Every change follows the same loop: edit casting.yaml, then run foundryctl cast -f casting.yaml again. For the sidecar, forge and apply as Apply Changes shows, then restart the workloads that run it.
-
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/deployment/deployment.yamlin the deployment collector's document orcollector/sidecar/sidecar.yamlin the sidecar's. It merges into the generated config, which becomes the resource'sspec.config(see custom config files). For example, to scrape kubelet metrics every 60s:spec: collector: spec: config: data: collector/deployment/deployment.yaml: | receivers: receiver_creator: receivers: kubeletstats: config: collection_interval: 60s -
Manifests (resources, annotations): add patches under
spec.patchesagainstcollectionagent/collector/deployment/opentelemetrycollector.yamlorcollectionagent/collector/sidecar/opentelemetrycollector.yaml, the collectors'OpenTelemetryCollectorresources, with paths under/spec. For example, to give the deployment collector more CPU and memory:spec: patches: - target: collectionagent/collector/deployment/opentelemetrycollector.yaml operations: - op: replace path: /spec/resources value: requests: cpu: 500m memory: 1Gi limits: cpu: 500m memory: 1GiFor every field of the resource, see the OpenTelemetryCollector API reference. Each run regenerates the files under
pours/, so keep every change incasting.yaml.
Troubleshooting
Collector pod stays Pending
In Step 5: Verify the Collection Agent, the deployment collector's pod stays Pending. Run this on the machine where you use kubectl to see why the pod is unscheduled:
kubectl describe pod -n signoz <pod-name>Replace <pod-name> with the pod's name from kubectl get pods -n signoz. The events show FailedScheduling.
Cause: no Fargate profile selects the collector's namespace, so no Fargate node is started for the pod.
Fix: add a Fargate profile that selects the namespace, then run this on the machine where you use kubectl to recreate the pod:
kubectl rollout restart -n signoz deployment/signoz-collector-deployment-collectorAfter the fix, kubectl get pods -n signoz -o wide shows the pod as Running on a fargate- node.
The pods view stays empty
In Step 5: Verify the Collection Agent, the Pods view in SigNoz stays empty. Run this on the machine where you use kubectl to read the deployment collector's logs:
kubectl logs -n signoz deployment/signoz-collector-deployment-collector --since=10mThe logs show errors from the kubelet scrapes: a 403, or a 404 on /api/v1/nodes/<node-name>/proxy/stats/summary.
Cause: with a 403, the collector's service account is not allowed through the Kubernetes API server's node proxy. With a 404, the kubelet on that node does not serve its stats through the proxy.
Fix: for a 403, run this on the machine where you use kubectl. It prints yes once the ClusterRole Foundry generates is in place:
kubectl auth can-i get nodes/proxy --as=system:serviceaccount:signoz:signoz-collector-deploymentIf it prints no, run Step 4: Deploy again. For a 404, scrape the kubelets directly, as the example's API-server proxy section shows.
After the fix, the Pods view in SigNoz lists your pods.
foundryctl cast stops with unsupported collector kind "agent"
In Step 4: Deploy, foundryctl cast -f casting.yaml stops before it applies anything, with the message unsupported collector kind "agent".
Cause: the document has no collector.kind, so the collector kind defaults to agent, and on EKS Fargate the collector kinds are deployment and sidecar.
Fix: add kind: deployment under spec.collector, as in Step 3: Create casting.yaml, or kind: sidecar in the sidecar's document, then run Step 4: Deploy again.
After the fix, kubectl get pods -n signoz shows the deployment collector's pod.
foundryctl cast rejects a patch
In Step 4: Deploy, foundryctl cast -f casting.yaml stops before it applies anything, with failed to apply patch for target "<target>" and one of these causes:
doc is missing key: <path>: missing valuedoc is missing path: <path>: missing valuepatch target "<target>" did not match any generated material
Cause: the patch's target or path does not exist in what Foundry generates for the OpenTelemetry Operator.
Fix: remove the patch from casting.yaml, then run this from the directory that contains it:
foundryctl forge -f casting.yamlTake the target from the files under pours/collectionagent/collector/ and the path from the resource under /spec, add the patch back, and run Step 4: Deploy again.
After the fix, kubectl get pods -n signoz shows the deployment collector's pod.
foundryctl cast reaches the wrong cluster or none
In Step 4: Deploy, foundryctl cast -f casting.yaml applies to another cluster or cannot reach one. Run this on the machine where you run foundryctl to see which cluster it uses:
kubectl config current-contextCause: foundryctl cast applies to the cluster of your current kubectl context.
Fix: switch to the right context with kubectl config use-context <context-name>, then run Step 4: Deploy again. Replace <context-name> with a context from kubectl config get-contexts.
After the fix, kubectl get pods -n signoz shows the deployment collector's pod on that cluster.
A workload's pods have no sidecar
In Step 4: Verify the sidecar, the kubectl get pods check prints nothing for a workload.
Cause: the workload's pods were created before the signoz-collector-sidecar resource existed, or its pod template lacks the annotation.
Fix: check that kubectl -n <your-namespace> get opentelemetrycollector signoz-collector-sidecar lists the resource and that the pod template carries the annotation, then restart the workload, for example with kubectl -n <your-namespace> rollout restart deployment/<your-workload>. Delete a Job and create it again.
After the fix, the check prints otc-container once per pod.