xk6-disruptor is a k6 extension that adds fault injection capabilities to test the reliability of applications under turbulent conditions.
Overview
xk6-disruptor implements the principles of Chaos Engineering to test how your applications handle:
Network delays and latency
HTTP and gRPC errors
Service degradation
Partial failures
Key features:
Everything as code - Write fault injection tests in JavaScript alongside your performance tests
Fast to adopt - No need to deploy and maintain a fleet of agents or operators
Easy to integrate - Works seamlessly with other k6 tests
Capabilities
Currently, the disruptor is designed for applications running in Kubernetes . Other platforms are not supported at this time.
The extension provides a JavaScript API to inject different faults in HTTP and gRPC requests:
Error injection - Return specific HTTP status codes or gRPC error codes
Delay injection - Add latency to requests
Target selection - Inject faults into specific Pods or Services
Use cases
xk6-disruptor helps you test application resilience:
Resilience policies Test backoff, timeouts, retries, and circuit breakers
Fallback functionality Verify graceful degradation when dependencies fail
SLO validation Test SLOs under common internal failures
Performance under stress Measure application performance with injected delays
The disruptor focuses on reproducing the side effects of failures (errors, delays) rather than root causes (failed instances, resource exhaustion). This makes tests repeatable and predictable while limiting their blast radius.
Installation
There are three ways to use xk6-disruptor:
Download a release binary
The quickest way to get started:
curl -L https://github.com/grafana/xk6-disruptor/releases/latest/download/xk6-disruptor-linux-amd64.tar.gz | tar xvz
View all releases
Build from source with Go
Install xk6
go install go.k6.io/xk6/cmd/xk6@latest
Clone and build
git clone https://github.com/grafana/xk6-disruptor.git
cd xk6-disruptor
xk6 build --output xk6-disruptor --with github.com/grafana/xk6-disruptor=.
This creates an xk6-disruptor binary in the current directory.
Build with Docker
docker run --rm -u "$( id -u ):$( id -g )" -v "${ PWD }:/xk6" grafana/xk6 build \
--with github.com/grafana/xk6-disruptor@latest
Quick start
Here’s a simple example that injects faults into a Kubernetes service:
import { ServiceDisruptor } from 'k6/x/disruptor' ;
export default function () {
// Create a disruptor targeting a service
const disruptor = new ServiceDisruptor ( 'app-service' , 'app-namespace' );
// Inject HTTP faults: 500ms delay and 10% error rate
const fault = {
averageDelay: '500ms' ,
errorRate: 0.1 ,
errorCode: 500 ,
};
disruptor . injectHTTPFaults ( fault , '30s' );
}
Run the test:
./xk6-disruptor run script.js
API overview
xk6-disruptor provides two main disruptor types:
ServiceDisruptor
Targets a Kubernetes Service and all its backend Pods:
import { ServiceDisruptor } from 'k6/x/disruptor' ;
export default function () {
const disruptor = new ServiceDisruptor ( 'my-service' , 'my-namespace' );
// Inject faults for 30 seconds
disruptor . injectHTTPFaults (
{
averageDelay: '100ms' ,
errorRate: 0.05 ,
errorCode: 503 ,
},
'30s'
);
}
PodDisruptor
Targets specific Pods matching a selector:
import { PodDisruptor } from 'k6/x/disruptor' ;
export default function () {
const selector = {
namespace: 'my-namespace' ,
select: {
labels: {
app: 'my-app' ,
},
},
};
const disruptor = new PodDisruptor ( selector );
// Inject gRPC faults
disruptor . injectGrpcFaults (
{
averageDelay: '200ms' ,
errorRate: 0.1 ,
statusCode: 14 , // UNAVAILABLE
},
'1m'
);
}
Fault types
Both HTTP and gRPC fault injection support:
Property Type Description averageDelaystring Average delay to add (e.g., ‘100ms’, ‘1s’) delayVariationstring Variation in delay (e.g., ‘50ms’) errorRatenumber Fraction of requests to fail (0.0 to 1.0) errorCodenumber HTTP status code or gRPC status code portnumber Target port (optional) excludestring Path/method regex to exclude (optional)
Example with all options:
const fault = {
averageDelay: '100ms' ,
delayVariation: '50ms' , // Delays between 50ms and 150ms
errorRate: 0.1 , // 10% of requests fail
errorCode: 503 ,
port: 8080 ,
exclude: '/health' , // Don't inject faults on health checks
};
disruptor . injectHTTPFaults ( fault , '1m' );
Combining with load tests
xk6-disruptor works seamlessly with k6 load testing:
import http from 'k6/http' ;
import { check , sleep } from 'k6' ;
import { ServiceDisruptor } from 'k6/x/disruptor' ;
export const options = {
scenarios: {
load: {
executor: 'constant-vus' ,
vus: 10 ,
duration: '2m' ,
},
disrupt: {
executor: 'shared-iterations' ,
vus: 1 ,
iterations: 1 ,
exec: 'injectFaults' ,
},
},
};
// Main load test
export default function () {
const res = http . get ( 'http://my-service.my-namespace.svc.cluster.local' );
check ( res , {
'status is 200' : ( r ) => r . status === 200 ,
'response time < 500ms' : ( r ) => r . timings . duration < 500 ,
});
sleep ( 1 );
}
// Fault injection scenario
export function injectFaults () {
const disruptor = new ServiceDisruptor ( 'my-service' , 'my-namespace' );
// Wait for load test to ramp up
sleep ( 30 );
// Inject faults for 1 minute
disruptor . injectHTTPFaults (
{
averageDelay: '200ms' ,
errorRate: 0.2 ,
errorCode: 500 ,
},
'1m'
);
}
Requirements
To use xk6-disruptor, you need:
Kubernetes cluster - Access to a Kubernetes cluster (1.23+)
kubectl access - Configured kubeconfig with permissions to:
Create/delete Pods
Read Services and Pods
Execute commands in Pods
Network policies - Cluster must allow Pod-to-Pod communication
Interactive demo
Try xk6-disruptor without any setup:
Launch interactive demo on Killercoda
The demo provides a fully configured environment with a sample application.
Learn more
GitHub Repository Source code and detailed documentation
Roadmap Upcoming features and enhancements
Contributing Contribute to the project
Blog: Fault Injection Learn about fault injection principles
Examples
Test retry logic
import { ServiceDisruptor } from 'k6/x/disruptor' ;
export default function () {
const disruptor = new ServiceDisruptor ( 'api-service' , 'production' );
// Inject 50% error rate to test retry mechanisms
disruptor . injectHTTPFaults (
{
errorRate: 0.5 ,
errorCode: 503 ,
},
'1m'
);
}
Test timeout handling
import { ServiceDisruptor } from 'k6/x/disruptor' ;
export default function () {
const disruptor = new ServiceDisruptor ( 'slow-service' , 'default' );
// Add significant delay to trigger timeouts
disruptor . injectHTTPFaults (
{
averageDelay: '5s' ,
delayVariation: '1s' ,
},
'2m'
);
}
Progressive fault injection
import { ServiceDisruptor } from 'k6/x/disruptor' ;
import { sleep } from 'k6' ;
export default function () {
const disruptor = new ServiceDisruptor ( 'my-service' , 'default' );
// Start with small delays
disruptor . injectHTTPFaults ({ averageDelay: '50ms' }, '30s' );
sleep ( 30 );
// Increase to moderate delays
disruptor . injectHTTPFaults ({ averageDelay: '200ms' }, '30s' );
sleep ( 30 );
// Add errors
disruptor . injectHTTPFaults (
{
averageDelay: '200ms' ,
errorRate: 0.1 ,
errorCode: 500 ,
},
'30s'
);
}
Troubleshooting
Check cluster connectivity
kubectl get pods -n my-namespace
Verify permissions
kubectl auth can-i create pods
kubectl auth can-i exec pods
Debug disruptor issues
Enable debug logging in your test:
import { ServiceDisruptor } from 'k6/x/disruptor' ;
export const options = {
logLevel: 'debug' ,
};
Next steps
Build Custom Binary Bundle xk6-disruptor with other extensions
Explore Extensions Discover more k6 extensions
Browser Extension Add browser testing to your suite
Community Forum Get help and share experiences