Sign inSign up

cbaugus/rust_loadtest

By cbaugus

•Updated 2 days ago

High-performance Rust HTTP load tester with multiple load models and Prometheus metrics

Buildkit cache
Image
Developer tools
Monitoring & observability
0

10K+

cbaugus/rust_loadtest repository overview

⁠Rust HTTP Load Testing Tool

A high-performance, Rust-based HTTP load testing tool designed for comprehensive service performance testing. Generate realistic traffic patterns, collect Prometheus metrics, and stress-test your endpoints with various load profiles.

⁠Quick Start

# Standard Ubuntu-based image - great for development and debugging
docker run --rm \
  -e TARGET_URL="https://your-api.com/endpoint" \
  -e LOAD_MODEL_TYPE="Concurrent" \
  -e NUM_CONCURRENT_TASKS="50" \
  -e TEST_DURATION="5m" \
  cbaugus/rust-loadtester:latest

# Chainguard static image - production-ready, minimal CVEs
docker run --rm \
  -e TARGET_URL="https://your-api.com/endpoint" \
  -e LOAD_MODEL_TYPE="Rps" \
  -e TARGET_RPS="200" \
  -e NUM_CONCURRENT_TASKS="100" \
  -e TEST_DURATION="10m" \
  cbaugus/rust-loadtester:latest-Chainguard

⁠Available Image Variants

⁠Standard Image (Ubuntu-based)

Tags: latest, main, <branch-name>

  • Size: ~80-100 MB
  • Base: Ubuntu latest
  • Best for: Development, testing, debugging
  • Features: Full shell access, standard utilities, easy troubleshooting

Tags: latest-Chainguard, main-Chainguard, <branch-name>-Chainguard

  • Size: ~10-15 MB (75% smaller)
  • Base: Chainguard static (distroless)
  • Best for: Production deployments, security-conscious environments
  • Features: Zero to minimal CVEs, no shell, static binary, maximum security posture

⁠Key Features

ā šŸš€ Multiple Load Models
  • Concurrent: Fixed number of concurrent requests at maximum speed
  • RPS: Constant target requests per second
  • RampRps: Gradual ramp-up to peak, sustain, then ramp-down
  • DailyTraffic: Complex daily traffic patterns with multiple phases
ā šŸ“Š Built-in Monitoring
  • Prometheus metrics exposed on port 9090
  • Real-time request tracking
  • Status code distribution
  • Concurrent request monitoring
ā šŸ”’ Security Features
  • HTTPS support with TLS verification control
  • mTLS (mutual TLS) support
  • Custom headers including authentication tokens
  • Minimal attack surface with Chainguard static image
ā āš™ļø Advanced Configuration
  • GET and POST request support
  • JSON payload support for POST requests
  • Custom DNS resolution override
  • Flexible duration formats (minutes, hours, days)

⁠Common Use Cases

⁠Load Testing a REST API
docker run --rm \
  -e TARGET_URL="https://api.example.com/users" \
  -e REQUEST_TYPE="GET" \
  -e LOAD_MODEL_TYPE="Rps" \
  -e TARGET_RPS="500" \
  -e NUM_CONCURRENT_TASKS="100" \
  -e TEST_DURATION="15m" \
  cbaugus/rust-loadtester:latest-Chainguard
⁠Testing Login Endpoint with JSON
docker run --rm \
  -e TARGET_URL="https://api.example.com/login" \
  -e REQUEST_TYPE="POST" \
  -e SEND_JSON="true" \
  -e JSON_PAYLOAD='{"username":"testuser","password":"testpass"}' \
  -e LOAD_MODEL_TYPE="Concurrent" \
  -e NUM_CONCURRENT_TASKS="20" \
  -e TEST_DURATION="10m" \
  cbaugus/rust-loadtester:latest
⁠Simulating Daily Traffic Patterns
docker run --rm \
  -e TARGET_URL="https://your-service.com/api" \
  -e LOAD_MODEL_TYPE="DailyTraffic" \
  -e DAILY_MIN_RPS="10" \
  -e DAILY_MID_RPS="200" \
  -e DAILY_MAX_RPS="1000" \
  -e DAILY_CYCLE_DURATION="24h" \
  -e NUM_CONCURRENT_TASKS="200" \
  -e TEST_DURATION="48h" \
  cbaugus/rust-loadtester:latest-Chainguard
⁠Using Custom Headers (API Keys, Auth Tokens)
docker run --rm \
  -e TARGET_URL="https://api.example.com/protected" \
  -e CUSTOM_HEADERS="Authorization: Bearer your_token,X-Api-Key:your_key" \
  -e LOAD_MODEL_TYPE="Concurrent" \
  -e NUM_CONCURRENT_TASKS="50" \
  -e TEST_DURATION="5m" \
  cbaugus/rust-loadtester:latest
⁠Ramp Testing (Gradual Load Increase)
docker run --rm \
  -e TARGET_URL="https://api.example.com/endpoint" \
  -e LOAD_MODEL_TYPE="RampRps" \
  -e MIN_RPS="50" \
  -e MAX_RPS="500" \
  -e NUM_CONCURRENT_TASKS="150" \
  -e TEST_DURATION="15m" \
  cbaugus/rust-loadtester:latest-Chainguard

⁠Essential Environment Variables

VariableRequiredDefaultDescription
TARGET_URLYes-Full URL of the endpoint to test
LOAD_MODEL_TYPEYes-Load model: Concurrent, Rps, RampRps, or DailyTraffic
NUM_CONCURRENT_TASKSNo10Maximum concurrent requests
TEST_DURATIONNo2hTest duration (e.g., 10m, 1h, 3d)
REQUEST_TYPENoGETHTTP method: GET or POST
SKIP_TLS_VERIFYNofalseSkip TLS certificate verification
CLUSTER_NODE_IDNohostnameNode identifier used in metrics labels
CLUSTER_REGIONNodefaultRegion label used in metrics and health output
CLUSTER_HEALTH_ADDRNo0.0.0.0:8080Bind address for the live control HTTP API
LOG_FORMATNoprettyLog output format: json for structured GCP/FluentBit logs, any other value for human-readable
RUST_LOGNorust_loadtest=infoLog level filter (e.g. rust_loadtest=warn,hyper=error,reqwest=error)
⁠Load Model Specific Variables

RPS Model:

  • TARGET_RPS: Target requests per second

RampRps Model:

  • MIN_RPS: Starting/ending RPS
  • MAX_RPS: Peak RPS
  • RAMP_DURATION: Total ramp profile duration

DailyTraffic Model:

  • DAILY_MIN_RPS: Base load (night-time)
  • DAILY_MID_RPS: Mid-level load (afternoon)
  • DAILY_MAX_RPS: Peak load (morning rush)
  • DAILY_CYCLE_DURATION: Duration of one full cycle

⁠Monitoring with Prometheus

Access metrics at http://<container-host>:9090/metrics

# View metrics
curl http://localhost:9090/metrics

# Example metrics available:
# - loadtest_requests_total
# - loadtest_status_codes
# - loadtest_concurrent_requests

⁠mTLS Support

docker run --rm \
  -v /local/path/to/client.crt:/etc/ssl/certs/client.crt \
  -v /local/path/to/client.key:/etc/ssl/private/client.key \
  -e TARGET_URL="https://secure-api.com/endpoint" \
  -e CLIENT_CERT_PATH="/etc/ssl/certs/client.crt" \
  -e CLIENT_KEY_PATH="/etc/ssl/private/client.key" \
  -e LOAD_MODEL_TYPE="Concurrent" \
  -e NUM_CONCURRENT_TASKS="50" \
  -e TEST_DURATION="10m" \
  cbaugus/rust-loadtester:latest-Chainguard

Note: Private keys must be in PKCS#8 format. Convert if needed:

openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt \
  -in original.key -out pkcs8.key

⁠Structured Logging (GCP / FluentBit)

Set LOG_FORMAT=json to emit one structured JSON object per log line instead of human-readable text. Required for FluentBit to unpack fields into GCP Cloud Logging jsonPayload so they are indexed, filterable, and priced as structured logs.

docker run --rm \
  -e LOG_FORMAT=json \
  -e RUST_LOG="rust_loadtest=warn,hyper=error,reqwest=error" \
  -e TARGET_URL="https://api.example.com/endpoint" \
  -e LOAD_MODEL_TYPE="Rps" \
  -e TARGET_RPS="200" \
  cbaugus/rust_loadtest:latest

Example JSON log line:

{"timestamp":"2026-03-16T20:39:32.285Z","level":"WARN","target":"rust_loadtest::executor","fields":{"step":"GET /dashboard","status":404,"elapsed_ms":312}}

RUST_LOG accepts per-crate filters — setting hyper=error,reqwest=error suppresses HTTP client noise and significantly reduces log volume and cost.

⁠Advanced Features

⁠Custom DNS Resolution

Override DNS for specific testing scenarios:

-e RESOLVE_TARGET_ADDR="example.com:192.168.1.50:8080"
⁠Header Value Escaping

Escape commas in header values with backslash:

-e CUSTOM_HEADERS="Keep-Alive:timeout=5\,max=200"
⁠JSON Payloads

Send JSON data with POST requests:

-e SEND_JSON="true" \
-e JSON_PAYLOAD='{"key":"value","nested":{"data":"here"}}'
⁠Large Payload / Upload Testing (bodySize)

Stress-test upload endpoints or request-body parsing by sending a synthetic payload of a specified size on every request — no need to inline large strings in your config.

Supported units: B, KB, MB

scenarios:
  - name: "Upload stress test"
    weight: 100
    steps:
      - name: "POST 1MB body"
        request:
          method: "POST"
          path: "/api/upload"
          bodySize: "1MB"          # generates 1 048 576 random bytes per request
          headers:
            Content-Type: "application/octet-stream"
        assertions:
          - type: statusCode
            expected: 200
          - type: responseTime
            max: "5s"

bodySize and body are mutually exclusive — use one or the other per step.

Combined with JWT auth (multi-step):

scenarios:
  - name: "Auth then upload"
    weight: 100
    steps:
      - name: "Login"
        request:
          method: "POST"
          path: "/auth/login"
          body: '{"username":"loadtest","password":"secret"}'
          headers:
            Content-Type: "application/json"
        extract:
          - type: jsonPath
            name: "jwt_token"
            jsonPath: "$.token"
        assertions:
          - type: statusCode
            expected: 200

      - name: "Upload 512KB"
        request:
          method: "POST"
          path: "/api/upload"
          bodySize: "512KB"
          headers:
            Authorization: "Bearer ${jwt_token}"
            Content-Type: "application/octet-stream"
        assertions:
          - type: statusCode
            expected: 200

⁠Live Control API (port 8080)

Every node exposes a lightweight HTTP API for real-time inspection and reconfiguration.

⁠GET /health

Returns live node status as JSON:

{
  "node_id": "node-1",
  "region": "us-east",
  "node_state": "running",
  "rps": 1423.7,
  "error_rate_pct": 0.12,
  "workers": 25,
  "memory_mb": 142.3,
  "total_memory_mb": 16384.0,
  "cpu_pct": 14.5,
  "time_remaining_secs": 3542,
  "test_started_at_unix": 1706000000,
  "test_duration_secs": 7200,
  "test_percent_complete": 50.8,
  "current_yaml": "version: \"1.0\"\n..."
}

node_state values: "running" (active test), "standby" (test complete, keeping connections warm), "idle" (no config).

⁠POST /config

Submit a YAML config to start or reconfigure the test immediately — no restart required:

curl -X POST http://<node>:8080/config \
  -H "Content-Type: application/x-yaml" \
  --data-binary @config.yaml

Example YAML config with standby:

version: "1.0"
config:
  baseUrl: "https://your-service.com"
  workers: 50
  duration: "1h"
  timeout: "30s"
load:
  model: "rps"
  target: 500
scenarios:
  - name: "Health check"
    weight: 100
    steps:
      - name: "GET /"
        request:
          method: "GET"
          path: "/"
        assertions:
          - type: statusCode
            expected: 200
standby:
  workers: 2
  rps: 0

When the test duration expires, nodes automatically transition to "standby" state using the standby: block (or startup env-var defaults if no standby: block is present). Standby workers keep connections warm at low (or zero) RPS until a new POST /config arrives.

⁠Why Choose This Tool?

āœ… High Performance: Built in Rust for maximum throughput and minimal overhead āœ… Flexible Load Models: From simple concurrent loads to complex daily traffic patterns āœ… Live Reconfiguration: Update test parameters on the fly via POST /config — no restart needed āœ… Auto Standby: Nodes automatically switch to warm-standby mode after test completion āœ… Production Ready: Chainguard static images with minimal CVEs āœ… Easy Monitoring: Built-in Prometheus metrics (port 9090) + live health API (port 8080) āœ… Secure: Support for HTTPS, mTLS, and custom authentication āœ… Container Native: Optimized for Docker/Kubernetes/Nomad deployments āœ… Actively Maintained: Regular updates and security patches

⁠Support & Documentation

⁠License

This project is open source. See the repository for license details.


Built with ā¤ļø in Rust | Optimized for modern cloud-native deployments

Tag summary

Content type

Image

Digest

sha256:232bc803e…

Size

35.1 MB

Last updated

2 days ago

docker pull cbaugus/rust_loadtest