| name | testing-resilience |
| description | Use when creating chaos engineering or resilience tests with k6 and xk6-disruptor. Use when the user wants to inject faults (pod failures, network delays, HTTP errors) into Kubernetes services during load tests, validate circuit breakers, or test system recovery behavior. |
Testing Resilience with k6
Create chaos and resilience tests using xk6-disruptor to inject faults into Kubernetes services during k6 load tests. Validates system behavior under failure conditions.
Overview
xk6-disruptor injects faults into Kubernetes pods and services while k6 generates load, allowing you to verify:
- System survives pod failures
- Graceful degradation under network issues
- Circuit breaker behavior
- Recovery time after fault removal
- Auto-scaling response to failures
Quick Start
import http from 'k6/http';
import { check, sleep } from 'k6';
import { ServiceDisruptor } from 'k6/x/disruptor';
export const options = {
scenarios: {
load: {
executor: 'constant-arrival-rate',
rate: 100,
timeUnit: '1s',
duration: '2m',
preAllocatedVUs: 50,
},
},
thresholds: {
http_req_failed: ['rate<0.3'],
http_req_duration: ['p(95)<3000'],
},
};
export function setup() {
const disruptor = new ServiceDisruptor('my-service', 'default');
const fault = {
averageDelay: '500ms',
errorRate: 0.1,
errorCode: 503,
};
disruptor.injectHTTPFaults(fault, '60s');
}
export default function () {
const res = http.get('http://my-service.default.svc.cluster.local:8080/api');
check(res, {
'not server error': (r) => r.status < 500 || r.status === 503,
});
sleep(0.1);
}
Prerequisites
- Kubernetes cluster with target services deployed
- k6 with xk6-disruptor extension (or use automatic resolution)
- RBAC permissions for the k6 pod to manage target pods
Disruptor Types
ServiceDisruptor
Targets all pods behind a Kubernetes Service:
import { ServiceDisruptor } from 'k6/x/disruptor';
const disruptor = new ServiceDisruptor('service-name', 'namespace');
PodDisruptor
Targets specific pods by label selector:
import { PodDisruptor } from 'k6/x/disruptor';
const disruptor = new PodDisruptor({
namespace: 'default',
select: { labels: { app: 'my-app' } },
});
Fault Types
HTTP Faults
Inject delays and errors into HTTP responses:
disruptor.injectHTTPFaults(
{
averageDelay: '500ms',
delayVariation: '100ms',
errorRate: 0.1,
errorCode: 503,
port: 8080,
exclude: '/health',
},
'60s'
);
gRPC Faults
Inject faults into gRPC services:
disruptor.injectGrpcFaults(
{
averageDelay: '500ms',
errorRate: 0.2,
statusCode: 14,
statusMessage: 'service overloaded',
},
'60s'
);
Pod Termination
Kill pods to test recovery:
disruptor.terminatePods({
count: 1,
interval: '30s',
});
See reference/fault-injection.md for detailed fault configuration.
Resilience Test Patterns
Pattern 1: Graceful Degradation
Verify system degrades gracefully under partial failure:
export function setup() {
const disruptor = new ServiceDisruptor('backend-service', 'default');
disruptor.injectHTTPFaults({
averageDelay: '1000ms',
errorRate: 0.2,
errorCode: 503,
}, '90s');
}
Success criteria: System returns degraded responses instead of cascading failures.
Pattern 2: Circuit Breaker Validation
Verify circuit breaker activates under error conditions:
export function setup() {
const disruptor = new ServiceDisruptor('downstream-service', 'default');
disruptor.injectHTTPFaults({
errorRate: 0.8,
errorCode: 500,
}, '60s');
}
Success criteria: Upstream service returns fallback responses quickly (circuit open).
Pattern 3: Recovery Test
Verify system recovers after fault is removed:
export const options = {
scenarios: {
load: {
executor: 'constant-arrival-rate',
rate: 50,
timeUnit: '1s',
duration: '5m',
preAllocatedVUs: 30,
},
},
};
export function setup() {
const disruptor = new ServiceDisruptor('my-service', 'default');
disruptor.injectHTTPFaults({
averageDelay: '2000ms',
errorRate: 0.5,
errorCode: 503,
}, '120s');
}
Success criteria: Metrics return to baseline within acceptable time after fault removal.
See reference/resilience-patterns.md for more patterns.
Thresholds for Resilience Tests
Resilience tests need relaxed thresholds compared to normal load tests. Use tag-based thresholds to set different criteria for chaos and recovery phases:
export const options = {
thresholds: {
http_req_failed: ['rate<0.5'],
http_req_duration: ['p(95)<5000'],
'http_req_duration{phase:recovery}': ['p(95)<500'],
},
};
Related Skills
- For generating load test scripts:
/k6:generating-api-load-tests
- For CI/CD and Kubernetes setup:
/k6:operating-k6-in-ci-cd
- For scenario design:
/k6:designing-test-scenarios