Skip to content
LoadStrike
Portal

Search LoadStrike

GOOD PLACES TO START

ClusterCode 60 / 69

EKS Coordinator And Agents

Set up finite EKS coordinator and Indexed Agent Jobs with matching identities, NATS connectivity, runner credentials and retained reports.

What this page helps you do

What this page helps you do

Set up finite EKS coordinator and Indexed Agent Jobs with matching identities, NATS connectivity, runner credentials and retained reports.

Who this is for

Teams moving from one machine to coordinator-and-agent execution or tighter workload targeting.

Prerequisites

  • A scenario that already works in a single-node run

By the end

A clearer cluster topology and the fields that must line up across nodes.

Use this page when

Use this page when execution topology, partitioning, or targeting changes how the run should be distributed.

Visual guide

Cluster deployment flow showing image build, registry, EKS pods, NATS, and merged report.
The same image can run as coordinator or agent, with EKS and NATS providing the deployment and coordination path.

Guide

Architecture

Use one coordinator Job and a finite Indexed Agent Job. Each standalone Agent waits for one signed run, executes its assignment and exits. A continuously restarted Deployment can leave idle replacement Agents after completion.

Runnable Images

Package your executable harness and its normal production SDK/runtime dependencies. The C# example uses a .NET 8 console entry point; other SDKs need their own entry points. A unit test assembly is not an application. Use the same verified immutable build on all nodes; keyless Go Agents need the compatible signed runtime preinstalled.

Explicit Configuration

Your application must read the deployment variables and pass them to the runner APIs. The sample names are not automatically bound by the SDK. Match SessionId, ClusterId, AgentGroup and scenario definitions; remote V2 requires unique stable AgentId values and the exact ExpectedAgentIds roster.

One Run Per Job

Set Indexed Job completions and parallelism to the expected Agent count. Ensure every Agent listener is ready before starting the coordinator. Wait for coordinator and agent Job Complete, inspect exit codes and diagnostics, and use new Job names and a new SessionId for each run.

NATS And Security

Use a reachable authenticated NATS broker and configure certificate trust for TLS in each language runtime. Keep broker credentials in a Secret and the entitled runner key in a separate coordinator-only Secret. Restrict namespace access and allow only required broker, licensing, sink and target network paths. Agents validate coordinator-issued authorization; do not give them the runner key.

EKS Access And Storage

Configure node or Fargate permissions to pull your immutable ECR image. AWS API calls from targets or sinks need supported AWS workload credentials, using EKS Pod Identity or IRSA as appropriate; image pull and pod API permissions are separate. Provision a suitable CSI storage class before creating the coordinator report claim.

Reports And Sinks

The coordinator writes the combined HTML, TXT, CSV and Markdown report set. Configured remote-agent sinks receive agent data; coordinator sinks receive the merged result. Final SinkErrors and DisabledSinks include child and coordinator failures. ReportingComplete describes raw observation delivery, not success of every independent final sink callback.

Artifact Retention

Retain coordinator artifacts on its PVC or export them before cleanup. Retrieve a completed Job report through a separate retention Pod or exporter. Use distinct node paths for agent JSONL output, or remote sinks; an RWO coordinator claim is not shared multi-node agent storage.

Reporting Limits

Distributed results retain aggregate and node statistics; temporal history can be unavailable and is disclosed in reports. Do not infer a merged latency time series from final counters. Size in-flight capacity and CPU/memory for offered load, and inspect explicit generator drops separately from application failures.

Validation Scope

Docker and local Kubernetes process tests verify SDK execution, Job completion and artifact delivery for the tested builds. They do not verify your EKS IAM, CNI policies, registry access, multi-node storage, broker TLS trust or external vendor credentials; validate those in the target cluster before a production load run.

Cluster setup samples

The executable harness explicitly maps environment inputs to runner APIs. Give every new run a fresh SESSION_ID and use that same value on the coordinator and all agents. The shared Jobs use stable indexed Agent identities, coordinator-only licensing and retained report storage.

If you run these examples locally, add a valid runner key before execution starts. Set it with WithRunnerKey("...") or the config key LoadStrike:RunnerKey.

Runnable Container Harness

using LoadStrike;

public static class LoadStrikeHarness
{
    public static int Main()
    {
        string Required(string name) => Environment.GetEnvironmentVariable(name)
            ?? throw new InvalidOperationException($"Missing {name}");
        var role = Enum.Parse<LoadStrikeNodeType>(Required("NODE_ROLE"));
        if (role is not (LoadStrikeNodeType.Agent or LoadStrikeNodeType.Coordinator))
            throw new InvalidOperationException("NODE_ROLE must be Agent or Coordinator");
        var scenario = LoadStrikeScenario.Create("checkout", _ =>
            Task.FromResult(LoadStrikeResponse.Ok(statusCode: "200")))
            .WithoutWarmUp()
            .WithLoadSimulations(LoadStrikeSimulation.IterationsForInject(10, TimeSpan.FromSeconds(1), 100));
        var runner = LoadStrikeRunner.RegisterScenarios(scenario)
            .UseLoadEngineV2().WithMaxInFlight(1000)
            .WithSessionId(Required("SESSION_ID")).WithClusterId(Required("CLUSTER_ID"))
            .WithAgentGroup(Required("AGENT_GROUP")).WithNatsServerUrl(Required("NATS_URL"))
            .WithNodeType(role).WithClusterCommandTimeout(TimeSpan.FromSeconds(180))
            .WithReportFolder(Environment.GetEnvironmentVariable("REPORT_DIR") ?? "/reports")
            .WithReportFormats(LoadStrikeReportFormat.Html, LoadStrikeReportFormat.Txt,
                LoadStrikeReportFormat.Csv, LoadStrikeReportFormat.Md);
        if (role == LoadStrikeNodeType.Agent)
            runner = runner.WithAgentId("agent-" + Required("JOB_COMPLETION_INDEX"));
        else
            runner = runner.EnableLocalDevCluster(false).WithAgentsCount(2)
                .WithExpectedAgentIds("agent-0", "agent-1").WithRunnerKey(Required("LOADSTRIKE_RUNNER_KEY"));
        var result = runner.Run();
        Console.WriteLine($"Requests={result.AllRequestCount}; sink errors={result.SinkErrors.Count}");
        return result.AllFailCount == 0 && result.SinkErrors.Count == 0 ? 0 : 1;
    }
}

One-Run Kubernetes Jobs (Map Inputs in Your Application)

ParameterDescription
Indexed agent Job

Starts two finite Agent processes with stable agent-0 and agent-1 identities. Each exits after its signed assignment; both must reach Job Complete.

Coordinator Job

Carries the runner key through SecretKeyRef, assigns work over reachable NATS and writes merged reports. Agent pods have no runner key.

Application inputs

The sample Program.cs explicitly reads these variables. Use a fresh SESSION_ID for each new run, shared by its coordinator and agents. Other SDK harnesses must map equivalent role, session, roster and transport inputs to their own runner APIs.

Retained reports

Only the coordinator mounts the RWO report claim. Use a retention Pod or artifact exporter after Job completion; use separate paths or remote destinations for agent sinks.

# Create the namespace and Secrets securely before applying the Jobs.
# loadstrike-coordinator-key: key = existing entitled runner key (coordinator only).
# loadstrike-nats: url = reachable authenticated NATS URL; configure TLS trust for each runtime.
# Replace the image with your immutable tested harness image. Change SESSION_ID for every run.
apiVersion: v1
kind: ConfigMap
metadata:
  name: loadstrike-runtime
  namespace: loadstrike
data:
  SESSION_ID: orders-run-20261004-001
  CLUSTER_ID: orders-cluster
  AGENT_GROUP: perf-agents
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: loadstrike-reports
  namespace: loadstrike
spec:
  accessModes: [ReadWriteOnce]
  resources:
    requests:
      storage: 2Gi
# Uses the cluster default storage class. On EKS configure a suitable CSI driver/class first.
# This claim is mounted only by the coordinator, not by agents on different worker nodes.
---
apiVersion: batch/v1
kind: Job
metadata:
  name: loadstrike-agents
  namespace: loadstrike
spec:
  completionMode: Indexed
  completions: 2
  parallelism: 2
  backoffLimit: 0
  activeDeadlineSeconds: 600
  template:
    spec:
      restartPolicy: Never
      automountServiceAccountToken: false
      securityContext:
        runAsNonRoot: true
        runAsUser: 10001
        runAsGroup: 10001
        fsGroup: 10001
      containers:
      - name: agent
        image: <aws-account-id>.dkr.ecr.<region>.amazonaws.com/loadstrike-harness:<immutable-tag>
        envFrom:
        - configMapRef:
            name: loadstrike-runtime
        env:
        - name: NODE_ROLE
          value: Agent
        - name: JOB_COMPLETION_INDEX
          valueFrom:
            fieldRef:
              fieldPath: metadata.annotations['batch.kubernetes.io/job-completion-index']
        - name: NATS_URL
          valueFrom:
            secretKeyRef:
              name: loadstrike-nats
              key: url
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop: [ALL]
        resources:
          requests: {cpu: "500m", memory: "512Mi"}
          limits: {cpu: "2", memory: "2Gi"}
---
apiVersion: batch/v1
kind: Job
metadata:
  name: loadstrike-coordinator
  namespace: loadstrike
spec:
  backoffLimit: 0
  activeDeadlineSeconds: 600
  template:
    spec:
      restartPolicy: Never
      automountServiceAccountToken: false
      securityContext:
        runAsNonRoot: true
        runAsUser: 10001
        runAsGroup: 10001
        fsGroup: 10001
      containers:
      - name: coordinator
        image: <aws-account-id>.dkr.ecr.<region>.amazonaws.com/loadstrike-harness:<immutable-tag>
        envFrom:
        - configMapRef:
            name: loadstrike-runtime
        env:
        - name: NODE_ROLE
          value: Coordinator
        - name: NATS_URL
          valueFrom:
            secretKeyRef:
              name: loadstrike-nats
              key: url
        - name: LOADSTRIKE_RUNNER_KEY
          valueFrom:
            secretKeyRef:
              name: loadstrike-coordinator-key
              key: key
        - name: REPORT_DIR
          value: /reports
        volumeMounts:
        - name: reports
          mountPath: /reports
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop: [ALL]
        resources:
          requests: {cpu: "500m", memory: "512Mi"}
          limits: {cpu: "2", memory: "2Gi"}
      volumes:
      - name: reports
        persistentVolumeClaim:
          claimName: loadstrike-reports