Run Gateway Benchmark
Overview
This skill drives the benchmark harness in
to measure Flex Gateway throughput,
latency, and resource use under configurable API counts and policies. It provisions a
dedicated EKS cluster, deploys Flex + an upstream echo service, runs a k6
, exports
Grafana dashboards as PNGs, and emits a self-contained Markdown report per run.
Detailed architecture, dashboards, idempotency design, and design rationale are documented
in
references/ARCHITECTURE.md
. Read it before extending the harness; this skill assumes it
as background.
mermaid
flowchart TD
Start{What do you want to do?}
Start -->|First-time setup| FT[Prerequisites + Registration + Push Upstream]
Start -->|Provision infra| UP["make up — EKS cluster"]
Start -->|Deploy + run a single benchmark| RUN["make benchmark or make run"]
Start -->|Re-run with new scenario knobs| KNOB[Edit env + make run]
Start -->|Retrieve results| REP[reports/RUN_ID/]
Start -->|Reset between sessions| CLEAN["make clean-deployment"]
Start -->|Stop AWS billing| DOWN["make down — destructive"]
Safety and Cost Guardrails
The harness provisions billable AWS infrastructure (EKS control plane, NAT gateway, EBS
volumes, c6i.2xlarge nodes, ECR). Two operations are destructive and must be confirmed with
the user before executing — never run them autonomously based on inferred intent:
| Operation | Effect | Confirm before running |
|---|
| Read-only checks on CLIs, docker daemon, AWS auth, , registration, and connectivity; reports remediation per gap | No — safe; never mutates state |
make prepare-registration
| Generates .run/registration/registration.yaml
and, when includes , prompts for / and writes them to (keeps existing values unless ) | Confirm before re-running with (rotates gateway identity, forces a Flex redeploy) |
| Creates VPC + EKS + ECR; starts AWS billing | Yes — confirm region, cluster name, and that costs are expected |
| Destroys all infra including the cluster, ECR repository contents, and Terraform state references | Yes — confirm the user has retrieved any reports they want to keep |
| Removes Flex + upstream + k6 TestRuns, keeps cluster | Safe to run between runs; preserves billing-relevant infra |
If
is set in
,
runs
automatically at the end
of the pipeline. Verify this is the user's intent before invoking
with that
flag set.
Step 1 — Verify prerequisites
All commands run from
skills/omni-gateway/omni-gateway-benchmark/
(where the
lives — the shell scripts the Makefile calls are under
).
Run the bundled preflight; it covers every check below in one pass and prints a remediation
command for each gap:
- Required CLIs present: , , , , (with ),
, , , , , , .
- Docker engine — client + server versions reported, and confirms the daemon
is reachable on the current context.
- AWS identity (
aws sts get-caller-identity
), the resolved , and
loaded from .
- exists and
.run/registration/registration.yaml
is present.
- When includes , both and are
non-empty.
- Egress to
flex-packages.anypoint.mulesoft.com
(the Helm chart source).
Exits non-zero if any check fails — wire it into your shell pipeline (
make preflight && make up
) so a missing prerequisite stops the run before AWS billing starts.
The AWS principal must have permissions to create EC2, EKS, VPC, ECR, IAM, and EBS resources
in the target region.
Step 2 — Configure the environment
Copy the example
and fill in scenario knobs:
Edit
based on the scenario the user wants. Reference table — the harness reads every
variable below:
| Variable | Default | Description |
|---|
| | AWS region for the EKS cluster |
| | EKS cluster + VPC name prefix |
| | Flex Gateway Helm chart and image version |
| | Override to use a private mirror |
| (empty → ) | Override to decouple tag from version |
| | Number of resources to create |
| rate-limit,client-id-enforcement
| Comma-list of policies to attach per API |
| | Target requests per second (constant-arrival-rate) |
| | Pre-allocated k6 virtual users |
| | k6 test duration (e.g., , ) |
| (empty) | Required when is in |
| (empty) | Required when is in |
| | Local port used by export-grafana-snapshot.sh
|
| | Set to to auto-run after |
| .run/registration/registration.yaml
| Path to Flex local-mode registration |
Validation checklist before continuing:
- If contains , both and are set.
- If (empty), no auth headers are required.
- matches a chart version published at
flex-packages.anypoint.mulesoft.com/helm
.
Step 3 — Generate the Flex registration artifact (one-time)
The benchmark runs Flex in local mode. Use the bundled target — it generates the artifact
once and, when
includes
, prompts for
/
and writes them into
:
bash
make prepare-registration
Behavior:
- Skips registration generation if
.run/registration/registration.yaml
already exists. To
rotate the gateway identity (forces a Flex redeploy), re-run with FORCE=1 make prepare-registration
— the existing file is backed up to first.
- Skips the credential prompt unless contains .
- Skips overwriting existing non-empty / unless .
- Supports non-interactive use:
CLIENT_ID=... CLIENT_SECRET=... make prepare-registration
.
Manual equivalent (use only if
is being driven outside the harness):
bash
flexctl registration create \
--connected=false \
--output-directory=.run/registration
Do not commit
.run/registration/registration.yaml
— it is gateway identity material and
is gitignored.
Step 4 — Build and push the upstream image (one-time)
The k6 driver hits an in-cluster echo server. The image must exist in ECR before
runs:
This builds for
via
(cross-compiling on Apple Silicon) and pushes
to the ECR repository created by Terraform. If
has not yet run, this fails because
the ECR repo does not exist — provision infra first (Step 5).
Skip condition: If
has already been run and the upstream image is unchanged,
this step is a no-op. The deploy-upstream hash check will skip redeployment if the rendered
manifest matches the live state.
Step 5 — Provision infrastructure (destructive on AWS billing)
Confirm with the user before running. This creates a VPC, EKS cluster, ECR, and installs the
observability + k6-operator Helm releases:
Expected duration: 15–25 minutes for a fresh cluster. Re-running on an existing cluster is
idempotent and finishes in seconds.
After completion, verify the cluster is reachable:
bash
aws eks update-kubeconfig --region "$AWS_REGION" --name "$CLUSTER_NAME"
kubectl get nodes
You should see two
nodes (
, tainted) and three
nodes
(
,
).
Step 6 — Deploy Flex + upstream
These targets are idempotent and content-addressed via SHA-256 hashes stored as pod template
annotations / Deployment labels. Re-running with unchanged config is a no-op:
bash
make deploy-upstream # bench-upstream Service + Deployment in 'default' namespace
make deploy-flex # Flex Gateway Helm release + CRD resources in 'flex' namespace
renders
from
assets/config/flex-config-header.yaml
+
assets/config/snippets/api-instance.yaml
+
assets/config/policies/<policy>.yaml
, hashes it together with
the image reference, and skips
if the hash matches the live deployment. Config
changes apply via
to CRDs without restarting Flex pods.
Step 7 — Run the benchmark
A single load test, including report generation:
This sequences: render
→ create the per-run ConfigMap → apply the k6
CRD → poll until
(default timeout 1800s) → port-forward Grafana and export PNGs →
emit the Markdown report.
defaults to a UTC timestamp (
). Override it for a stable identifier:
bash
RUN_ID=baseline-1.13.0-rl make run
For the full pipeline (
→ deploys →
, optionally
if
):
Re-running with different scenario knobs does not require redeploying:
bash
RPS=2000 VUS=400 DURATION=5m make run
N_APIS=50 POLICIES= make run # 50 APIs, no policies
FLEX_VERSION=1.14.0 make deploy-flex && make run
If a
is already in flight in the
namespace, the new run will
fail with a name collision — wait for the previous run to finish or run
to clear stale TestRuns.
Step 8 — Retrieve results
Each run persists artifacts under
:
| Artifact | Path | Notes |
|---|
| Markdown report | reports/<RUN_ID>/flex<VERSION>_n<N_APIS>_<POLICIES>_rps<RPS>_<RUN_ID>.md
| Scenario params, raw k6 metrics (, , , ), Grafana deep-links |
| Dashboard PNGs | reports/<RUN_ID>/<DashboardTitle>.png
| 1600×900, one per dashboard (Flex / Envoy, Flex / Pods, k6 / Driver, plus default kube-prometheus-stack boards) |
Ephemeral render output lives under
(
,
,
,
) and is safe to delete.
To re-export Grafana for the most recent run without re-running k6:
To open Grafana interactively while a run is in flight (anonymous Viewer is
enabled; no login required):
bash
make watch # opens port-forward + prints live URLs + opens k6 dashboard
# or, manually:
kubectl -n monitoring port-forward svc/kps-grafana 3000:80
# → http://localhost:3000
accepts
to filter the k6 / Driver dashboard to a
specific run, and
to skip the auto-open.
Step 9 — Clean up
Two cleanup paths, ordered by aggressiveness:
bash
make clean-deployment # Remove Flex + upstream + k6 TestRuns; keep cluster + observability
make down # terraform destroy — destroys everything (confirm with user first)
is safe between sessions and preserves the cluster cost (~$0.10/hr for the
EKS control plane plus node-group on-demand pricing).
stops all AWS billing for
this environment but is irreversible — any reports not copied out of
will remain
locally, but ECR images and cluster state are gone.
Scenario Cookbook
Common parameter combinations:
| Goal | Configuration |
|---|
| Baseline, no policies | N_APIS=10 POLICIES= RPS=1000 VUS=200 DURATION=2m
|
| Rate-limit only | POLICIES=rate-limit RATE_LIMIT_RPS=500
|
| Client-ID enforcement only | POLICIES=client-id-enforcement CLIENT_ID=... CLIENT_SECRET=...
|
| Both policies, high fan-out | N_APIS=50 POLICIES=rate-limit,client-id-enforcement RPS=2000 VUS=400 DURATION=5m
|
| Version comparison | Run twice with and ; both make deploy-flex && make run
; diff the two files |
The k6 thresholds in the rendered scenario are hard failures:
,
,
. A run that exceeds them will surface in the report's
line — the harness still completes and reports.
Troubleshooting
| Problem | Likely cause | Fix |
|---|
| fails with | AWS principal lacks EKS/VPC/ECR/IAM permissions | Attach a policy granting the missing actions; verify with aws sts get-caller-identity
|
fails with repository does not exist
| not yet run; ECR repo missing | Run first, then retry |
| fails pulling the chart | not published at the public chart repo | Check helm search repo flex-gateway/flex-gateway --versions
; pick a published version |
| blocks past the 1800s timeout | k6 TestRun stuck in or ; missing image; namespace not ready | kubectl -n k6-operator-system get testruns,pods
; inspect kubectl describe testrun <name>
|
| Report missing PNGs | Grafana port-forward race or image-renderer plugin unavailable | Re-run ; if persistent, check kubectl -n monitoring logs deploy/kps-grafana
for the renderer container |
| returns 401 on every request | / empty or do not match a Contract resource | Set both in ; verify the Contract resource exists for the API instance |
| Flex pod in after | Missing or stale secret | Regenerate via flexctl registration create --connected=false
; rerun |
| annotation never updates | Hash collision (rare) or annotation patch failed | Force redeploy: kubectl -n flex annotate deploy flex-gateway bench/spec-hash- --overwrite
then |
| collision causes TestRun apply to fail | Previous TestRun with same still in the namespace | or kubectl -n k6-operator-system delete testrun <name>
|
For deeper triage of the gateway itself (not the harness), invoke
or
.
Available Scripts
The
targets above are the supported entry points. They delegate to the scripts in
, listed here for reference when debugging the harness or composing steps manually.
Every script reads its configuration from
and accepts
for usage:
| Script | Driven by | Purpose |
|---|
| | Read-only check of every CLI, daemon, credential, and one-time artifact before any run |
| make prepare-registration
| Generate the local-mode Flex registration artifact; collect / when needed |
| | Build the upstream echo image for and push to ECR |
| | Deploy (or hash-skip) the Service + Deployment |
| | Render config, then deploy (or hash-skip) the Flex Gateway Helm release + CRDs |
| | Assemble from header + API-instance + policy snippets |
| | Block until the Flex Gateway deployment finishes rolling out |
| | Render the k6 from scenario knobs |
| | Create the per-run k6 , wait for it, and export the Grafana snapshot |
| | Poll a k6 until it reaches (or times out) |
export-grafana-snapshot.sh
| | Port-forward Grafana and export dashboard PNGs for a time window |
| | Parse k6 summary from runner logs and emit the per-run Markdown report |
| | Open a Grafana port-forward and print live dashboard URLs |
| | Tear down per-run workloads while keeping the cluster, observability, and k6-operator |
Related Jobs
- — install Flex on Linux/Docker/Kubernetes (this skill provisions its
own EKS install for benchmarking; use for production deployments)
- — validate the rendered before
- — parse Flex pod logs when a benchmark surfaces unexpected failures
- — triage non-harness gateway issues observed during a run