Chaos Engineering
Status: BETA – This feature is in active development. API and behavior may change.
What is chaos engineering?
Real systems fail in ways tests rarely cover: a pod dies mid-request, the network between two services slows to a crawl, a disk fills up. Chaos engineering is the practice of causing those failures on purpose, in a controlled way, to learn how your system behaves before a real outage does it for you. You form a hypothesis (“if one payment pod dies, checkout still works”), inject the fault, and watch whether the system stays healthy. If it doesn’t, you’ve found a weakness in a safe window instead of at 3 a.m.
New to this? Start small: kill a single pod of a non-critical service in a staging namespace, with auto-rollback on. Watch what happens, then widen the blast radius as your confidence grows.
Mockarty provides a built-in chaos engineering platform for Kubernetes. Run controlled fault injection experiments to test system resilience. Supports 12 fault types including pod kills, network partitions/delay/loss, resource stress, DNS disruption, IO chaos, and time chaos.


Key capabilities:
- 12 fault injection types (pod_kill, pod_kill_random, network_partition, network_delay, network_loss, deployment_restart, scale, node_drain, resource_stress, dns_disruption, io_chaos, time_chaos)
- Safety guardrails (namespace deny lists, blast radius limits, auto-rollback)
- Steady-state validation (HTTP probes, Prometheus metrics, pod counts)
- Scheduling and automation (cron-based recurring experiments)
- Reports (HTML, JSON)
- 6 pre-built experiment presets (Chaos Monkey, Network Partition, Scale to Zero, etc.)
- Web UI with cluster topology visualization
- Integration with contract testing for validating resilience alongside spec compliance
Requirements:
- PRO license (chaos engineering is a PRO feature)
- Kubernetes cluster (1.20+)
- kubectl access or kubeconfig file
About URLs in examples: All examples use
localhost:5770as the default Mockarty address. If your instance runs on a remote server, replacelocalhost:5770with its actual address (e.g.https://mockarty.company.comorhttp://192.168.1.50:5770). See Tips & Useful Features for details.
Quick Start
Step 1. Connect to a cluster
cURL
curl -X POST http://localhost:5770/api/v1/chaos/profiles \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{"name": "staging", "namespace": "default", "kubeconfig": "/path/to/.kube/config"}'
CLI
mockarty-cli chaos cluster add --name staging --kubeconfig ~/.kube/config
mockarty-cli chaos cluster test
Go
// go get github.com/mockarty/mockarty-go
client := mockarty.NewClient("http://localhost:5770", "YOUR_TOKEN")
profile, err := client.Chaos().CreateProfile(ctx, &mockarty.ChaosProfile{
Name: "staging",
Namespace: "default",
Kubeconfig: "/path/to/.kube/config",
})
// Test connectivity
result, err := client.Chaos().TestProfile(ctx, profile.ID)
fmt.Println("Connected:", result)
Python
# pip install mockarty
from mockarty import MockartyClient
client = MockartyClient("http://localhost:5770", token="YOUR_TOKEN")
profile = client.chaos.create_profile({
"name": "staging",
"namespace": "default",
"kubeconfig": "/path/to/.kube/config",
})
# Test connectivity
result = client.chaos.test_profile(profile["id"])
print("Connected:", result)
Java
// Gradle: implementation "ru.mockarty:mockarty-java:0.3.0"
MockartyClient client = new MockartyClient("http://localhost:5770", "YOUR_TOKEN");
ChaosProfile profile = new ChaosProfile();
profile.setName("staging");
profile.setNamespace("default");
profile.setKubeconfig("/path/to/.kube/config");
ChaosProfile created = client.chaos().createProfile(profile);
// Test connectivity
Map<String, Object> result = client.chaos().testProfile(created.getId());
System.out.println("Connected: " + result);
Step 2. Run a preset experiment
cURL
# Create experiment from preset, then run it
EXPERIMENT_ID=$(curl -s -X POST http://localhost:5770/api/v1/chaos/experiments \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{
"name": "frontend-chaos-monkey",
"namespace": "my-app",
"presetName": "chaos-monkey",
"durationSec": 300,
"target": {"selector": {"app": "frontend"}, "namespace": "my-app"}
}' | jq -r '.id')
curl -X POST "http://localhost:5770/api/v1/chaos/experiments/$EXPERIMENT_ID/run" \
-H "Authorization: Bearer YOUR_TOKEN"
CLI
mockarty-cli chaos preset run --preset chaos-monkey \
--k8s-namespace my-app --selector app=frontend --duration 5m
Go
// List available presets
presets, err := client.Chaos().ListPresets(ctx)
// Create and run an experiment from a preset definition
exp, err := client.Chaos().Create(ctx, &mockarty.ChaosExperiment{
Name: "frontend-chaos-monkey",
Namespace: "my-app",
PresetName: "chaos-monkey",
DurationSec: 300,
Target: mockarty.TargetConfig{
Selector: map[string]string{"app": "frontend"},
Namespace: "my-app",
},
})
err = client.Chaos().Run(ctx, exp.ID)
Python
# List available presets
presets = client.chaos.list_presets()
# Create and run an experiment from a preset definition
exp = client.chaos.create({
"name": "frontend-chaos-monkey",
"namespace": "my-app",
"presetName": "chaos-monkey",
"durationSec": 300,
"target": {
"selector": {"app": "frontend"},
"namespace": "my-app",
},
})
client.chaos.run(exp["id"])
Java
// List available presets
List<ChaosPreset> presets = client.chaos().listPresets();
// Create and run an experiment from a preset definition
ChaosExperiment exp = new ChaosExperiment();
exp.setName("frontend-chaos-monkey");
exp.setNamespace("my-app");
exp.setPresetName("chaos-monkey");
exp.setDurationSec(300);
ChaosExperiment created = client.chaos().create(exp);
client.chaos().run(created.getId());
Step 3. View results
cURL
curl http://localhost:5770/api/v1/chaos/experiments/EXPERIMENT_ID/report \
-H "Authorization: Bearer YOUR_TOKEN"
CLI
mockarty-cli chaos get EXPERIMENT_ID
mockarty-cli chaos report EXPERIMENT_ID --format html --output report.html
Go
report, err := client.Chaos().GetReport(ctx, "EXPERIMENT_ID")
fmt.Println("Status:", report.Status)
// Download HTML report
htmlBytes, err := client.Chaos().DownloadReport(ctx, "EXPERIMENT_ID", "html")
os.WriteFile("report.html", htmlBytes, 0644)
Python
report = client.chaos.get_report("EXPERIMENT_ID")
print("Status:", report["status"])
# Download HTML report
html_bytes = client.chaos.download_report("EXPERIMENT_ID", format="html")
with open("report.html", "wb") as f:
f.write(html_bytes)
Java
Map<String, Object> report = client.chaos().getReport("EXPERIMENT_ID");
System.out.println("Status: " + report.get("status"));
// Download HTML report
byte[] htmlBytes = client.chaos().downloadReport("EXPERIMENT_ID", "html");
Files.write(Path.of("report.html"), htmlBytes);
Cluster Setup
Adding a Cluster Profile
cURL
curl -X POST http://localhost:5770/api/v1/chaos/profiles \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{
"name": "production",
"namespace": "default",
"kubeconfig": "/home/user/.kube/config",
"context": "prod-context"
}'
CLI
mockarty-cli chaos cluster add --name production --kubeconfig ~/.kube/config
# With context and namespace restrictions
mockarty-cli chaos cluster add --name production \
--kubeconfig ~/.kube/config --context prod-context \
--allowed-namespaces app,test --denied-namespaces kube-system,monitoring
Go
profile, err := client.Chaos().CreateProfile(ctx, &mockarty.ChaosProfile{
Name: "production",
Namespace: "default",
Kubeconfig: "/home/user/.kube/config",
Context: "prod-context",
})
fmt.Println("Created profile:", profile.ID)
Python
profile = client.chaos.create_profile({
"name": "production",
"namespace": "default",
"kubeconfig": "/home/user/.kube/config",
"context": "prod-context",
})
print("Created profile:", profile["id"])
Java
ChaosProfile profile = new ChaosProfile();
profile.setName("production");
profile.setNamespace("default");
profile.setKubeconfig("/home/user/.kube/config");
profile.setContext("prod-context");
ChaosProfile created = client.chaos().createProfile(profile);
System.out.println("Created profile: " + created.getId());
Testing Connectivity
cURL
curl -X POST http://localhost:5770/api/v1/chaos/profiles/PROFILE_ID/test \
-H "Authorization: Bearer YOUR_TOKEN"
CLI
mockarty-cli chaos cluster test
Go
result, err := client.Chaos().TestProfile(ctx, "PROFILE_ID")
fmt.Println("Connection status:", result)
Python
result = client.chaos.test_profile("PROFILE_ID")
print("Connection status:", result)
Java
Map<String, Object> result = client.chaos().testProfile("PROFILE_ID");
System.out.println("Connection status: " + result);
Viewing Cluster Info
mockarty-cli chaos cluster info # Namespaces, nodes, capabilities
mockarty-cli chaos cluster list # All configured clusters
mockarty-cli chaos cluster use staging # Switch active cluster
Managing the cluster (kubectl-native)
The CLI talks directly to the active cluster’s kubeconfig, so you can inspect
and act on workloads without leaving the tool:
# Pods
mockarty-cli chaos pods list --k8s-namespace shop -l app=checkout
mockarty-cli chaos pods describe checkout-abc12 --k8s-namespace shop
mockarty-cli chaos pods logs checkout-abc12 --k8s-namespace shop --tail 200 -f
mockarty-cli chaos pods kill checkout-abc12 --k8s-namespace shop # controller recreates it
# Deployments
mockarty-cli chaos deployments list --k8s-namespace shop
mockarty-cli chaos deployments scale checkout --replicas 5 --k8s-namespace shop
mockarty-cli chaos deployments restart checkout --k8s-namespace shop
# Config, services, events, topology
mockarty-cli chaos configmaps list --k8s-namespace shop
mockarty-cli chaos services list --k8s-namespace shop
mockarty-cli chaos events --k8s-namespace shop
mockarty-cli chaos topology --k8s-namespace shop --output json
Add --format json to any list/topology command for scripting. The mutating
commands (pods kill, deployments scale|restart) require the preview flag;
the read-only ones do not.
Fault Types
| Fault Type | Description | Risk Level |
|---|---|---|
pod_kill |
Kill a specific pod | Medium |
pod_kill_random |
Kill a random pod matching the selector | Medium |
network_partition |
Block all network traffic to/from target | High |
network_delay |
Inject latency on target pod network interfaces (latencyMs field) |
Medium |
network_loss |
Drop a percentage of packets on target pods (lossPercent field) |
Medium |
deployment_restart |
Trigger a rolling restart of a deployment | Medium |
scale |
Change replica count (including scale to zero) | High |
node_drain |
Evict all pods from a node | High |
resource_stress |
Apply CPU/memory stress on target pods | Medium |
dns_disruption |
Disrupt DNS resolution for target domains | High |
io_chaos |
Inject filesystem faults: IO latency or IO errors on a mount path (ioLatencyMs, ioErrPercent, ioPath) |
High |
time_chaos |
Shift the clock on target pods by a delta (timeOffsetSec) |
Medium |
Target modes: one (specific pod), random_one (default), all, fixed_percent.
Faults that need the data-plane injector
pod_kill, pod_kill_random, deployment_restart, scale, node_drain and
resource_stress run against the native Kubernetes API and work on any cluster.
network_delay, network_loss, io_chaos, time_chaos, dns_disruption and a
real (data-plane-enforced) network_partition need an in-cluster fault injector.
Install it once with the bundled chart — a single command brings everything,
nothing else to install:
helm install mockarty-chaos ./mockarty-chaos-operator \
--namespace mockarty-chaos --create-namespace
The chart bundles the data-plane injector as a dependency. Once it’s running,
all fault types are available — Mockarty drives them and shows the results. For a
Docker-runtime cluster add --set chaos-mesh.chaosDaemon.runtime=docker --set chaos-mesh.chaosDaemon.socketPath=/var/run/docker.sock. If your cluster
already runs its own data-plane injector, disable the bundle with
--set chaos-mesh.enabled=false.
Running Experiments
From CLI Flags
mockarty-cli chaos run \
--type pod_kill_random \
--k8s-namespace my-app \
--selector app=frontend \
--duration 5m \
--interval 30s \
--auto-rollback
mockarty-cli chaos run \
--type network_partition \
--deployment my-service \
--k8s-namespace my-app \
--duration 2m \
--auto-rollback
From YAML File
# experiment.yaml
name: frontend-resilience-test
namespace: my-app
durationSec: 600
faults:
- type: pod_kill_random
intervalSec: 60
target:
mode: random_one
selector:
app: frontend
namespace: my-app
safety:
autoRollback: true
haltOnSteadyFail: true
denyNamespaces: [kube-system, monitoring]
maxPodsAffected: 3
blastRadiusPercent: 30
steadyState:
checks:
- name: frontend-health
type: http
endpoint: "http://frontend.my-app.svc:8080/health"
method: GET
expected: 200
intervalSec: 10
- name: min-frontend-pods
type: pod_count
query: "app=frontend"
expected: 2
cURL
curl -X POST http://localhost:5770/api/v1/chaos/experiments \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d @experiment.json
# Then run it
curl -X POST http://localhost:5770/api/v1/chaos/experiments/EXPERIMENT_ID/run \
-H "Authorization: Bearer YOUR_TOKEN"
CLI
mockarty-cli chaos run -f experiment.yaml
Go
exp, err := client.Chaos().Create(ctx, &mockarty.ChaosExperiment{
Name: "frontend-resilience-test",
Namespace: "my-app",
DurationSec: 600,
Faults: []mockarty.FaultConfig{
{Type: "pod_kill_random", IntervalSec: 60},
},
Target: mockarty.TargetConfig{
Mode: "random_one",
Selector: map[string]string{"app": "frontend"},
Namespace: "my-app",
},
Safety: mockarty.SafetyConfig{
AutoRollback: true,
HaltOnSteadyFail: true,
DenyNamespaces: []string{"kube-system", "monitoring"},
MaxPodsAffected: 3,
BlastRadiusPercent: 30,
},
})
// Run the experiment
err = client.Chaos().Run(ctx, exp.ID)
Python
exp = client.chaos.create({
"name": "frontend-resilience-test",
"namespace": "my-app",
"durationSec": 600,
"faults": [
{"type": "pod_kill_random", "intervalSec": 60},
],
"target": {
"mode": "random_one",
"selector": {"app": "frontend"},
"namespace": "my-app",
},
"safety": {
"autoRollback": True,
"haltOnSteadyFail": True,
"denyNamespaces": ["kube-system", "monitoring"],
"maxPodsAffected": 3,
"blastRadiusPercent": 30,
},
})
# Run the experiment
client.chaos.run(exp["id"])
Java
ChaosExperiment exp = new ChaosExperiment();
exp.setName("frontend-resilience-test");
exp.setNamespace("my-app");
exp.setDurationSec(600);
ChaosExperiment created = client.chaos().create(exp);
// Run the experiment
client.chaos().run(created.getId());
Using Presets
Mockarty ships with 6 pre-built experiment presets:
| Preset | Description | Risk | Fault Types |
|---|---|---|---|
chaos-monkey |
Randomly kills a pod every 5 min | Medium | pod_kill_random |
network-partition |
Blocks all ingress/egress traffic | High | network_partition |
scale-to-zero |
Scales deployment to 0 replicas | High | scale |
resource-pressure |
CPU/memory stress on target | Medium | resource_stress |
rolling-restart-storm |
Repeated deployment restarts | Medium | deployment_restart |
dns-disruption |
Disrupts DNS resolution | High | dns_disruption |
cURL
# Create an experiment from a preset and run it
EXPERIMENT_ID=$(curl -s -X POST http://localhost:5770/api/v1/chaos/experiments \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{
"name": "chaos-monkey-test",
"namespace": "my-app",
"presetName": "chaos-monkey",
"durationSec": 300,
"target": {"mode": "random_one", "selector": {"app": "web"}, "namespace": "my-app"}
}' | jq -r '.id')
curl -X POST "http://localhost:5770/api/v1/chaos/experiments/$EXPERIMENT_ID/run" \
-H "Authorization: Bearer YOUR_TOKEN"
CLI
# List all presets
mockarty-cli chaos preset list
# Run a preset
mockarty-cli chaos preset run --preset chaos-monkey \
--k8s-namespace my-app --selector app=web --duration 5m
mockarty-cli chaos preset run --preset network-partition \
--k8s-namespace my-app --selector app=api --duration 3m
mockarty-cli chaos preset run --preset dns-disruption \
--k8s-namespace my-app --selector app=gateway --duration 2m
Go
// List all presets
presets, err := client.Chaos().ListPresets(ctx)
for _, p := range presets {
fmt.Printf("Preset: %s (%s)\n", p.Name, p.Description)
}
// Create experiment from a preset and run it
exp, err := client.Chaos().Create(ctx, &mockarty.ChaosExperiment{
Name: "chaos-monkey-test",
Namespace: "my-app",
PresetName: "chaos-monkey",
DurationSec: 300,
Target: mockarty.TargetConfig{
Selector: map[string]string{"app": "web"},
Namespace: "my-app",
},
})
err = client.Chaos().Run(ctx, exp.ID)
Python
# List all presets
presets = client.chaos.list_presets()
for p in presets:
print(f"Preset: {p['name']} ({p.get('description', '')})")
# Create experiment from a preset and run it
exp = client.chaos.create({
"name": "chaos-monkey-test",
"namespace": "my-app",
"presetName": "chaos-monkey",
"durationSec": 300,
"target": {
"selector": {"app": "web"},
"namespace": "my-app",
},
})
client.chaos.run(exp["id"])
Java
// List all presets
List<ChaosPreset> presets = client.chaos().listPresets();
for (ChaosPreset p : presets) {
System.out.printf("Preset: %s (%s)%n", p.getName(), p.getDescription());
}
// Create experiment from a preset and run it
ChaosExperiment exp = new ChaosExperiment();
exp.setName("chaos-monkey-test");
exp.setNamespace("my-app");
exp.setPresetName("chaos-monkey");
exp.setDurationSec(300);
ChaosExperiment created = client.chaos().create(exp);
client.chaos().run(created.getId());
Safety & Guardrails
Namespace Protection
safety:
denyNamespaces: [kube-system, monitoring, cert-manager, istio-system]
allowNamespaces: [staging-app, test-env] # Whitelist mode
Blast Radius Limits
safety:
maxPodsAffected: 5
minReplicasAlive: 2
blastRadiusPercent: 30
Auto-Rollback
Automatically reverts all changes if steady-state checks fail:
safety:
autoRollback: true # Revert on failure
haltOnSteadyFail: true # Stop if steady-state check fails
CLI flag: --auto-rollback (enabled by default).
Manual approval
Some experiments should not start just because someone clicked Run. Tick
Require manual approval in the experiment’s safety settings and the run is
held until a person releases it:
safety:
requireApproval: true # hold the run until someone approves it
What happens:
- The experiment is created with the status Awaiting approval and cannot be
run — starting it returns an error explaining that it needs approval. - Anyone with chaos admin rights opens the experiment and presses Approve.
They are asked why it is safe to run; that note is stored with the approval. - The experiment moves to Pending and can now be run normally.
The approval records who granted it and when, and both approving and withdrawing
an approval are written to the audit log. If a reviewer changes their mind before
the run starts, Unapprove puts the experiment back behind the gate.
Over the API:
# release the run
curl -X POST http://localhost:5770/api/v1/chaos/experiments/$ID/approve \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"note": "blast radius reviewed with the platform team"}'
# change your mind (only possible before the run starts)
curl -X POST http://localhost:5770/api/v1/chaos/experiments/$ID/unapprove \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"note": "spotted a production selector"}'
An approval always names a person: a request that is not signed in is refused.
Steady-State Validation
Verify system behavior before, during, and after experiments:
steadyState:
checks:
# HTTP endpoint check
- name: health-check
type: http
endpoint: "http://my-service.my-app.svc:8080/health"
method: GET
expected: 200
intervalSec: 10
timeoutSec: 5
# Prometheus metric query
- name: error-rate
type: prometheus
query: "rate(http_requests_total{job='frontend',code=~'5..'}[1m])"
expected: 0.01
tolerance: 0.005
intervalSec: 30
# Pod count check
- name: min-pods
type: pod_count
query: "app=frontend"
expected: 2
tolerance: 0
Monitoring & Reports
Viewing Experiment Status
cURL
curl http://localhost:5770/api/v1/chaos/experiments/EXPERIMENT_ID \
-H "Authorization: Bearer YOUR_TOKEN"
curl "http://localhost:5770/api/v1/chaos/experiments?status=active&limit=10" \
-H "Authorization: Bearer YOUR_TOKEN"
CLI
mockarty-cli chaos get EXPERIMENT_ID
mockarty-cli chaos list --status active --limit 10
mockarty-cli chaos abort EXPERIMENT_ID
Go
// Get a single experiment
exp, err := client.Chaos().Get(ctx, "EXPERIMENT_ID")
fmt.Println("Status:", exp.Status)
// List active experiments
experiments, err := client.Chaos().List(ctx, &mockarty.ChaosListOptions{
Status: "active",
Limit: 10,
})
// Abort a running experiment
err = client.Chaos().Abort(ctx, "EXPERIMENT_ID")
Python
# Get a single experiment
exp = client.chaos.get("EXPERIMENT_ID")
print("Status:", exp["status"])
# List active experiments
experiments = client.chaos.list(status="active", limit=10)
# Abort a running experiment
client.chaos.abort("EXPERIMENT_ID")
Java
// Get a single experiment
ChaosExperiment exp = client.chaos().get("EXPERIMENT_ID");
System.out.println("Status: " + exp.getStatus());
// List active experiments
List<ChaosExperiment> experiments = client.chaos().list(null, "active", 10, 0);
// Abort a running experiment
client.chaos().abort("EXPERIMENT_ID");
Getting Reports
cURL
# JSON report
curl http://localhost:5770/api/v1/chaos/experiments/EXPERIMENT_ID/report \
-H "Authorization: Bearer YOUR_TOKEN"
# Download in specific format: html, json
curl -o report.html \
"http://localhost:5770/api/v1/chaos/experiments/EXPERIMENT_ID/report/download?format=html" \
-H "Authorization: Bearer YOUR_TOKEN"
CLI
mockarty-cli chaos report EXPERIMENT_ID
mockarty-cli chaos report EXPERIMENT_ID --format html --output report.html
mockarty-cli chaos report EXPERIMENT_ID --format json --output report.json
Go
// Get JSON report
report, err := client.Chaos().GetReport(ctx, "EXPERIMENT_ID")
// Get metrics and events
metrics, err := client.Chaos().GetMetrics(ctx, "EXPERIMENT_ID")
events, err := client.Chaos().GetEvents(ctx, "EXPERIMENT_ID")
// Download report in a specific format: html, json
htmlBytes, err := client.Chaos().DownloadReport(ctx, "EXPERIMENT_ID", "html")
os.WriteFile("report.html", htmlBytes, 0644)
Python
# Get JSON report
report = client.chaos.get_report("EXPERIMENT_ID")
# Get metrics and events
metrics = client.chaos.get_metrics("EXPERIMENT_ID")
events = client.chaos.get_events("EXPERIMENT_ID")
# Download report in a specific format: html, json
html_bytes = client.chaos.download_report("EXPERIMENT_ID", format="html")
with open("report.html", "wb") as f:
f.write(html_bytes)
Java
// Get JSON report
Map<String, Object> report = client.chaos().getReport("EXPERIMENT_ID");
// Get metrics and events
Map<String, Object> metrics = client.chaos().getMetrics("EXPERIMENT_ID");
Map<String, Object> events = client.chaos().getEvents("EXPERIMENT_ID");
// Download report in a specific format: html, json
byte[] htmlBytes = client.chaos().downloadReport("EXPERIMENT_ID", "html");
Files.write(Path.of("report.html"), htmlBytes);
| Format | Use Case |
|---|---|
| JSON | Programmatic analysis, dashboards |
| HTML | Rich visual report for stakeholders |
Scheduling
Run experiments on a recurring schedule:
name: daily-resilience-check
namespace: staging
schedule:
cronExpr: "0 3 * * *"
repeatCount: 0 # 0 = infinite when cron is set
jitter: 30 # random jitter in seconds added to start time
faults:
- type: pod_kill_random
intervalSec: 60
target:
mode: random_one
selector: { app: api }
namespace: staging
durationSec: 300
safety:
autoRollback: true
denyNamespaces: [kube-system]
What happens after you save
The schedule starts at its next matching time, never immediately — saving a
schedule (or restarting Mockarty) will not fire an experiment on the spot.
A run is skipped, not queued, when the previous one is still going: overlapping
fault injections turn a test into an outage. The skipped slot is simply the next
one on the cron.
repeatCount: 0 means “keep going”. Any other number stops the schedule once it
has run that many times, and the schedule is then shown as paused.
jitter adds up to that many random seconds to each start time, so several
experiments sharing one expression do not all hit the cluster on the same second.
Seeing and stopping recurring runs
Open Chaos Engineering → Experiments. When any experiment recurs, a Recurring
schedules table appears under the experiment list showing the cron expression,
the next run, how many runs have happened, and whether it is paused.
- Pause stops future runs and keeps everything else. Use it when an
experiment starts hurting an environment — it is reversible. - Delete cancels the recurrence only. The experiment and all of its past
runs are kept, and you can still run it by hand.
Neither one stops a run that is already in progress — abort that from the
experiment itself.
The same list is available over the API:
curl http://localhost:5770/api/v1/chaos/schedules?namespace=staging
# pause (id is the SCHEDULE id from the list above, not the experiment id)
curl -X POST http://localhost:5770/api/v1/chaos/schedules/<id>/pause \
-H 'Content-Type: application/json' -d '{"paused": true}'
# cancel the recurrence, keep the experiment
curl -X DELETE http://localhost:5770/api/v1/chaos/schedules/<id>
If a cron expression cannot be parsed — or can never occur, like 0 0 31 2 * —
it is rejected when you save, and the experiment is still created for manual
runs.
Cluster Inspection
Topology & Resources
# Cluster topology
curl http://localhost:5770/api/v1/chaos/clusters/CLUSTER_ID/topology \
-H "Authorization: Bearer YOUR_TOKEN"
# Pod operations
curl -X DELETE http://localhost:5770/api/v1/chaos/pods/NAMESPACE/POD_NAME \
-H "Authorization: Bearer YOUR_TOKEN"
curl http://localhost:5770/api/v1/chaos/pods/NAMESPACE/POD_NAME/logs \
-H "Authorization: Bearer YOUR_TOKEN"
# Deployment operations
curl -X POST http://localhost:5770/api/v1/chaos/deployments/NAMESPACE/DEPLOY/scale \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{"replicas": 3}'
curl -X POST http://localhost:5770/api/v1/chaos/deployments/NAMESPACE/DEPLOY/restart \
-H "Authorization: Bearer YOUR_TOKEN"
Chaos Operator
The operator is a Kubernetes deployment that enables advanced experiment types. It creates RBAC resources and runs inside the cluster.
Two install scopes — pick the one you need:
- Operator only (the
installbelow — API, CLI, or the agent in a chat): deploys the Mockarty operator alone. That’s everything the native-Kubernetes fault types need —pod_kill,pod_kill_random,deployment_restart,scale,node_drain,resource_stress. If those are the only faults you run, this is all you need. - Operator + data-plane injector (one Helm command): the data-plane fault types —
network_delay,network_loss,io_chaos,time_chaos,dns_disruptionand a real (enforced)network_partition— additionally need the in-cluster injector. The bundled Helm chart installs both in a single command — see Faults that need the data-plane injector. Run a data-plane fault without it and the experiment reports a clearrequires the data-plane injectorresult instead of silently passing.
cURL
curl -X POST http://localhost:5770/api/v1/chaos/operator/install \
-H "Authorization: Bearer YOUR_TOKEN"
curl http://localhost:5770/api/v1/chaos/operator/status \
-H "Authorization: Bearer YOUR_TOKEN"
CLI
mockarty-cli chaos operator install
mockarty-cli chaos operator install --namespace my-chaos-ns
mockarty-cli chaos operator status
mockarty-cli chaos operator uninstall
Go
// Check operator status
status, err := client.Chaos().GetOperatorStatus(ctx, "my-chaos-ns")
fmt.Println("Operator installed:", status.Installed)
// Generate operator manifest
manifest, err := client.Chaos().GenerateOperatorManifest(ctx, "http://mockarty:5770", "")
fmt.Println(manifest)
Python
# Check operator status
status = client.chaos.get_operator_status(namespace="my-chaos-ns")
print("Operator installed:", status.get("installed"))
Java
// Check operator status
Map<String, Object> status = client.chaos().getOperatorStatus("my-chaos-ns");
System.out.println("Operator installed: " + status.get("installed"));
CI/CD Integration
Example GitHub Actions workflow:
name: Chaos Engineering Tests
on:
schedule:
- cron: '0 2 * * 1'
workflow_dispatch:
jobs:
chaos-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install CLI
run: curl -fsSL https://mockarty.ru/install.sh | sh
- name: Configure cluster
run: mockarty-cli chaos cluster add --name ci --kubeconfig ${{ secrets.KUBECONFIG_PATH }}
- name: Run experiment
run: |
mockarty-cli chaos preset run --preset chaos-monkey \
--k8s-namespace staging --selector app=api --duration 5m
- name: Get report
run: |
sleep 330
EXPERIMENT_ID=$(mockarty-cli chaos list --status completed --limit 1 -o json | jq -r '.[0].id')
mockarty-cli chaos report $EXPERIMENT_ID --format html --output chaos-report.html
mockarty-cli chaos report $EXPERIMENT_ID --format json --output chaos-results.json
- uses: actions/upload-artifact@v4
with:
name: chaos-report
path: |
chaos-report.html
chaos-results.xml
API Reference
Presets
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/chaos/presets |
List available presets |
Note: To run a preset, create an experiment with the
presetNamefield set viaPOST /api/v1/chaos/experiments, then start it withPOST /api/v1/chaos/experiments/:id/run.
Experiments
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/chaos/experiments |
List experiments (filters: namespace, status, limit, offset) |
| GET | /api/v1/chaos/experiments/:id |
Get experiment details |
| POST | /api/v1/chaos/experiments |
Create an experiment |
| PUT | /api/v1/chaos/experiments/:id |
Update an experiment |
| DELETE | /api/v1/chaos/experiments/:id |
Delete an experiment |
| POST | /api/v1/chaos/experiments/:id/run |
Start an experiment |
| POST | /api/v1/chaos/experiments/:id/abort |
Abort an active experiment |
| GET | /api/v1/chaos/experiments/:id/metrics |
Get experiment metrics |
| GET | /api/v1/chaos/experiments/:id/events |
Get experiment event log |
| GET | /api/v1/chaos/experiments/:id/report |
Get report (JSON) |
| GET | /api/v1/chaos/experiments/:id/report/download |
Download report (format: html, json) |
| GET | /api/v1/chaos/experiments/:id/snapshot |
Get experiment snapshot |
Profiles
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/chaos/profiles |
List cluster profiles |
| POST | /api/v1/chaos/profiles |
Create a cluster profile |
| PUT | /api/v1/chaos/profiles/:id |
Update a cluster profile |
| DELETE | /api/v1/chaos/profiles/:id |
Delete a cluster profile |
| POST | /api/v1/chaos/profiles/:id/test |
Test cluster connectivity |
| POST | /api/v1/chaos/profiles/:id/connect |
Connect to a cluster |
| POST | /api/v1/chaos/profiles-test |
Test connectivity (inline config) |
Operator
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/chaos/operator/manifest |
Generate operator manifest |
| POST | /api/v1/chaos/operator/install |
Install operator |
| GET | /api/v1/chaos/operator/status |
Get operator status |
Cluster Inspection
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/chaos/clusters/:id/topology |
Get cluster topology |
| GET | /api/v1/chaos/queue/:clusterId |
Get experiment queue |
| DELETE | /api/v1/chaos/pods/:namespace/:name |
Delete a pod |
| GET | /api/v1/chaos/pods/:namespace/:name |
Get pod details |
| GET | /api/v1/chaos/pods/:namespace/:name/logs |
Get pod logs |
| POST | /api/v1/chaos/deployments/:namespace/:name/scale |
Scale a deployment |
| POST | /api/v1/chaos/deployments/:namespace/:name/restart |
Restart a deployment |
| GET | /api/v1/chaos/deployments/:namespace/:name |
Get deployment details |
| GET | /api/v1/chaos/configmaps/:namespace |
List configmaps |
| GET | /api/v1/chaos/configmaps/:namespace/:name |
Get configmap |
| PUT | /api/v1/chaos/configmaps/:namespace/:name |
Update configmap |
| GET | /api/v1/chaos/services/:namespace |
List services |
| GET | /api/v1/chaos/crds |
List CRDs |
| GET | /api/v1/chaos/crds/:group/:version/:resource |
Get CRD instances |
| GET | /api/v1/chaos/events/:namespace |
Get namespace events |
Contract Testing Integration
Chaos engineering and contract testing work together to provide comprehensive reliability assurance:
- Before chaos experiments: Run contract tests to ensure mocks and specs are in sync. This establishes a baseline of correctness before injecting faults.
- During chaos experiments: Use steady-state HTTP checks that point to contract-validated endpoints, ensuring you’re testing against known-good contracts.
- After chaos experiments: Re-run contract tests to verify that no drift was introduced during fault injection or recovery.
This combination catches both functional drift (contract testing) and resilience gaps (chaos engineering), providing end-to-end confidence in your service mesh.
Related Documentation
- API Reference – Full REST API documentation
- CLI User Guide – Command-line tool reference
- SDK Guide – SDK clients (Go, Python, Java)
- Performance Testing – Load testing capabilities
- Contract Testing – Contract testing with Pact