Skip to main content
Back to Blog
Guide
2026-02-23

Chaos Engineering -- Resilience Testing for Modern Applications

Complete guide to chaos engineering and resilience testing. Covers fault injection, Chaos Monkey, Litmus, GameDay exercises, and building resilient systems through controlled failure.

Chaos engineering is the discipline of experimenting on a system to build confidence in its ability to withstand turbulent conditions in production. If your application has never been tested under failure, your first real outage will be your first chaos experiment -- and your users will be the ones running it. Resilience testing through controlled chaos gives you the power to find weaknesses before they become incidents.

Key Takeaways

  • Chaos engineering is a disciplined approach to identifying system weaknesses by deliberately injecting failures -- it is not about breaking things randomly
  • Fault injection covers network faults, compute failures, application errors, and infrastructure outages, each targeting different resilience layers
  • Tools like Chaos Monkey, Litmus Chaos, and Gremlin make it practical to run chaos experiments in Kubernetes and cloud-native environments
  • GameDay exercises bring teams together for structured resilience testing with defined roles, runbooks, and post-mortems
  • Steady state hypothesis is the foundation of every chaos experiment -- you must define what "normal" looks like before you can detect deviation
  • AI coding agents can automate resilience testing patterns like error boundary validation, offline mode testing, and retry logic verification

What Is Chaos Engineering?

Chaos engineering originated at Netflix in 2011 when the engineering team built Chaos Monkey -- a tool that randomly terminated production instances in AWS to ensure that their services could survive unexpected failures. The reasoning was straightforward: if Netflix could keep streaming movies while servers were being killed, customers would never notice real infrastructure failures.

But chaos engineering is much more than randomly killing servers. The Principles of Chaos Engineering, formalized by Netflix and now maintained by the community, define a rigorous scientific approach to resilience testing:

1. Define Steady State. Before running any experiment, you must establish measurable indicators of normal system behavior. This is your steady state hypothesis -- the metrics that define "everything is working." Examples include request latency under 200ms, error rate below 0.1%, and throughput above 1,000 requests per second.

2. Hypothesize About Steady State. Form a specific hypothesis: "If we inject 500ms of network latency between the API gateway and the payment service, the system will continue to serve requests within acceptable latency bounds because of our timeout and retry configuration."

3. Vary Real-World Events. Inject failures that mirror real-world disruptions -- server crashes, network partitions, disk filling up, DNS resolution failures, dependency timeouts. The more realistic the fault, the more valuable the experiment.

4. Run Experiments in Production. While you should start in staging, the ultimate goal is to run chaos experiments in production. Staging environments rarely replicate the full complexity of production traffic patterns, data volumes, and service interactions.

5. Automate Experiments to Run Continuously. Manual, one-off experiments have limited value. The real power of chaos engineering comes from automated, continuous experimentation that catches regressions as the system evolves.

6. Minimize Blast Radius. Start small. Kill one instance, not an entire availability zone. Add 100ms of latency, not 30 seconds. Gradually increase the scope and severity of experiments as you build confidence. Always have a way to stop the experiment immediately.

The core insight is that chaos engineering is proactive reliability testing. You are not waiting for failures to happen -- you are causing them on your terms, during business hours, with your team ready to respond.


The Chaos Engineering Process

Every chaos experiment follows a structured five-step cycle. Skipping steps -- especially the first two -- is the difference between chaos engineering and just breaking things.

Step 1: Define Steady State

Identify the key metrics that indicate your system is healthy. These should be business-level and infrastructure-level indicators:

Business Metrics:
- Order completion rate > 99.5%
- Search results returned within 300ms (p95)
- Payment processing success rate > 99.9%

Infrastructure Metrics:
- API error rate < 0.1%
- Pod restart count = 0 over 5 minutes
- Database connection pool utilization < 80%

Step 2: Hypothesize

Write a clear, falsifiable hypothesis. Bad hypothesis: "The system should handle failures." Good hypothesis: "When we terminate 1 of 3 API pods, the remaining pods will absorb the traffic and request latency will remain below 500ms at p99 because the Horizontal Pod Autoscaler will scale up within 30 seconds."

Step 3: Inject Fault

Execute the fault injection using your chosen chaos tool. This is the step that gets all the attention, but it is only meaningful because of the work done in steps 1 and 2.

Step 4: Observe

Monitor your steady state metrics during and after the experiment. Compare the observed behavior against your hypothesis. Did latency spike? Did error rates increase? How long did recovery take? Capture everything -- dashboards, logs, alerts that fired.

Step 5: Fix or Validate

If the system maintained steady state, your hypothesis is confirmed and you have evidence of resilience for that failure mode. If the system deviated from steady state, you have found a weakness. Document the finding, prioritize the fix, and re-run the experiment after the fix is deployed.

Then repeat the cycle. Increase the blast radius, combine failure modes, or target a different component.


Types of Fault Injection

Fault injection is the mechanism by which you introduce controlled failures into your system. Different fault types test different resilience layers.

CategoryFault TypeWhat It TestsExample
NetworkLatency injectionTimeout handling, circuit breakersAdd 2s delay between services
NetworkPacket lossRetry logic, idempotencyDrop 10% of packets on port 443
NetworkNetwork partitionGraceful degradation, split-brain handlingBlock traffic between AZ-1 and AZ-2
NetworkDNS failureDNS caching, fallback resolutionReturn NXDOMAIN for payment-service.internal
ComputeCPU stressAutoscaling, resource limitsPin CPU to 95% on 2 of 5 nodes
ComputeMemory exhaustionOOM handling, pod evictionAllocate memory until OOM killer triggers
ComputeProcess killRestart policies, health checksSIGKILL the main application process
ApplicationException injectionError handling, fallback logicForce 500 errors on 5% of /checkout requests
ApplicationDependency failureCircuit breakers, graceful degradationMake Redis return errors for all commands
InfrastructureAZ failureMulti-AZ redundancy, failoverTerminate all instances in us-east-1a
InfrastructureDisk fullLog rotation, storage alertsFill root volume to 100%
InfrastructureClock skewTime-dependent logic, certificate validationShift system clock forward by 24 hours

Start with network latency injection -- it is the safest, most reversible, and most commonly encountered real-world fault. From there, progress to process kills, then dependency failures, and eventually multi-fault scenarios.


Chaos Engineering Tools

The chaos engineering ecosystem has matured significantly. Here is how the leading tools compare:

ToolTypeTarget EnvironmentKey StrengthsBest For
Chaos MonkeyOpen sourceAWS (EC2, ASG)Netflix pedigree, battle-testedAWS-native teams
Litmus ChaosOpen source (CNCF)KubernetesChaosHub experiment library, GitOps-nativeKubernetes-first teams
Chaos MeshOpen source (CNCF)KubernetesFine-grained fault injection, dashboard UIAdvanced K8s chaos
GremlinCommercialMulti-platformEnterprise features, managed service, SRE workflowsEnterprise SRE teams
AWS Fault Injection ServiceCloud serviceAWS (ECS, EKS, EC2, RDS)Native AWS integration, IAM controlsAWS-heavy organizations
SteadybitCommercialKubernetes, cloudExperiment designer, reliability scoringPlatform engineering teams
ToxiproxyOpen sourceApplication-levelLightweight, language-agnostic TCP proxyTesting network conditions in CI

For Kubernetes-native teams, Litmus Chaos and Chaos Mesh are the strongest open source options. Litmus has a larger experiment library through ChaosHub, while Chaos Mesh offers more precise fault injection controls.

For cloud-native AWS teams, AWS Fault Injection Service provides the tightest integration with IAM, CloudWatch, and Systems Manager. You can target specific ECS tasks, EKS pods, or RDS instances with native AWS safety controls.

For enterprise environments, Gremlin offers a managed platform with built-in guardrails, team management, and compliance features that open source tools lack.

For local and CI testing, Toxiproxy is lightweight and effective for simulating network faults between services without requiring Kubernetes or cloud infrastructure.


Getting Started with Litmus Chaos

Litmus Chaos is a CNCF incubating project that provides a complete chaos engineering platform for Kubernetes. Here is how to get started from scratch.

Install Litmus on your cluster:

# Add the Litmus Helm chart repository
helm repo add litmuschaos https://litmuschaos.github.io/litmus-helm/
helm repo update

# Install Litmus in the litmus namespace
kubectl create ns litmus
helm install chaos litmuschaos/litmus \
  --namespace=litmus \
  --set portal.frontend.service.type=NodePort

Create a ChaosEngine to run a pod-delete experiment:

# pod-delete-experiment.yaml
apiVersion: litmuschaos.io/v1alpha1
kind: ChaosEngine
metadata:
  name: api-pod-delete
  namespace: default
spec:
  appinfo:
    appns: 'default'
    applabel: 'app=api-server'
    appkind: 'deployment'
  engineState: 'active'
  chaosServiceAccount: litmus-admin
  experiments:
    - name: pod-delete
      spec:
        components:
          env:
            - name: TOTAL_CHAOS_DURATION
              value: '30'
            - name: CHAOS_INTERVAL
              value: '10'
            - name: FORCE
              value: 'false'
        probe:
          - name: check-api-health
            type: httpProbe
            httpProbe/inputs:
              url: 'http://api-server.default.svc:8080/health'
              method:
                get:
                  criteria: '=='
                  responseCode: '200'
            mode: Continuous
            runProperties:
              probeTimeout: 5s
              interval: 2s
              retry: 3

Apply and observe the experiment:

# Apply the chaos experiment
kubectl apply -f pod-delete-experiment.yaml

# Watch the experiment progress
kubectl get chaosengine api-pod-delete -n default -w

# Check the results
kubectl get chaosresult api-pod-delete-pod-delete -n default -o yaml

The experiment above does the following: it targets pods with the label app=api-server, deletes them every 10 seconds for a total of 30 seconds, and continuously probes the health endpoint to verify the service remains available. If the health probe fails during the experiment, the chaos result reports a Fail verdict -- meaning your system did not maintain steady state.

Interpreting results:

# Successful experiment (system is resilient)
status:
  experimentStatus:
    verdict: Pass
    phase: Completed
    probeSuccessPercentage: "100"

# Failed experiment (weakness found)
status:
  experimentStatus:
    verdict: Fail
    phase: Completed
    probeSuccessPercentage: "60"
    failStep: "check-api-health probe failed during chaos"

A Pass verdict means your hypothesis held -- the system tolerated pod deletion. A Fail verdict means you discovered a resilience gap that needs fixing, typically in areas like readiness probes, replica counts, or Pod Disruption Budgets.


GameDay Exercises

A GameDay is a structured, team-based chaos engineering session where engineers deliberately introduce failures and practice their incident response. Think of it as a fire drill for your production systems.

GameDays transform chaos engineering from a solo activity into an organizational capability. They build muscle memory for incident response and create shared understanding of system behavior under failure.

Planning Checklist:

  • Define scope -- Which systems and failure modes will you test?
  • Set objectives -- What do you want to learn? (e.g., "Validate our Redis failover completes within 30 seconds")
  • Choose timing -- Schedule during business hours when the team is fully staffed
  • Notify stakeholders -- Inform support teams, on-call engineers, and management
  • Prepare rollback -- Document exactly how to stop each experiment immediately
  • Set up monitoring -- Ensure dashboards and alerts are visible to all participants
  • Define abort criteria -- Specify the conditions that trigger an immediate halt (e.g., customer-facing error rate exceeds 1%)

Roles:

  • GameDay Lead: Coordinates the session, manages timing, decides when to abort
  • Chaos Operator: Executes the fault injection experiments
  • Observer: Monitors dashboards, captures metrics, takes screenshots
  • Incident Commander: Practices the incident response process as if it were a real outage
  • Scribe: Documents everything -- what happened, when, what the team decided

Communication Protocol:

1. GameDay Lead announces: "Starting experiment: Redis primary failover"
2. Chaos Operator confirms: "Experiment injected. Redis primary terminated."
3. Observer reports: "Latency spike detected on dashboard. p99 at 2.3s."
4. Incident Commander responds: "Monitoring for recovery. Failover in progress."
5. Observer reports: "Latency normalizing. p99 back to 180ms after 45 seconds."
6. GameDay Lead announces: "Experiment complete. Moving to post-mortem."

Post-Mortem Template:

After each experiment, capture the following:

  1. Hypothesis -- What did you expect to happen?
  2. Actual behavior -- What actually happened?
  3. Steady state impact -- Which metrics deviated and by how much?
  4. Recovery time -- How long until the system returned to normal?
  5. Surprises -- What did the team not expect?
  6. Action items -- What needs to be fixed, improved, or investigated further?

Schedule GameDays quarterly at minimum. Monthly is better. The more you practice, the more natural incident response becomes.


Chaos Engineering for Web Applications

Chaos engineering is not limited to backend infrastructure. Frontend resilience is equally important -- and often neglected. Your users interact with the frontend, and that is where they experience failures.

API Timeout Handling

What happens when your API takes 30 seconds to respond instead of 300 milliseconds? Does the UI hang? Does the user see a loading spinner forever? Or does the application gracefully timeout and show a helpful error message?

// Test that your fetch calls have proper timeout handling
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);

try {
  const response = await fetch('/api/data', {
    signal: controller.signal,
  });
  clearTimeout(timeout);
  return response.json();
} catch (error) {
  if (error.name === 'AbortError') {
    // Show user-friendly timeout message
    showNotification('Request timed out. Please try again.');
  }
  throw error;
}

Offline Mode Testing

Progressive web applications should handle network loss gracefully. Test what happens when you go offline mid-session:

  • Does unsaved data persist in local storage or IndexedDB?
  • Does the UI indicate the offline state clearly?
  • Do queued requests replay when connectivity returns?
  • Do service workers serve cached content for critical pages?

Retry Logic Verification

When an API call fails with a 503, does your application retry with exponential backoff? Or does it hammer the already-struggling server with rapid retries? Test both the retry behavior and the backoff timing.

Testing Techniques for Frontend Resilience:

  • Network throttling: Use browser DevTools or Playwright network emulation to simulate slow 3G connections
  • Service worker failures: Unregister service workers mid-session to test fallback behavior
  • Local storage corruption: Clear or corrupt local storage entries to test recovery paths
  • Third-party script failures: Block CDN requests for analytics, chat widgets, and ad scripts to verify the core application still functions

Frontend resilience testing overlaps heavily with the testing patterns covered in our flaky tests guide -- many flaky E2E tests are actually detecting real resilience issues that teams dismiss as test problems.


CI/CD Integration

Chaos experiments become most valuable when they run automatically as part of your deployment pipeline. But you need to be strategic about when and how you run them -- chaos tests in CI should validate known resilience properties, not explore new failure modes.

Where Chaos Tests Fit in the Pipeline:

Unit Tests -> Integration Tests -> Deploy to Staging -> Chaos Tests -> Promote to Production

Chaos tests run after deployment to staging but before promotion to production. They validate that the deployment did not regress any previously verified resilience properties.

Automated Chaos in CI:

# .github/workflows/resilience.yml
name: Resilience Tests
on:
  workflow_dispatch:
  schedule:
    - cron: '0 3 * * 1'  # Weekly on Monday at 3 AM

jobs:
  chaos-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Deploy to staging
        run: kubectl apply -f k8s/staging/

      - name: Wait for rollout
        run: kubectl rollout status deployment/api-server -n staging --timeout=300s

      - name: Run pod-delete chaos experiment
        run: |
          kubectl apply -f chaos/pod-delete-experiment.yaml
          sleep 60
          VERDICT=$(kubectl get chaosresult -n staging -o jsonpath='{.items[0].status.experimentStatus.verdict}')
          if [ "$VERDICT" != "Pass" ]; then
            echo "Chaos experiment failed: pod-delete"
            exit 1
          fi

      - name: Run network-latency chaos experiment
        run: |
          kubectl apply -f chaos/network-latency-experiment.yaml
          sleep 90
          VERDICT=$(kubectl get chaosresult -n staging -o jsonpath='{.items[1].status.experimentStatus.verdict}')
          if [ "$VERDICT" != "Pass" ]; then
            echo "Chaos experiment failed: network-latency"
            exit 1
          fi

      - name: Promote to production
        if: success()
        run: kubectl apply -f k8s/production/

When to Run Chaos Tests:

  • Not on every commit -- chaos tests are slow (minutes, not seconds) and require deployed infrastructure
  • On staging deployments -- validate resilience before production promotion
  • On a weekly schedule -- catch regressions from infrastructure changes, dependency updates, and configuration drift
  • Before major releases -- run the full chaos test suite as a release gate

Steady State Assertions:

Define your steady state as code so it can be verified programmatically:

// chaos/assertions.ts
interface SteadyStateCheck {
  name: string;
  check: () => Promise<boolean>;
}

const steadyStateChecks: SteadyStateCheck[] = [
  {
    name: 'API responds within 500ms',
    check: async () => {
      const start = Date.now();
      const res = await fetch('https://staging.example.com/health');
      return res.ok && Date.now() - start < 500;
    },
  },
  {
    name: 'Error rate below 1%',
    check: async () => {
      const metrics = await fetchPrometheusMetric('http_errors_total');
      return metrics.rate < 0.01;
    },
  },
];

Rollback Triggers:

Integrate chaos test results with your deployment pipeline's rollback mechanism. If a chaos experiment fails in staging, block the production promotion and alert the team. For more details on building robust CI/CD pipelines with automated testing gates, see our CI/CD testing pipeline guide.


Automate Resilience Testing with AI Agents

AI coding agents can accelerate resilience testing by generating test cases, identifying missing error handling, and verifying recovery paths. QASkills provides specialized skills for exactly these patterns.

Error Boundary Testing:

npx @qaskills/cli add error-boundary-tester

This skill teaches your AI agent to verify that React error boundaries catch component failures gracefully, test fallback UI rendering, and ensure that errors in one component do not cascade across the application.

Offline Mode Testing:

npx @qaskills/cli add offline-mode-tester

This skill focuses on progressive web app resilience -- testing service worker behavior, local storage persistence, request queuing, and network recovery flows.

Additional Resilience Skills:

# Find race conditions in concurrent code
npx @qaskills/cli add race-condition-finder

# Detect memory leaks that cause gradual degradation
npx @qaskills/cli add memory-leak-detector

The race-condition-finder skill is particularly relevant for chaos engineering because race conditions often only manifest under load or when services respond at unexpected speeds -- exactly the conditions that chaos experiments create.

The memory-leak-detector skill helps identify the slow degradation that chaos engineering alone might miss. A service that leaks 10MB per hour works fine during a 30-second chaos experiment but fails catastrophically under sustained production load.

Browse all available resilience and reliability testing skills at qaskills.sh/skills. For a guided setup that detects your agent and installs the right skills, visit getting started.


Frequently Asked Questions

Is chaos engineering safe for production?

Yes, when done correctly. The key is minimizing blast radius -- start with the smallest possible experiment and scale up gradually. Use abort conditions that automatically stop the experiment if customer impact exceeds your threshold. Major companies like Netflix, Amazon, Google, and Microsoft run chaos experiments in production daily. The risk of not testing resilience is far greater than the risk of a controlled experiment.

How is chaos engineering different from traditional testing?

Traditional testing verifies that your application works correctly under expected conditions. Chaos engineering verifies that your system stays available under unexpected conditions. Unit tests check logic, integration tests check component interactions, and chaos tests check that the overall system tolerates real-world failures like network partitions, server crashes, and dependency outages. They complement each other -- you need both.

When should a team start doing chaos engineering?

Start after you have basic observability in place -- monitoring, alerting, and dashboards that show system health. You cannot run meaningful chaos experiments if you cannot observe the results. You also need your application to be deployed in a way that is designed for some level of redundancy (multiple replicas, load balancing). A single-server application will obviously fail when you kill the server -- that experiment teaches you nothing new.

Can you do chaos engineering without Kubernetes?

Absolutely. Chaos engineering predates Kubernetes by several years. Chaos Monkey was built for AWS EC2 instances. Toxiproxy works at the TCP level and runs anywhere. AWS Fault Injection Service targets ECS, EC2, and RDS directly. For web application frontend testing, you just need a browser and network throttling tools. Kubernetes-native tools like Litmus and Chaos Mesh are popular because Kubernetes is a common deployment target, but the principles and many tools apply to any infrastructure.

How do you measure the success of a chaos engineering program?

Track these metrics over time: Mean Time to Recovery (MTTR) -- does it decrease as you run more experiments? Incident frequency -- are you finding and fixing weaknesses before they cause real incidents? Blast radius of real incidents -- when outages do happen, are they smaller and more contained? Experiment count -- are you running more experiments and covering more failure modes? A mature chaos engineering program should show improving MTTR, fewer customer-impacting incidents, and a growing library of validated resilience properties.

Chaos Engineering -- Resilience Testing for Modern Applications | QASkills.sh