Tips & Tricks (업데이트: 2026. 6. 3.)

Claude Code 운영 장애 대응: 탐지, 롤백, RCA, 재발 방지

Claude Code 운영 장애 대응 가이드: 비밀키, 삭제, DB, 비용, 롤백, RCA, 재발 방지까지 정리.

Claude Code 운영 장애 대응: 탐지, 롤백, RCA, 재발 방지

Claude Code는 파일을 읽고, 코드를 고치고, 명령을 실행할 수 있어서 운영 저장소에서도 빠르게 움직입니다. 하지만 빠른 승인 하나가 비밀키 유출, 파일 삭제, main 덮어쓰기, 위험한 DB 마이그레이션, API 호출 폭증으로 이어질 수 있습니다.

이 글은 특정 회사의 실제 장애 보고서가 아닙니다. ClaudeCodeLab에서 진행한 장애 연습, 저장소 리뷰, 콘텐츠 운영 경험을 바탕으로 만든 합성 사례입니다. 시간과 금액은 예시지만, 패턴은 운영 전에 연습할 만큼 현실적입니다.

장애는 사용자, 데이터, 보안, 비용, 가용성에 영향을 주는 사건입니다. 봉쇄는 피해가 더 커지지 않게 멈추는 일입니다. RCA는 근본 원인 분석입니다. 롤백은 마지막으로 안전했던 버전으로 되돌리는 일입니다.

정확한 설정 문법은 공식 Claude Code settingshooks guide를 확인하세요. 여기서는 탐지, 봉쇄, 진단, 롤백, 커뮤니케이션, 사후 분석, 재발 방지를 하나의 흐름으로 정리합니다.

대응 흐름

단계목적Claude Code에 시킬 일
탐지무엇이 바뀌고 누가 영향을 받는지 확인알림, 로그, diff, 배포, 최근 명령 요약
봉쇄피해 확산 중지키 폐기, 작업 중지, feature flag OFF, endpoint 차단 제안
진단직접 원인 좁히기마지막 정상 배포와 실패 변경 비교
롤백안전한 상태로 복귀대상 버전, 데이터 위험, 검증 명령 정리
커뮤니케이션이해관계자 불안 줄이기상태, 영향, 다음 업데이트 시각, 담당자 작성
사후 분석사고를 학습으로 전환RCA, 타임라인, 탐지 누락, 액션 아이템 작성
예방같은 사고를 어렵게 만들기permissions, hooks, CI, 알림, 리뷰 게이트 추가

비밀키, 과금, 개인정보, DB 쓰기와 관련된 사고는 먼저 봉쇄하고 나중에 조사합니다.

일곱 가지 사고 패턴

패턴발생 상황첫 조치흔한 실패
비밀키 유출.env, 로그, 스크린샷에 API key 노출키 폐기, 교체, 로그 확인git만 정리하고 CI 로그를 놓침
위험한 삭제rm -rf가 필요한 파일 삭제작업 중지, 백업 확인, 미추적 파일 목록화git checkout .은 미추적 파일을 복구하지 못함
force pushmain이 팀원의 커밋을 덮어씀push 중지, reflog 확인, 복구 브랜치 생성--force-with-lease--force 혼동
DB 마이그레이션drop, 대량 update, lock으로 운영 장애쓰기 중지, 상태 보존, 복구 계획검증 안 된 SQL을 운영에서 실행
API 무한 재시도실패할수록 호출과 비용 증가프로세스 종료, 큐 중지, 한도 확인”재시도”가 무한 루프가 됨
의존성 배포 실패로컬은 통과, 운영은 503이전 배포 재활성화, lockfile 확인npm update가 major 버전을 올림
인증 누락admin endpoint가 공개됨endpoint 차단, 접근 로그 확인”admin”이라고만 쓰고 인증 요구를 안 씀

세 가지 실전 사례

API key 유출은 GitHub secret scanning, 클라우드 알림, 과금 화면에서 발견될 수 있습니다. 첫 조치는 원인 분석이 아니라 키 폐기입니다. 이후 공개 저장소, PR, CI 로그, 채팅, 모니터링을 확인합니다.

git status --short
git diff --cached --name-only
git log --all -- .env .env.local
git grep -n "sk-" -- ':!node_modules' ':!dist'

DB 마이그레이션 실패는 쓰기를 멈춘 뒤 조사합니다. 코드는 빠르게 롤백할 수 있지만 삭제된 데이터는 백업, WAL, 감사 로그, 외부 재동기화가 필요합니다.

psql "$DATABASE_URL" -c "select now();"
psql "$DATABASE_URL" -c "\d users"
pg_dump "$DATABASE_URL" --schema-only > schema_before_repair.sql

API 재시도에는 명확한 한도가 있어야 합니다. 아래 파일을 incident-budget-runner.mjs로 저장해 배치 작업을 감싸세요.

#!/usr/bin/env node
import { spawn } from "node:child_process";

const command = process.argv.slice(2);
const maxAttempts = Number(process.env.MAX_ATTEMPTS || 3);
const maxCostCents = Number(process.env.MAX_COST_CENTS || 200);
const costPerAttempt = Number(process.env.COST_PER_ATTEMPT_CENTS || 0);

if (command.length === 0) {
  console.error("사용법: node incident-budget-runner.mjs <명령> [...인자]");
  process.exit(2);
}

let estimatedCost = 0;

for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
  const child = spawn(command[0], command.slice(1), {
    stdio: "inherit",
    shell: process.platform === "win32"
  });
  const exitCode = await new Promise((resolve) => {
    child.on("exit", (code) => resolve(code ?? 1));
  });
  estimatedCost += costPerAttempt;
  if (exitCode === 0) process.exit(0);
  if (estimatedCost >= maxCostCents) {
    console.error(`중지: 예상 비용 ${estimatedCost} 센트 도달`);
    process.exit(1);
  }
  const delayMs = Math.min(1000 * 2 ** (attempt - 1), 10_000);
  await new Promise((resolve) => setTimeout(resolve, delayMs));
}

console.error(`${maxAttempts}회 시도 후 실패`);
process.exit(1);

Claude Code 방어 설정

{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "permissions": {
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(./secrets/**)",
      "Bash(git push --force *main*)",
      "Bash(git push -f *main*)",
      "Bash(rm -rf /*)",
      "Bash(rm -rf ~*)"
    ],
    "ask": [
      "Bash(git push*)",
      "Bash(rm*)",
      "Bash(npm install*)",
      "Bash(*migrate*)",
      "Bash(*deploy*)"
    ]
  },
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-danger.sh"
          }
        ]
      }
    ]
  }
}
#!/usr/bin/env bash
set -euo pipefail

payload="$(cat)"
command="$(node -e 'const fs = require("fs"); const raw = fs.readFileSync(0, "utf8") || "{}"; const json = JSON.parse(raw); console.log(json.tool_input?.command || "");' <<< "$payload")"
blocked='(rm[[:space:]]+-rf[[:space:]]+(/|~)|git[[:space:]]+push[[:space:]].*(-f|--force)([[:space:]]|$)|DROP[[:space:]]+TABLE|TRUNCATE[[:space:]])'

if [[ "$command" =~ $blocked ]]; then
  echo "위험한 명령을 차단했습니다: $command" >&2
  exit 2
fi

exit 0

공지와 사후 분석 템플릿

## 장애 업데이트
- 상태: 조사 중 / 봉쇄 완료 / 복구 검증 중
- 영향: 기능, 사용자, 시작 시각
- 현재 조치: 작업 중지, 배포 롤백, 로그 확인
- 다음 업데이트: YYYY-MM-DD HH:mm
- 담당자:
# 사후 분석: [제목]

## 요약
- 시작:
- 탐지:
- 복구:
- 영향:
- 심각도: P0/P1/P2/P3

## 타임라인
| 시각 | 사건 |
| --- | --- |
| HH:mm | |

## 원인
- 직접 원인:
- 근본 원인:
- 탐지가 늦은 이유:

## 재발 방지
| 조치 | 담당자 | 기한 |
| --- | --- | --- |
| | | |

외부 참고 자료로는 Google SRE의 Postmortem Culture가 좋습니다.

관련 글과 CTA

Claude Code 보안 모범 사례, 권한 설정 가이드, API 비용 가이드, 검증 기록 워크플로도 함께 읽어 보세요.

개인 사용자는 무료 치트시트로 위험 명령과 확인 습관부터 고정하면 됩니다. 재사용 템플릿은 ClaudeCodeLab 제품에서, 팀 도입은 Claude Code 교육과 상담에서 CLAUDE.md, 권한, hooks, 리뷰, 장애 연습을 함께 정리할 수 있습니다.

ClaudeCodeLab 연습에서 가장 효과가 컸던 변화는 진단보다 봉쇄를 먼저 쓰는 것이었습니다. 게시 전 JSON, Bash, Node 구문을 확인한 것도 단순 오류를 줄였습니다. 20분짜리 리허설만 해도 빠진 알림, 검증되지 않은 백업, 너무 넓은 Claude Code 권한이 눈에 들어옵니다.

#claude-code #incident #production #sre #security #postmortem
무료

무료 PDF: Claude Code 치트시트

이메일을 입력하면 명령, 리뷰 습관, 안전한 워크플로를 정리한 PDF를 받을 수 있습니다.

개인정보를 안전하게 관리하며 스팸을 보내지 않습니다.

Masa

작성자 소개

Masa

Claude Code 실무 워크플로와 팀 도입을 검증하는 엔지니어입니다.