Skip to content

Amazon ECS

This guide covers installing the KloudMate agent on Amazon ECS so your services report traces (APM), logs, and metrics, with no changes to your application code or container images. One install script covers both ECS launch types, EC2 and Fargate, and picks the right approach for each.

If you only want to ship container logs and don’t want the agent, there’s a manual path using Fluent Bit and FireLens instead: see Amazon ECS Container Logs. The agent automates that wiring and adds APM and metrics on top.

How the agent runs depends on your launch type, because EC2 and Fargate give it very different access to the underlying host.

EC2 launch type. The EC2 container instances are self-managed, so the agent runs as an ECS daemon service: one agent task per instance. That daemon is the collector, the telemetry gateway, and eBPF monitoring for the whole instance. It collects:

  • Host metrics: CPU, memory, disk, and network for each container instance
  • Container metrics: per-container CPU, memory, network, and disk for every task on the instance
  • Container and host logs: stdout/stderr from containers plus system logs
  • APM traces: SDK auto-injection for Java, Node.js, Python, and .NET services; eBPF for Go, Rust, and everything else (see How APM works below)

Fargate launch type. There’s no host to run a daemon on, so the installer instruments each service you name. It rewrites the task definition to add a collector sidecar. For SDK runtimes, it also stages the OpenTelemetry SDKs and routes the application’s logs. Each instrumented task reports:

  • APM traces: OpenTelemetry SDK injection for Java, Node.js, Python, and .NET
  • Task metrics: CPU, memory, network, and disk for the task’s containers
  • Application logs: the app’s stdout/stderr, forwarded through FireLens to the collector

APM is language-aware, and the runtime decides how a service gets traced:

RuntimeEC2Fargate
Java, Node.js, Python, .NETSDK auto-injection (richer traces)SDK auto-injection (richer traces)
Go, Rust, and otherseBPF monitoring on the daemonLogs and metrics only, no traces

For Java, Node.js, Python, and .NET, the installer injects the OpenTelemetry SDK. This produces richer traces, such as framework spans and database statements. On EC2, it rewrites those services’ task definitions to export to the daemon on the instance. On Fargate, it adds the SDK plus a collector sidecar to the task.

For Go, Rust, and other runtimes, there’s no SDK to inject. On EC2 the daemon’s eBPF picks them up automatically, with no task-definition change. On Fargate, which can’t run eBPF, those services still get logs and metrics, but no traces.

View all collected data in these KloudMate sections:

1. Infrastructure Monitoring

  • Monitor container-instance metrics (CPU, memory, disk, network) on EC2
  • See running containers and tasks and their resource usage
  • Track availability and uptime across the cluster

Infrastructure Monitoring

2. APM & Tracing

  • Follow requests across your instrumented services
  • Break down latency, throughput, and error rates per service

APM & Tracing

3. Dashboards

  • Build custom dashboards for your ECS services, tasks, or cluster

Creating a Dashboard

4. Log Explorer

  • Search logs per container, task, or service
  • Filter by container name, severity, or timestamp
  • Correlate logs with traces and metrics to troubleshoot

Log Explorer

Run the install script once from any machine that has AWS credentials for the account (a laptop, a CI job, or AWS CloudShell). It drives the ECS API and does not run on your container hosts.

Before you start, make sure you have:

  • AWS credentials for the account and region that hold your cluster, with permission to register task definitions and update services
  • The AWS CLI and jq on the machine you run the script from
  • An ECS cluster already running your workloads
  • Network access and permissions from Before you start if your outbound traffic is restricted

Instrumenting a service runs a task-definition injection step. This happens on every Fargate install, and on any EC2 install that names services. That step needs either Docker, which runs the agent’s ECS image, or a native kmagent binary set through KM_AGENT_BIN. A daemon-only EC2 install needs neither.

Step 1: Go to Settings → Agents in your KloudMate account.

Step 2: Select Amazon ECS from the list of available integrations.

Step 3: Copy the command for your launch type and run it from a machine with AWS credentials.

This registers a daemon task definition and a daemon service, so one agent task runs on every container instance. List your Java/Node/Python/.NET services in KM_ECS_SERVICES to SDK-instrument them at the same time:

KM_API_KEY="YOUR_API_KEY" \
KM_COLLECTOR_ENDPOINT="https://otel.kloudmate.com:4318" \
KM_ECS_CLUSTER=your-cluster \
KM_ECS_LAUNCH_TYPE=ec2 \
KM_ECS_SERVICES=web,orders \
  bash -c "$(curl -fsSL https://cdn.kloudmate.com/scripts/install_ecs.sh)"

KM_ECS_SERVICES is optional on EC2. Omit it to deploy just the daemon. eBPF picks up Go and other non-SDK services automatically. Only Java/Node/Python/.NET services need the per-service task-definition rewrite for SDK traces. For any service you SDK-instrument, the daemon’s eBPF stands down, so you never get duplicate traces.

eBPF needs a privileged task with host PID and network access, which the daemon task definition already requests.

The EC2 instances also need their container-instance role to allow pulling images. The AWS-managed AmazonEC2ContainerServiceforEC2Role policy covers this. A missing role shows up as image-pull failures on the agent tasks.

This instruments each service you list, then rolls it onto a new task-definition revision:

KM_API_KEY="YOUR_API_KEY" \
KM_COLLECTOR_ENDPOINT="https://otel.kloudmate.com:4318" \
KM_ECS_CLUSTER=your-cluster \
KM_ECS_LAUNCH_TYPE=fargate \
KM_ECS_SERVICES=web,orders \
  bash -c "$(curl -fsSL https://cdn.kloudmate.com/scripts/install_ecs.sh)" -- --yes

KM_ECS_SERVICES is required on Fargate. The -- --yes at the end skips the per-service confirmation prompt. Drop it if you’d rather approve each service before it’s rolled onto the new revision. All containers in a Fargate awsvpc task share localhost, so the injected SDK sends telemetry to localhost:4318, where the collector sidecar receives it.

The bundled .NET and Python instrumentation is glibc-only. On an Alpine or other musl-based image it won’t load, so use a glibc-based image for those two runtimes. Node.js and Java are unaffected.

Keep your API key out of the task definition

Section titled “Keep your API key out of the task definition”

By default, the script writes KM_API_KEY inline into the task definition. That key is a workspace-wide ingest credential. Once it’s inline, anyone with ecs:DescribeTaskDefinition can read it, and it’s visible in the console and CloudTrail.

Set these as environment variables on the command:

VariableRequiredDefaultNotes
KM_API_KEYYesnoneYour workspace ingest key.
KM_ECS_CLUSTERYesnoneTarget ECS cluster name.
KM_ECS_LAUNCH_TYPEYesnoneec2 or fargate.
KM_ECS_SERVICESFargate; optional on EC2noneComma-separated services to SDK-instrument (Java/Node/Python/.NET).
KM_COLLECTOR_ENDPOINTNohttps://otel.kloudmate.com:4318Where telemetry is sent.
KM_REGIONNoaws configure get regionAWS region for the ECS API, and the awslogs region when KM_ECS_LOG_GROUP is set.
KM_ECS_LOG_GROUPNononeCloudWatch log group for the agent’s own sidecar and daemon logs, for example /kmagent/ecs. Off by default: nothing is written to CloudWatch (no logs:* IAM, no extra cost), and the collector self-ships its errors to KloudMate instead. Setting it needs the permissions in the note below.
KM_API_KEY_SECRET_ARNNononeReference the key from Secrets Manager instead of inlining it.
KM_EBPF_ENABLEDNotrueEC2 daemon eBPF monitoring (traces Go and other non-SDK services).
KM_AGENT_BINNononePath to a native kmagent binary for the injection step, so Docker isn’t needed.
KM_DAEMON_FAMILYNokm-agent-ec2EC2 daemon task-definition family.
KM_EC2_IMAGE / KM_ECS_IMAGE / KM_FIRELENS_IMAGENoPinned defaultsOverride the agent or FireLens images.

Two flags are passed after -- rather than as environment variables: --yes skips the Fargate confirmation prompt, and --dry-run prints the task definitions without registering them.

Capture the agent’s own logs in CloudWatch (optional)

Section titled “Capture the agent’s own logs in CloudWatch (optional)”

By default, the agent’s sidecars and EC2 daemon don’t write their own container logs to CloudWatch. That means no logs:* IAM is required, and there’s no extra CloudWatch cost. You can still see a running agent: the collector ships its own error logs to KloudMate, where you’ll find them under service.name=kmagent in Log Explorer.

Set KM_ECS_LOG_GROUP (for example /kmagent/ecs) to also send the sidecars’ and daemon’s own logs to CloudWatch. This mainly helps catch sidecar startup or staging failures on Fargate, where there’s no docker logs to fall back on.

Attach an inline policy for the three actions on that group, or create the group yourself before you run the installer:

{
  "Effect": "Allow",
  "Action": ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"],
  "Resource": "arn:aws:logs:*:*:log-group:/kmagent/ecs:*"
}

The one-line script handles services in bulk. For a per-service view, or to instrument a single service without Docker, the kmagent binary has an ecs subcommand set. Use it to check whether a service is instrumented. This is useful for Fargate tasks, which never register in the agents list.

Summarize every task-definition family in a region and its instrumentation state (which components are attached, the detected language):

kmagent ecs status --region us-east-1

Inspect a single family:

kmagent ecs discover --task-definition your-service --region us-east-1

Both are read-only: they describe task definitions and report, without changing anything. To instrument one service end to end (describe, inject, register a new revision, then optionally roll the service onto it):

kmagent ecs instrument \
  --task-definition your-service \
  --service your-service --cluster your-cluster \
  --region us-east-1

instrument takes --enable-apm=false to skip SDK injection (EC2 apps still fall back to eBPF), --enable-logs=false to skip Fargate log routing, --language to force a runtime the detector missed, and --dry-run to preview the task definition.

The two launch types appear differently in KloudMate:

  • EC2 daemon: each container instance appears in Settings → Agents as Amazon ECS, one row per instance. Its APM tab has no per-service toggle. Instead, it points you to the kmagent ecs discover and instrument commands and explains the language-aware split (SDK for Java/Node/Python/.NET, eBPF for the rest).
  • Fargate tasks are autonomous: each collector sidecar ships telemetry on its own and does not appear as an agent row. Find that data in APM, Log Explorer, and Infrastructure keyed by service name. The install flow’s verify step accounts for this, so it won’t wait for a Fargate check-in that never comes.

The agent sends your ECS logs to KloudMate as part of the install. On EC2 the daemon reads container and host logs directly. On Fargate it adds a FireLens log router to each instrumented service. Either way, this replaces the manual Fluent Bit and FireLens setup and adds APM and metrics alongside it.

To collect additional application log files with the agent, see Collect File Logs with KloudMate Agent.

  • Open Infrastructure Monitoring to see your container instances, tasks, and their metrics
  • Use APM & Tracing to follow requests across your instrumented services
  • Investigate container and application logs in Log Explorer
  • Configure alerts for cluster, task, or service thresholds
  • If an agent looks unhealthy, check its own error logs: see See the agent’s own errors

The injector is idempotent. Re-running the script strips its previous additions and re-injects with your current settings. Changing the collector endpoint or upgrading the agent image then applies cleanly, instead of stacking duplicate sidecars. Turning logs off on a later run also reverts the FireLens driver it added, leaving no leftover configuration.

There’s no one-line uninstaller. Remove the agent the same way it was added, through the ECS API.

EC2 (daemon service): delete the agent’s daemon service. This stops and removes the agent task on every container instance.

aws ecs delete-service --cluster your-cluster --service km-agent --force

Instrumented services (EC2 or Fargate): roll each SDK-instrumented service back to the task-definition revision it used before instrumentation.

aws ecs update-service \
  --cluster your-cluster \
  --service web \
  --task-definition web:PREVIOUS_REVISION

Replace PREVIOUS_REVISION with the revision number from before you ran the installer. After that, the service no longer runs the collector sidecar or SDK injection. Services that were only traced by eBPF have no task-definition changes to revert. They stop being traced once the daemon service is gone.