Reliability & Chaos Testing
What it is
Section titled “What it is”Chaos engineering is the discipline of experimenting on a system to build confidence in its ability to withstand turbulent conditions. You form a hypothesis about steady state, inject a realistic fault, and observe whether the system holds.
steady state ──► inject fault ──► observe ──► learn │ │ │ │ p99, errors kill pod did SLO hold? fix / accept add latency partition netRelated practice: reliability testing keeps the focus on the SLOs you promised (availability, error budget) rather than on a single outage.
When to use it / when to avoid it
Section titled “When to use it / when to avoid it”Use it for
- Systems with replication, retries, failover or autoscaling claims to verify
- Game days: a scheduled, controlled experiment with a rollback ready
- Validating that timeouts, circuit breakers and retries actually work
- Finding the failure a real datacentre or network event will eventually cause
Avoid or reduce it when
- You have no observability — you cannot learn from an experiment you cannot see
- There is no blast-radius control (feature flags, canary, abort button)
- You start in production before proving the experiment in staging
- Nobody owns the SLOs; without a target, “resilient” is undefined
Frameworks & tools
Section titled “Frameworks & tools”| Tool | Ecosystem | Notes |
|---|---|---|
| Chaos Mesh | Kubernetes | CRDs for pod, network, IO, DNS and time chaos |
| Litmus | Kubernetes | ChaosHub library, experiment workflows |
| Gremlin | SaaS / agent | Managed attacks, safety controls |
| Toxiproxy | Multi | TCP proxy to inject latency and resets |
| AWS Fault Injection Simulator | AWS | Managed cloud-level faults |
| Pumba | Docker | Chaos for plain Docker containers |
| Chaos Monkey | JVM / Spinnaker | The original random-termination tool |
| kube-monkey | Kubernetes | Schedules random pod kills |
Quick setup
Section titled “Quick setup”docker run -d --name toxiproxy -p 8474:8474 -p 8666:8666 \ ghcr.io/shopify/toxiproxy:2.9.0toxiproxy-cli create postgres --listen 0.0.0.0:8666 --upstream db:5432toxiproxy-cli toxic add postgres -t latency -a latency=300helm repo add chaos-mesh https://charts.chaos-mesh.orghelm install chaos-mesh chaos-mesh/chaos-mesh -n chaos-mesh --create-namespacenpm install -D toxiproxy-node-clientpip install toxiproxy-pythongo get github.com/Shopify/toxiproxy/v2/client<!-- Testcontainers Toxiproxy module --><dependency> <groupId>org.testcontainers</groupId> <artifactId>toxiproxy</artifactId> <version>1.20.1</version> <scope>test</scope></dependency>dotnet add package Toxiproxy.NetExample
Section titled “Example”toxiproxy-cli create postgres --listen 0.0.0.0:8666 --upstream db:5432toxiproxy-cli toxic add postgres -t latency -a latency=500# now run your suite; assert timeouts and circuit breakers behavetoxiproxy-cli toxic remove postgres -n latency_downstreamapiVersion: chaos-mesh.org/v1alpha1kind: PodChaosmetadata: name: kill-apispec: action: pod-kill mode: one selector: labelSelectors: app: api duration: '1m'const proxy = await api.createProxy({ name: 'redis', listen: '0.0.0.0:8667', upstream: 'redis:6379' });await proxy.addToxic({ type: 'latency', attributes: { latency: 200 } });from toxiproxy import Toxiproxy
api = Toxiproxy()proxy = api.create(name="redis", listen="0.0.0.0:8667", upstream="redis:6379")proxy.add_toxic(type="latency", attributes={"latency": 200})# assert the cache layer degrades gracefully, then clean upproxy.destroy()// wrap the HTTP client with a timeout to emulate a slow dependencyclient := &http.Client{Timeout: 250 * time.Millisecond}_, err := client.Get("http://downstream/health")if err == nil { t.Fatal("expected a timeout under injected latency")}var proxy = new ToxiproxyContainer(DockerImageName.parse("ghcr.io/shopify/toxiproxy:2.9.0"));proxy.start();var toxi = proxy.getProxy(proxy.getContainerIpAddress(), 8666);toxi.toxics().latency("pg-latency", ToxicDirection.DOWNSTREAM, 300);var proxy = await ToxiproxyClient.CreateProxy("postgres", "0.0.0.0:8666", "db:5432");await proxy.Add(new LatencyToxic { Latency = 300 });Anti-patterns & best practices
Section titled “Anti-patterns & best practices”- Define steady state first. Without an SLO you cannot tell an experiment from an outage.
- Constrain the blast radius. One service, one zone, an abort switch, and a feature flag around anything risky.
- Run game days on a schedule. Practice drills beat a heroic scramble during a real incident.
- Inject realistic faults. Real incidents are latency, partial failure and DNS — not just a clean pod kill.
- Automate in staging, explore in production. Same experiment, staged confidence.
- Blame the system, not the person. Every surprise is a missing guard rail; turn it into a test or a dashboard panel.
Self-assessment quiz
Section titled “Self-assessment quiz”Self-assessment quiz
Pick one answer per question, then press Check answers.