website: git 드리프트 알람 문서화 및 알람 튜닝 사고 모델 정리
배포 서버의 git 워킹트리 드리프트를 감지하는 알람을 추가하고, 그 과정에서 겪은 오탐 사고를 계기로 알람 튜닝에 필요한 변수 관계를 문서로 정리했습니다. `infra/observability.md` 파일 하나에 36줄이 추가됐습니다.
요약
2026년 7월 12일, infra/observability-drift-docs 브랜치의 PR #108이 dev에 머지됐습니다. 커밋 메시지는 "docs(infra): git 드리프트 알람 문서화 + 알람 튜닝 사고 모델"로, 문서 전용 변경이지만 그 안에 담긴 내용은 단순한 기록 이상입니다. 배포 서버가 몇 주째 옛날 커밋에 고정된 채 배포마다 롤백만 반복하던 실제 장애를 계기로 새 알람을 만들었고, 그 알람을 튜닝하는 과정에서 또 한 번의 오탐을 겪으면서 알람 설계 전반에 대한 사고 모델까지 정리하게 된 케이스입니다.
배경 및 목적
배포 서버의 git 워킹트리는 SSH로 직접 파일을 고치거나, 미머지 브랜치를 서버에서 먼저 검증하다 보면 gitignore 안 된 낯선 파일이 남는 식으로 조용히 오염될 수 있습니다. 이렇게 되면 git pull이 실패하기 시작하고, 그 실패가 눈에 띄지 않은 채 다음 배포부터 계속 깨지는 상태로 이어집니다. 실제로 이 프로젝트에서는 서버가 몇 주 동안 과거 커밋에 고정된 채 배포마다 롤백만 반복하는 사고가 있었다고 문서에 명시돼 있습니다.
기존에도 메모리 사용률, DB 백업 부재를 감지하는 알람은 있었지만 git 드리프트를 감지하는 장치는 없었습니다. 이번 작업은 이 공백을 메우는 동시에, 알람을 처음 튜닝하며 겪은 오탐 사고를 통해 얻은 교훈을 나중에 같은 실수를 반복하지 않도록 문서화하는 게 목적이었습니다.
구현 내용
변경된 파일
infra/observability.md(36줄 추가, 0줄 삭제)
문서 하나만 수정됐지만 내용은 크게 두 부분으로 나뉩니다: 새 알람 정의 및 배경 설명, 그리고 알람 튜닝 사고 모델.
git 드리프트 알람 추가
기존 알람 테이블에 새 행이 하나 추가됐습니다.
| likelion-prod 배포서버 git 드리프트 감지 | custom_likelion | GitDriftFileCount[10m].max() > 0 | 8분 지속 시 (pending-duration) | CRITICAL |
이 알람은 infra/push-git-drift-metric.py라는 새 스크립트가 git status --porcelain 라인 수를 그대로 메트릭 값으로 밀어 넣는 방식으로 동작합니다. cron */5 * * * *로 5분마다 실행됩니다. 여기서 흥미로운 부분은 gitignore 처리를 이용한 자연스러운 필터링입니다. .env.*, infra/nginx.conf, infra/data/, infra/.prev_backend_tag_* 같은 "서버 전용 정상 파일"은 애초에 git status에 잡히지 않으므로, 별도의 화이트리스트 로직 없이도 "정상적으로 서버에만 있는 파일"과 "git이 몰라야 하는데 존재하는 이상 파일"이 자동으로 구분됩니다.
파일 역할 테이블에도 이 스크립트가 추가됐습니다.
| infra/push-git-drift-metric.py | 배포 서버 git 워킹트리 드리프트(git status --porcelain 라인 수) → custom metric. cron */5 * * * *로 실행 |
알람 튜닝 사고 모델
이 문서에서 가장 분량이 큰 부분은 새로 추가된 "알람 튜닝 사고 모델" 섹션입니다. 커스텀 메트릭 알람을 튜닝할 때 얽혀 있는 네 가지 변수를 정의합니다.
- C (cron 주기): 메트릭이 실제로 몇 분마다 찍히는가
- W (쿼리 윈도우): 알람 쿼리
[Xm]이 매 평가 시점에 최근 몇 분을 뭉쳐 보는가 - R (resolution): 알람이 몇 분마다 재평가하는가
- P (pending-duration): breaching이 몇 분 연속돼야 실제 FIRING으로 전환되는가
이 네 변수 사이의 관계를 네 가지로 정리했습니다.
첫째, W는 C 이상이어야 합니다. 메트릭이 C분에 한 번만 찍히는데 W가 그보다 작으면 두 push 사이에 데이터가 없는 구간이 생겨서 breaching 카운트가 끊깁니다.
둘째, "스미어링" 현상입니다. [Xm].max() 같은 쿼리는 최근 X분 안에 나쁜 값이 있었는지만 보기 때문에, 단 한 틱만 나쁜 값이 찍혀도 그 이후 W분 동안 계속 "나쁨"으로 관측됩니다. 즉 실제 지속시간과 무관하게 관측상 breaching 지속시간은 단일 blip 기준으로 W분이 됩니다.
셋째, 파이어에 필요한 최소 연속 tick 수를 공식으로 정리했습니다.
k_min = ceil( (P - W) / C ) + 1
W ≥ P면 단 한 번의 blip만으로 파이어가 발생하고, W < P여야 비로소 2번 이상 연속된 진짜 상태가 필요해집니다. 그런데 관계 ①(W ≥ C)과 동시에 만족하려면 C ≤ W < P가 성립해야 하므로, P가 C보다 확실히 커야만 순간적인 blip을 무시하고 진짜 지속 상태만 잡는 설계가 가능합니다. 반대로 P ≤ C면 W를 아무리 조정해도 구조적으로 단일 blip을 피할 수 없습니다.
넷째, OK 복귀 속도는 P와 무관하게 W만 결정합니다. 문제가 사라지면 마지막 나쁜 push가 윈도우에서 밀려나는 순간, 즉 W분 후에 바로 OK로 돌아갑니다.
기술적 의사결정
왜 백업 알람과 디스크 알람은 custom metric인가
문서에는 기존 알람들의 설계 이유도 함께 재확인돼 있습니다. 백업 알람이 dead man's switch 방식인 이유는, 백업 스크립트 자체는 이미 매일 잘 돌고 있었지만 "잘 되고 있다"는 걸 확인하려면 사람이 매번 SSH로 들어가야 했기 때문입니다. 값 자체(=1)는 의미가 없고, 신호가 26시간 동안 안 들어오는 것 자체가 이상 신호로 취급됩니다. cron이 안 돌았든, 서버가 죽었든, 스크립트가 실패했든 원인을 불문하고 다 잡히는 방식입니다.
디스크 사용률이 custom metric인 이유는 OCI의 Compute Instance Monitoring 플러그인이 CPU/메모리/디스크 I/O는 기본 제공하지만 "디스크가 몇 % 찼는가"는 제공하지 않기 때문입니다. 하이퍼바이저/블록스토리지 레벨에선 파일시스템 내부를 알 수 없고 OS 안에서만 알 수 있는 정보라, 서버 위 스크립트가 직접 df 값을 계산해 채워 넣는 구조입니다.
같은 맥락에서 git 드리프트도 OCI 네이티브 메트릭으로는 알 수 없는 정보이므로 custom metric으로 구현하는 것이 자연스러운 선택이었습니다.
실제 오탐 사례와 P 값 조정
2026년 7월 12일, 배포 스크립트가 정상적으로 생성했다가 지우는 롤백 마커 파일(infra/.prev_backend_tag_stage)이 gitignore 누락으로 드리프트로 잡히는 일이 있었습니다. C=5분, W=10분, P=5분(이후 3분으로 낮췄던) 조합에서 1분짜리 정상 상태가 오탐 FIRING을 일으켰습니다.
근본 원인은 gitignore 누락이라 그 부분을 수정했지만, 동시에 P=3분(≤C=5분) 상태에서는 어떤 W를 골라도 구조적으로 단일 blip을 피할 수 없다는 걸 앞서 정리한 사고 모델로 확인했습니다. 그래서 P=8분(>C=5분)으로 조정해, 앞으로는 순간적인 상태 변화 한 번으로는 알람이 뜨지 않고 최소 2번 연속 cron tick 동안 실제로 더러운 상태가 유지돼야 파이어하도록 바꿨습니다.
배운 점 및 개선점
알람을 하나 추가하는 일이 단순히 쿼리 하나 작성하는 걸로 끝나지 않는다는 걸 다시 확인한 작업이었습니다. cron 주기, 쿼리 윈도우, pending-duration이 서로 독립적인 값이 아니라 구조적으로 얽혀 있어서, 이 관계를 이해하지 못한 채 값을 조정하면 아무리 튜닝해도 오탐을 피할 수 없는 조합에 갇힐 수 있습니다. 이번 오탐 사고가 그 예시였고, 공식(k_min = ceil((P - W) / C) + 1)으로 정리해두니 다음에 비슷한 알람을 설계할 때 감으로 값을 조정하는 대신 원인을 구조적으로 짚을 수 있게 됐습니다.
gitignore 관리도 다시 생각하게 됐는데, 배포 스크립트가 만드는 임시 파일들을 빠짐없이 gitignore에 반영하는 게 이런 종류의 오탐을 예방하는 첫 단계라는 걸 실감했습니다. 앞으로는 새 배포 스크립트를 추가할 때 임시 파일 생성 여부와 gitignore 반영을 체크리스트처럼 확인하는 게 좋을 것 같습니다.
참고 자료
- OCI Compute Instance Monitoring 공식 문서 (디스크 사용률 미제공 확인)
#83이슈 (백업 스크립트 정상 동작 재확인 관련)