이 글에서 얻는 것

  • Chaos Engineering 5대 원칙과 왜 필요한지 이해합니다
  • Steady-State Hypothesis를 설계하고 실험 시나리오를 작성할 수 있습니다
  • LitmusChaos, AWS FIS, Chaos Toolkit 실전 구현으로 장애를 주입합니다
  • GameDay 프로세스를 기획하고 운영할 수 있습니다
  • Chaos 성숙도 모델로 조직의 현재 수준을 진단하고 로드맵을 세울 수 있습니다

1. Chaos Engineering이란?

“시스템이 예기치 않은 상황에서도 기대한 대로 동작하는가를 검증하기 위해, 의도적으로 장애를 주입하는 실험적 접근”

왜 필요한가?

전통 테스트Chaos Engineering
“이 기능이 동작하는가?”“이 기능이 장애 상황에서도 동작하는가?”
행복 경로(Happy Path) 중심실패 경로(Failure Path) 중심
단위·통합 테스트로 커버분산 시스템의 창발적 장애 발견
배포 전 실행프로덕션에서도 실행

Netflix가 2011년 Chaos Monkey를 만든 이유: “언제든 인스턴스가 죽을 수 있다"는 가정 하에 설계하라.

5대 원칙 (Principles of Chaos Engineering)

1. 정상 상태(Steady State) 정의
   → "정상"을 비즈니스 메트릭으로 수치화

2. 가설 수립
   → "장애 X를 주입해도 정상 상태가 유지될 것이다"

3. 실제 이벤트 재현
   → 서버 다운, 네트워크 지연, 디스크 풀, DNS 실패 등

4. 폭발 반경(Blast Radius) 최소화
   → 작게 시작, 점진적 확대, 즉시 중단 가능

5. 자동화와 지속 실행
   → CI/CD 통합, 정기 실행으로 회귀 방지

2. 실험 설계: Steady-State Hypothesis

모든 Chaos 실험의 핵심은 **“정상 상태를 먼저 정의하는 것”**입니다.

Steady-State 정의 프레임워크

계층메트릭정상 기준 (예시)측정 방법
비즈니스주문 성공률≥ 99.9%주문 API 응답 2xx 비율
서비스응답 시간 p99< 500msPrometheus histogram
인프라에러율< 0.1%ALB 5xx / total
의존성Circuit Breaker Open 횟수0Resilience4j 메트릭

실험 시나리오 설계 템플릿

## 실험: [실험 이름]

### 배경
- 대상 서비스: [서비스 A]
- 의존성: [DB, Cache, 외부 API]
- 최근 관련 장애: [있으면 기재]

### Steady-State Hypothesis
- 주문 API 응답 시간 p99 < 500ms
- 에러율 < 0.1%
- Circuit Breaker 미작동 (Closed 상태)

### 실험 방법
- **장애 유형**: [서비스 B Pod 50% Kill]
- **범위**: [Namespace: staging, 트래픽의 10%]
- **지속 시간**: [5분]

### 중단 조건 (Abort Criteria)
- 에러율 > 5%
- p99 > 3초
- 비즈니스 메트릭 이상

### 롤백 절차
1. 실험 즉시 중단 (kill experiment)
2. [kubectl rollout restart deployment/service-b]
3. 메트릭 정상 복구 확인

### 예상 결과
- Circuit Breaker가 Open되어 fallback 응답 반환
- 전체 에러율 0.1% 미만 유지

### 실제 결과
- [ ] 가설 유지 / 가설 깨짐
- 발견 사항: [기재]
- 개선 사항: [기재]

3. 장애 유형 카탈로그

인프라 레벨

장애 유형설명도구
Pod Kill특정 Pod 강제 종료LitmusChaos, Chaos Mesh
Node Drain노드 전체 Pod 퇴거kubectl, AWS FIS
CPU StressCPU 사용률 강제 증가stress-ng, LitmusChaos
Memory Stress메모리 압박stress-ng
Disk Fill디스크 용량 소진dd, fallocate
AZ 장애가용 영역 전체 격리AWS FIS

네트워크 레벨

장애 유형설명도구
Network Latency지연 주입 (100ms~5s)tc netem, Toxiproxy
Packet Loss패킷 손실 (1%~50%)tc netem
DNS FailureDNS 조회 실패LitmusChaos, CoreDNS 조작
Network Partition서비스 간 통신 차단iptables, Chaos Mesh

애플리케이션 레벨

장애 유형설명도구
Exception Injection특정 API에 500 에러 주입Toxiproxy, 코드 내 chaos flag
Slow Response응답 지연 주입Toxiproxy
Connection Pool ExhaustionDB 커넥션 고갈pgbench, 커스텀 스크립트
Cache FailureRedis 다운Pod Kill, Failover 테스트

4. 실전 구현: LitmusChaos (Kubernetes)

설치

# LitmusChaos 3.x 설치 (Helm)
helm repo add litmuschaos https://litmuschaos.github.io/litmus-helm/
helm install litmus litmuschaos/litmus \
  --namespace litmus --create-namespace \
  --set portal.frontend.service.type=ClusterIP

Pod Kill 실험

# pod-kill-experiment.yaml
apiVersion: litmuschaos.io/v1alpha1
kind: ChaosEngine
metadata:
  name: order-service-chaos
  namespace: staging
spec:
  appinfo:
    appns: staging
    applabel: "app=order-service"
    appkind: deployment
  engineState: active
  chaosServiceAccount: litmus-admin
  experiments:
    - name: pod-delete
      spec:
        components:
          env:
            - name: TOTAL_CHAOS_DURATION
              value: "300"        # 5분간 실험
            - name: CHAOS_INTERVAL
              value: "30"         # 30초마다 Pod Kill
            - name: FORCE
              value: "false"      # Graceful shutdown
            - name: PODS_AFFECTED_PERC
              value: "50"         # 50% Pod만 대상
        probe:
          - name: "order-api-health"
            type: httpProbe
            mode: Continuous
            httpProbe/inputs:
              url: "http://order-service.staging:8080/actuator/health"
              method:
                get:
                  criteria: ==
                  responseCode: "200"
            runProperties:
              probeTimeout: 5s
              interval: 10s
              retry: 3
              probePollingInterval: 2s
# 실험 실행
kubectl apply -f pod-kill-experiment.yaml

# 실험 상태 확인
kubectl get chaosengine order-service-chaos -n staging -o yaml

# 실험 결과 확인
kubectl get chaosresult order-service-chaos-pod-delete -n staging -o yaml

Network Latency 실험

apiVersion: litmuschaos.io/v1alpha1
kind: ChaosEngine
metadata:
  name: network-latency-chaos
  namespace: staging
spec:
  appinfo:
    appns: staging
    applabel: "app=payment-service"
    appkind: deployment
  engineState: active
  chaosServiceAccount: litmus-admin
  experiments:
    - name: pod-network-latency
      spec:
        components:
          env:
            - name: NETWORK_INTERFACE
              value: "eth0"
            - name: NETWORK_LATENCY
              value: "500"       # 500ms 지연
            - name: JITTER
              value: "100"       # ±100ms 변동
            - name: TOTAL_CHAOS_DURATION
              value: "300"
            - name: DESTINATION_IPS
              value: "10.0.10.0/24"  # DB 서브넷만 대상
        probe:
          - name: "payment-p99-check"
            type: promProbe
            mode: Continuous
            promProbe/inputs:
              endpoint: "http://prometheus.monitoring:9090"
              query: >
                histogram_quantile(0.99,
                  rate(http_server_requests_seconds_bucket{
                    service="payment-service"
                  }[1m]))
              comparator:
                type: float
                criteria: "<="
                value: "2.0"     # p99 < 2초 이내 유지되어야 함
            runProperties:
              probeTimeout: 10s
              interval: 15s

5. 실전 구현: AWS Fault Injection Service (FIS)

AWS 매니지드 서비스를 대상으로 하는 Chaos 실험에 최적화된 도구입니다.

AZ 장애 시뮬레이션

{
  "description": "AZ-a 장애 시뮬레이션",
  "targets": {
    "ec2-instances": {
      "resourceType": "aws:ec2:instance",
      "resourceTags": {
        "Application": "myapp"
      },
      "filters": [
        {
          "path": "Placement.AvailabilityZone",
          "values": ["ap-northeast-2a"]
        }
      ],
      "selectionMode": "ALL"
    }
  },
  "actions": {
    "stop-instances": {
      "actionId": "aws:ec2:stop-instances",
      "parameters": {
        "startInstancesAfterDuration": "PT10M"
      },
      "targets": {
        "Instances": "ec2-instances"
      }
    }
  },
  "stopConditions": [
    {
      "source": "aws:cloudwatch:alarm",
      "value": "arn:aws:cloudwatch:ap-northeast-2:123456789012:alarm:chaos-abort-alarm"
    }
  ],
  "roleArn": "arn:aws:iam::123456789012:role/FISExperimentRole"
}

RDS Failover 테스트

{
  "description": "RDS Multi-AZ Failover 테스트",
  "actions": {
    "rds-failover": {
      "actionId": "aws:rds:reboot-db-instances",
      "parameters": {
        "forceFailover": "true"
      },
      "targets": {
        "DBInstances": "rds-target"
      }
    }
  },
  "targets": {
    "rds-target": {
      "resourceType": "aws:rds:db",
      "resourceArns": [
        "arn:aws:rds:ap-northeast-2:123456789012:db:myapp-db"
      ],
      "selectionMode": "ALL"
    }
  },
  "stopConditions": [
    {
      "source": "aws:cloudwatch:alarm",
      "value": "arn:aws:cloudwatch:ap-northeast-2:123456789012:alarm:db-connection-alarm"
    }
  ]
}

Terraform으로 FIS 관리

resource "aws_fis_experiment_template" "az_failure" {
  description = "AZ-a failure simulation"
  role_arn    = aws_iam_role.fis.arn

  stop_condition {
    source = "aws:cloudwatch:alarm"
    value  = aws_cloudwatch_metric_alarm.chaos_abort.arn
  }

  action {
    name      = "stop-instances"
    action_id = "aws:ec2:stop-instances"

    parameter {
      key   = "startInstancesAfterDuration"
      value = "PT10M"
    }

    target {
      key   = "Instances"
      value = "ec2-targets"
    }
  }

  target {
    name           = "ec2-targets"
    resource_type  = "aws:ec2:instance"
    selection_mode = "ALL"

    resource_tag {
      key   = "Application"
      value = "myapp"
    }

    filter {
      path   = "Placement.AvailabilityZone"
      values = ["ap-northeast-2a"]
    }
  }

  tags = { Name = "az-failure-test" }
}

6. 실전 구현: Chaos Toolkit (범용)

어떤 인프라에서든 사용할 수 있는 Python 기반 오픈소스 프레임워크입니다.

설치 및 기본 실험

pip install chaostoolkit chaostoolkit-kubernetes chaostoolkit-prometheus
# experiment-service-down.yaml
version: 1.0.0
title: "주문 서비스 장애 시 결제 서비스 회복력 검증"
description: >
  주문 서비스 Pod를 50% 종료했을 때,
  결제 서비스의 Circuit Breaker가 정상 동작하고
  전체 에러율이 1% 미만으로 유지되는지 검증

tags:
  - kubernetes
  - circuit-breaker
  - order-service

contributions:
  reliability: high
  security: none

# 1단계: 정상 상태 정의
steady-state-hypothesis:
  title: "결제 서비스 정상 동작 확인"
  probes:
    - name: "결제 API 응답 코드 200"
      type: probe
      provider:
        type: http
        url: "http://payment-service.staging:8080/actuator/health"
        timeout: 5
      tolerance:
        status: 200

    - name: "에러율 1% 미만"
      type: probe
      provider:
        type: python
        module: chaosprometheus.probes
        func: query_instant
        arguments:
          query: >
            sum(rate(http_server_requests_seconds_count{
              service="payment-service", status=~"5.."}[5m]))
            /
            sum(rate(http_server_requests_seconds_count{
              service="payment-service"}[5m]))
          api_url: "http://prometheus.monitoring:9090"
      tolerance:
        type: range
        range: [0.0, 0.01]

# 2단계: 장애 주입
method:
  - type: action
    name: "주문 서비스 Pod 50% 종료"
    provider:
      type: python
      module: chaosk8s.pod.actions
      func: terminate_pods
      arguments:
        label_selector: "app=order-service"
        ns: staging
        qty: 2
        rand: true
        grace_period: 30
    pauses:
      after: 30   # 30초 대기 후 Steady-State 재검증

  - type: probe
    name: "Circuit Breaker 상태 확인"
    provider:
      type: python
      module: chaosprometheus.probes
      func: query_instant
      arguments:
        query: >
          resilience4j_circuitbreaker_state{
            name="orderServiceCB", application="payment-service"} == 1
        api_url: "http://prometheus.monitoring:9090"
    tolerance: true   # Circuit Breaker가 Open(1)이면 정상

# 3단계: 롤백
rollbacks:
  - type: action
    name: "주문 서비스 복원"
    provider:
      type: python
      module: chaosk8s.deployment.actions
      func: rollout_restart
      arguments:
        name: order-service
        ns: staging
# 실험 실행
chaos run experiment-service-down.yaml

# 실험 보고서 생성
chaos report --export-format=pdf journal.json report.pdf

7. GameDay 운영 가이드

GameDay는 Chaos Engineering을 조직 차원의 훈련으로 확장한 것입니다.

GameDay 프로세스

1주 전: 계획
├── 대상 서비스·실험 시나리오 선정
├── 참가자 역할 지정 (Driver / Observer / Scribe)
├── 중단 기준(Abort Criteria) 합의
└── Runbook·롤백 절차 준비

당일: 실행
├── 09:00 킥오프 (목적·범위·안전장치 공유)
├── 09:30 Steady-State 베이스라인 측정
├── 10:00 실험 1: Pod Kill
├── 10:30 실험 2: Network Latency
├── 11:00 실험 3: DB Failover
├── 11:30 실험 4: AZ 장애
└── 12:00 정리·복원 확인

당일: 회고
├── 발견된 약점 목록화
├── 개선 액션 아이템·담당자·기한 확정
├── 다음 GameDay 주제 선정
└── 전사 공유 (결과 요약)

GameDay 체크리스트

단계항목확인
사전실험 시나리오 문서화 완료
사전Rollback 절차 검증 완료
사전모니터링 대시보드 준비
사전Abort 알람 설정 완료
사전이해관계자(PM·CTO) 통보
실행Steady-State 베이스라인 기록
실행각 실험 시작/종료 시간 기록
실행이상 징후 즉시 Scribe 기록
사후발견 사항 JIRA 티켓 생성
사후회고 문서 작성 및 공유

역할 정의

역할책임인원
Driver실험 실행, 장애 주입/해제1명
Observer대시보드·메트릭 실시간 감시2~3명
Scribe타임라인·발견 사항 실시간 기록1명
Incident Commander중단 판단, 에스컬레이션1명 (시니어)
On-call Standby실제 장애 전파 시 긴급 대응1~2명

8. 관측성(Observability) 연계

Chaos 실험은 관측 없이 실행하면 의미가 없습니다. 실험 중 반드시 모니터링해야 할 항목:

실험 중 관측 대시보드

┌─────────────────────────────────────────────────┐
│  Chaos Experiment: order-service-pod-kill         │
│  Status: RUNNING  |  Duration: 03:24             │
├─────────────────────────────────────────────────┤
│  📊 Golden Signals                               │
│  ├── Error Rate: 0.02% (Threshold: < 1%)  ✅    │
│  ├── Latency p99: 420ms (Threshold: < 500ms) ✅ │
│  ├── Traffic: 1,200 req/s (Normal: 1,100)  ✅   │
│  └── Saturation: CPU 45%, Mem 62%          ✅   │
├─────────────────────────────────────────────────┤
│  🔧 Resilience Signals                           │
│  ├── Circuit Breaker: CLOSED → OPEN (예상대로)   │
│  ├── Retry Count: 23 (Budget 100)          ✅   │
│  ├── Fallback Invoked: 18회               ✅    │
│  └── Pod Ready: 2/4 (50% Kill)            ✅    │
├─────────────────────────────────────────────────┤
│  ⚠️ Downstream Impact                            │
│  ├── Payment Service: Healthy              ✅    │
│  ├── Notification: Healthy                 ✅    │
│  └── Frontend: Degraded (order 버튼 비활성) ⚠️   │
└─────────────────────────────────────────────────┘

Prometheus 쿼리 예시

# 실험 전후 에러율 비교
sum(rate(http_server_requests_seconds_count{status=~"5.."}[5m]))
/
sum(rate(http_server_requests_seconds_count[5m]))

# Circuit Breaker 상태 변화
resilience4j_circuitbreaker_state{application="payment-service"}

# Pod Restart 횟수
increase(kube_pod_container_status_restarts_total{
  namespace="staging", pod=~"order-service.*"
}[1h])

# Fallback 호출 횟수
increase(resilience4j_circuitbreaker_calls_total{
  kind="fallback"
}[5m])

Grafana Annotation으로 실험 구간 표시

# 실험 시작 시 Annotation 생성
curl -X POST http://grafana:3000/api/annotations \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $GRAFANA_TOKEN" \
  -d '{
    "dashboardUID": "chaos-dashboard",
    "time": '$(date +%s000)',
    "tags": ["chaos", "pod-kill", "order-service"],
    "text": "Chaos Experiment Started: order-service pod-kill 50%"
  }'

9. Chaos 성숙도 모델

5단계 성숙도

레벨이름특징도구빈도
L1Ad-hockubectl delete pod 수동 실행없음비정기
L2ScriptedChaos Toolkit 실험 파일 작성Chaos Toolkit월 1회
L3AutomatedCI/CD에 Chaos 테스트 통합LitmusChaos + CI주 1회
L4Continuous프로덕션에서 상시 실행AWS FIS + 자동 Abort매일
L5Culture전 팀이 자체 실험 설계·실행셀프서비스 플랫폼상시

성숙도 진단 체크리스트

L1 → L2 전환 조건:
☐ Steady-State Hypothesis 문서화 습관
☐ 최소 3개 실험 시나리오 작성 완료
☐ 롤백 절차 테스트 완료

L2 → L3 전환 조건:
☐ 스테이징 환경에서 주기적 실행 (주 1회 이상)
☐ CI 파이프라인에 Chaos 단계 추가
☐ 실험 결과 자동 리포팅

L3 → L4 전환 조건:
☐ 프로덕션 Canary 실험 1건 이상 성공
☐ 자동 Abort 메커니즘 검증
☐ 온콜 팀과 협의·훈련 완료
☐ GameDay 분기 1회 이상 진행

L4 → L5 전환 조건:
☐ 팀별 자체 실험 설계·실행
☐ Chaos 실험 커버리지 메트릭 존재
☐ 경영진 보고 포함 (SLA/SLO 연계)

도입 로드맵 (권장 12개월)

Month 1-2:  L1 → L2
├── Chaos Toolkit 설치, 첫 실험 3건 작성
├── 스테이징 환경에서 Pod Kill / Network Latency 실행
└── 팀 내 Chaos 소개 세션

Month 3-4:  L2 → L3
├── LitmusChaos 도입 (K8s 환경)
├── CI 파이프라인에 nightly chaos job 추가
└── 실험 결과 Slack 자동 알림

Month 5-8:  L3 → L4
├── 프로덕션 Canary 실험 시작 (트래픽 1%)
├── AWS FIS로 AZ 장애·RDS Failover 테스트
├── 첫 GameDay 실시
└── 온콜 팀 훈련

Month 9-12: L4 → L5
├── 팀별 셀프서비스 실험 플랫폼
├── Chaos 커버리지 대시보드
└── 분기별 GameDay 정례화

10. 안티패턴과 주의사항

반드시 피해야 할 실수

안티패턴문제해결
YOLO ChaosAbort 조건 없이 프로덕션 실험반드시 중단 알람 설정
관측 없는 실험장애 주입했는데 결과를 모름Probe/Metric 필수 연계
Big Bang처음부터 프로덕션 100% 대상스테이징 → 카나리 → 점진 확대
1회성 실험한 번 하고 끝CI/CD 통합, 정기 실행
비밀 실험팀에 알리지 않고 실행이해관계자 사전 통보 필수
Fix-less Chaos발견만 하고 개선 안 함실험 → 티켓 → 수정 → 재실험

Chaos Engineering ≠ 부하 테스트

항목Chaos Engineering부하 테스트
목적회복력 검증성능 한계 측정
방법장애 주입트래픽 증가
측정정상 상태 유지 여부TPS, 응답 시간, 에러율
환경스테이징 + 프로덕션주로 스테이징
빈도상시배포 전·정기

운영 체크리스트

실험 전

  • Steady-State Hypothesis 작성 (비즈니스 메트릭 포함)
  • 실험 시나리오 문서화 (배경/방법/중단 조건/롤백)
  • 모니터링 대시보드 준비 (Golden Signals + Resilience)
  • Abort 알람 설정 완료
  • 이해관계자 통보

실험 중

  • 베이스라인 메트릭 기록
  • 실시간 대시보드 감시
  • 이상 징후 즉시 기록
  • Abort 기준 초과 시 즉시 중단

실험 후

  • 실험 결과 정리 (가설 유지/깨짐)
  • 발견 사항 JIRA 티켓 생성
  • 개선 후 재실험 계획
  • 회고 문서 공유

요약

  1. 정상 상태를 먼저 정의: 숫자로 측정 가능한 비즈니스 메트릭
  2. 작게 시작, 점진적 확대: 스테이징 → 프로덕션 카나리 → 전체
  3. 도구 선택: LitmusChaos(K8s), AWS FIS(AWS 매니지드), Chaos Toolkit(범용)
  4. 관측이 핵심: 장애 주입 + 메트릭 모니터링 = 학습
  5. 문화로 만들기: GameDay 정례화, 성숙도 모델 단계적 향상

관련 글