TT Lab
시작하기
배우기 러닝패스 코스

내가 부순다 — 가설을 먼저 쓰는 카오스 실험실

망가뜨리기 실험실 — 다섯 번 부수고 한 번 고친다

TT Lab 에서 이어서 보기

목표

임시 VM 안의 진짜 k3s 위에서 다섯 번의 카오스 실험을 합니다. 정상 기준선을 재고, 다섯 실험의 가설을 부수기 전에 한꺼번에 적고, Pod 를 죽이고 CPU 를 조이고 메모리를 말린 뒤, 배운 것을 설계에 반영해 같은 공격을 다시 받습니다. kubectl 의 기본 조회와 Deployment 구조를 아는 중급 학습자를 위한 65분 실험입니다.

왜 중요한가

장애를 주입하는 일 자체는 명령 한 줄입니다. 어려운 것은 그 실험이 다음 주에도 남는 무언가를 만들게 하는 일입니다. 그래서 이 실습의 산출물은 고장이 아니라 노트입니다. 가설은 실험 전에 적고, 측정은 실험 창 안에서 하고, 결론은 둘을 견준 결과로 적습니다. 예상이 빗나가는 것은 실패가 아닙니다 — 반증된 가설이야말로 그 실험이 벌 수 있는 가장 비싼 정보이고, 그것을 refuted 라고 적는 것이 정답입니다.

판정 표 (결론에서 쓸 이름)

같은 숫자를 사람마다 다르게 읽지 않도록 이름 붙이는 규칙을 먼저 정해 둡니다.

측정 도구

python3 /opt/fixtures/chaos_lab.py 는 세 가지만 합니다. 고장을 대신 내주지도, 고쳐 주지도 않습니다.

안전 범위

임시 VM 안의 API https://127.0.0.1:6443 과 labhub-chaos 네임스페이스만 씁니다. 운영 클러스터나 다른 사람의 환경에서는 절대 실행하지 마세요. 제공 앱은 원인을 하나만 남기기 위해 Recreate 전략을 씁니다 — 무중단 운영 권장값이라는 뜻이 아닙니다. 앱 이미지는 digest 로 고정되어 있습니다.

이 실습은 65분으로 잡혀 있어 기본 세션(60분)보다 깁니다. 시작할 때 미리 시간을 연장하세요. 세션이 끝나면 VM 과 기록 파일은 사라지고 되살릴 수 없습니다. 기록 파일은 편집 가능한 실험 노트이지 위조 불가능한 증거가 아닙니다.

단계

  1. /opt/fixtures/chaos-lab-app.json 을 적용하고 롤아웃이 끝나기를 기다린 뒤, 아무것도 건드리지 않은 상태로 20초 부하를 걸어 기준선을 기록하세요. python3 /opt/fixtures/chaos_lab.py load 20 /root/chaos-lab/raw-01.json 으로 재고 python3 /opt/fixtures/chaos_lab.py record steady /root/chaos-lab/raw-01.json /root/chaos-lab/01-steady.json 으로 남깁니다.
  2. 기준선 파일에서 성공률과 p95 를 읽어 steady_state 에 정상 상태를 적고, 다섯 실험(kill-one · kill-ha · cpu-squeeze · mem-squeeze · hardened)의 가설을 /root/chaos-lab/hypothesis.json 에 쓰세요. 실험마다 availability, latency, 왜 그렇게 예상하는지(why), 언제 멈출지(abort_if) 네 가지가 필요합니다. availability_ratio_min 은 0.95 이상이면서 기준선 측정값 이하, p95_ms_max 는 기준선 p95 이상 그 3배 이하로 잡습니다.
  3. 복제본이 1인 상태에서 부하를 배경으로 띄우고, 측정 창 안에서 그 하나뿐인 Pod 를 지우세요. 창이 닫히면 python3 /opt/fixtures/chaos_lab.py record kill-one /root/chaos-lab/raw-03.json /root/chaos-lab/03-kill-one.json 으로 남깁니다. 자원 한계와 preStop 은 기준선 그대로 두세요.
  4. 복제본을 3으로 늘려 셋이 모두 Ready 가 된 뒤, 같은 방식으로 부하 창 안에서 Pod 를 정확히 하나만 지우세요. python3 /opt/fixtures/chaos_lab.py record kill-ha /root/chaos-lab/raw-04.json /root/chaos-lab/04-kill-ha.json 으로 남깁니다. 복제본 수 말고는 아무것도 바꾸지 않습니다.
  5. shop 컨테이너의 cpu 한계만 100m 으로 낮추세요(memory 는 96Mi, 복제본은 3 그대로). 롤아웃이 끝나고 셋이 모두 Ready 가 된 뒤에 20초 부하를 걸고 python3 /opt/fixtures/chaos_lab.py record cpu-squeeze /root/chaos-lab/raw-05.json /root/chaos-lab/05-cpu-squeeze.json 으로 남깁니다.
  6. cpu 한계를 500m 으로 되돌리면서 memory 한계를 40Mi 로 낮추세요. 앱은 기동할 때 48MiB 를 한 번에 잡으므로 컨테이너가 OOM 으로 죽습니다. 재시작이 잡히면 20초 부하를 걸고 python3 /opt/fixtures/chaos_lab.py record mem-squeeze /root/chaos-lab/raw-06.json /root/chaos-lab/06-mem-squeeze.json 으로 남깁니다.
  7. 자원 한계를 정상값(cpu 500m · memory 96Mi)으로 되돌리면서, 이번에는 종료 처리를 더하세요. preStop 훅으로 최소 3초를 벌고 terminationGracePeriodSeconds 를 10 이상으로 올립니다. 롤아웃이 끝나면 3단계·4단계와 같은 공격을 다시 하고 python3 /opt/fixtures/chaos_lab.py record hardened /root/chaos-lab/raw-07.json /root/chaos-lab/07-hardened.json 으로 남깁니다.
  8. 다섯 기록의 숫자에 지시문의 판정 표대로 이름을 붙여 /root/chaos-lab/conclusion.json 에 쓰세요. 실험마다 observed_availability, observed_latency, 가설과 견준 verdict(confirmed 또는 refuted), 그리고 이 결과로 무엇을 바꿀지(action)가 필요합니다. 마지막 채점은 앞선 기록과 지금 클러스터를 함께 봅니다 — 고친 설계가 살아 있어야 합니다.

참고

부수기 전에 「정상」을 숫자로 남긴다

/opt/fixtures/chaos-lab-app.json 을 적용하고 롤아웃이 끝나기를 기다린 뒤, 아무것도 건드리지 않은 상태로 20초 부하를 걸어 기준선을 기록하세요. python3 /opt/fixtures/chaos_lab.py load 20 /root/chaos-lab/raw-01.json 으로 재고 python3 /opt/fixtures/chaos_lab.py record steady /root/chaos-lab/raw-01.json /root/chaos-lab/01-steady.json 으로 남깁니다.

Running·Ready·실제 요청 성공은 서로 다른 사실입니다. Ready endpoint 가 1개가 된 뒤에 재세요. 측정 창 안에 새 Pod 가 생기면 기준선으로 인정되지 않습니다.

다섯 개의 가설을 먼저 적는다

기준선 파일에서 성공률과 p95 를 읽어 steady_state 에 정상 상태를 적고, 다섯 실험(kill-one · kill-ha · cpu-squeeze · mem-squeeze · hardened)의 가설을 /root/chaos-lab/hypothesis.json 에 쓰세요. 실험마다 availability, latency, 왜 그렇게 예상하는지(why), 언제 멈출지(abort_if) 네 가지가 필요합니다. availability_ratio_min 은 0.95 이상이면서 기준선 측정값 이하, p95_ms_max 는 기준선 p95 이상 그 3배 이하로 잡습니다.

예상이 맞을 필요는 없습니다. 틀린 예상을 나중에 refuted 로 적는 것이 이 실습의 정답입니다. 라벨의 뜻은 지시문의 판정 표에 있습니다. 이 파일은 여기서부터 고치지 마세요 — 마지막 채점이 첫 실험 기록보다 먼저 쓰였는지 봅니다.

복제본 하나짜리 서비스를 죽여 본다

복제본이 1인 상태에서 부하를 배경으로 띄우고, 측정 창 안에서 그 하나뿐인 Pod 를 지우세요. 창이 닫히면 python3 /opt/fixtures/chaos_lab.py record kill-one /root/chaos-lab/raw-03.json /root/chaos-lab/03-kill-one.json 으로 남깁니다. 자원 한계와 preStop 은 기준선 그대로 두세요.

부하를 먼저 띄우고 몇 초 뒤에 죽여야 영향이 창 안에 잡힙니다. 죽인 다음에 재기 시작하면 이미 대체 Pod 가 준비된 뒤의 숫자를 재게 됩니다. 창이 닫힐 때 Pod 가 다시 Ready 여야 기록됩니다.

복제본을 셋으로 늘리고 같은 공격을 반복한다

복제본을 3으로 늘려 셋이 모두 Ready 가 된 뒤, 같은 방식으로 부하 창 안에서 Pod 를 정확히 하나만 지우세요. python3 /opt/fixtures/chaos_lab.py record kill-ha /root/chaos-lab/raw-04.json /root/chaos-lab/04-kill-ha.json 으로 남깁니다. 복제본 수 말고는 아무것도 바꾸지 않습니다.

바꾸는 변수는 한 번에 하나여야 결과를 설명할 수 있습니다. 셋이 전부 Ready 인지 확인한 뒤에 재세요. 성공률이 기준선만큼 회복되지 않더라도 그대로 기록하면 됩니다 — 그게 이 실험의 결과입니다.

CPU 를 조인다 — 죽지 않고 느려지는 고장

shop 컨테이너의 cpu 한계만 100m 으로 낮추세요(memory 는 96Mi, 복제본은 3 그대로). 롤아웃이 끝나고 셋이 모두 Ready 가 된 뒤에 20초 부하를 걸고 python3 /opt/fixtures/chaos_lab.py record cpu-squeeze /root/chaos-lab/raw-05.json /root/chaos-lab/05-cpu-squeeze.json 으로 남깁니다.

자원 한계는 Pod 템플릿에 있으니 바꾸면 새 Pod 가 뜹니다. 롤아웃 도중에 재면 배포의 영향과 한계의 영향이 섞입니다. 한계는 요청량보다 작을 수 없다는 점도 기억하세요.

메모리를 말린다 — 이번에는 죽는다

cpu 한계를 500m 으로 되돌리면서 memory 한계를 40Mi 로 낮추세요. 앱은 기동할 때 48MiB 를 한 번에 잡으므로 컨테이너가 OOM 으로 죽습니다. 재시작이 잡히면 20초 부하를 걸고 python3 /opt/fixtures/chaos_lab.py record mem-squeeze /root/chaos-lab/raw-06.json /root/chaos-lab/06-mem-squeeze.json 으로 남깁니다.

이번 롤아웃은 끝나지 않습니다. rollout status 를 기다리지 말고 재시작 횟수나 종료 이유를 보세요. 종료 코드와 이유가 CPU 때와 어떻게 다른지가 이 실험의 핵심입니다.

배운 것을 설계에 반영하고 같은 공격을 다시 받는다

자원 한계를 정상값(cpu 500m · memory 96Mi)으로 되돌리면서, 이번에는 종료 처리를 더하세요. preStop 훅으로 최소 3초를 벌고 terminationGracePeriodSeconds 를 10 이상으로 올립니다. 롤아웃이 끝나면 3단계·4단계와 같은 공격을 다시 하고 python3 /opt/fixtures/chaos_lab.py record hardened /root/chaos-lab/raw-07.json /root/chaos-lab/07-hardened.json 으로 남깁니다.

preStop 은 TERM 신호보다 먼저 실행되고, 훅이 끝나야 신호가 나갑니다. 그 사이에 엔드포인트 제거가 퍼집니다. 유예 시간의 카운트다운은 훅 전에 시작되므로 훅보다 넉넉해야 합니다. 프로브를 지우거나 복제본을 더 늘려 숫자를 좋게 만드는 것은 이 실험의 계약을 피하는 행동입니다.

가설과 측정을 견주어 실험 노트를 닫는다

다섯 기록의 숫자에 지시문의 판정 표대로 이름을 붙여 /root/chaos-lab/conclusion.json 에 쓰세요. 실험마다 observed_availability, observed_latency, 가설과 견준 verdict(confirmed 또는 refuted), 그리고 이 결과로 무엇을 바꿀지(action)가 필요합니다. 마지막 채점은 앞선 기록과 지금 클러스터를 함께 봅니다 — 고친 설계가 살아 있어야 합니다.

반증된 가설은 실패가 아닙니다. 예상과 다르면 refuted 라고 적는 것이 맞는 답입니다. 숫자만 그럴듯하게 적고 이름을 아무렇게나 붙이면 채점기가 같은 규칙으로 다시 계산해 걸러냅니다. action 다섯 개는 서로 달라야 합니다.