온콜 런북
프로덕션 TRUSCA 스택에 대해 가장 빈번한 4개의 PagerDuty 알림에 대한 빠른 참조 플레이북입니다. 각 시나리오는 다음을 나열합니다:
- 증상 — 페이지를 트리거한 것
- 고객 영향 — 사용자가 지금 할 수 있는 / 할 수 없는 것
- 진단 — 실행할 정확한 명령(호스트 + 컨테이너)
- 복구 — 순서대로 수행할 조치
- 에스컬레이션 — 포털 개발팀을 깨워야 하는 시점
모든 명령은 docker-compose V1(하이픈) 과 bash 호스트 셸을 가정합니다.
# EMAIL/PASSWORD 를 설치 시 생성한 super-admin 으로 교체하세요.
EMAIL=admin@example.com
PASSWORD=...
ACCESS_TOKEN=$(curl -fsS -X POST "https://<your-host>/api/auth/login" \
-H "Content-Type: application/json" \
-d "{\"email\":\"$EMAIL\",\"password\":\"$PASSWORD\"}" | jq -r '.access_token')
시나리오 1 — Trivy DB stale 또는 누락
증상
PagerDuty: TRUSCA Trivy DB last refresh > 14 days 또는 TRUSCA Trivy DB missing on worker. 곧 도착하는 /admin/health → Vulnerability data 카드(roadmap)가 이를 구동합니다.
고객 영향
- 신규 스캔 큐잉은 여전히 가능합니다 —
cdxgen+ scancode가 SBOM과 라이선스 finding을 계속 생성합니다. - DB refresh가 성공할 때까지 신규 CVE 탐지가 멈춥니다.
- 기존
vulnerability_findings행은 변경 없음 — 갭은 forward-only.
진단
# 1. DB가 디스크에 있는가?
docker-compose -f docker-compose.yml exec worker \
ls -lh /var/lib/trivy/db/
# 2. DB 메타데이터(Created 타임스탬프)
docker-compose -f docker-compose.yml exec worker \
cat /var/lib/trivy/db/metadata.json
# 3. 최근 download / refresh 로그
docker-compose -f docker-compose.yml logs --tail=500 worker | grep trivy_db
docker-compose -f docker-compose.yml logs --tail=500 beat | grep trivy_db_refresh
# 4. ghcr.io로 outbound HTTPS 도달 가능?
docker-compose -f docker-compose.yml exec worker \
curl -fsS https://ghcr.io/v2/ -o /dev/null -w "%{http_code}\n"
복구(순서대로)
- 일회성 refresh 강제(권장 — 단일 명령, 재시작 없음):
docker-compose -f docker-compose.yml exec worker \celery -A apps.backend.tasks.celery_app call tasks.trivy_db.refreshsleep 30docker-compose -f docker-compose.yml exec worker \cat /var/lib/trivy/db/metadata.json | jq '.Created'
- 비우고 재다운로드(메타데이터 손상 시):
부팅 시docker-compose -f docker-compose.yml exec worker \rm -rf /var/lib/trivy/dbdocker-compose -f docker-compose.yml restart worker
trivy --download-db-only가 실행되어 1~3분 내 디렉터리를 재채움. - 미러 폴백(워커에서
ghcr.io도달 불가 시):TRIVY_DB_REPOSITORY를 사내 미러로 설정 — 취약점 데이터 — Air-gapped 운영 참조.
복구 후 자동 재매칭 beat이 다음 사이클에서 기존 스캔에 대해 누락된 CVE를 가져옵니다 — 운영자 액션 불필요.
에스컬레이션
- 두 번의 refresh 시도가 같은 오류로 실패하거나,
- 최근
trivy registry login후에도 사내 미러가unauthorized를 반환하거나, metadata.json은 존재하지만 여러 생태계의 spot 스캔에서Results가 빈 경우(스키마 불일치 시사).
포털 개발팀 호출 시 첨부: 워커 로그(docker-compose logs --tail=2000 worker), metadata.json 내용, 워커 내부에서 trivy --version 출력.
시나리오 2 — 자동 백업 3일 연속 실패
증상
PagerDuty: TRUSCA auto-backup task failure count = 3.
고객 영향
- 호스트가 크래시하면 포털의 모든 데이터가 위험합니다(복원할 최근 백업 없음). 신선한 백업이 도착할 때까지 다운스트림 작업(컴플라이언스 동결 등)을 계획하세요.
진단
# 1. Celery Beat 스케줄 하트비트
docker-compose logs --tail=500 beat | grep daily-auto-backup
# 2. 워커 로그에서 백업 태스크 실행
docker-compose logs --tail=2000 worker | grep -E 'backup\.(completed|failed)' | tail -20
# 3. 가장 최근 백업 행 + 상태
curl -fsS "https://<your-host>/v1/admin/backup/list" \
-H "Authorization: Bearer $ACCESS_TOKEN" | jq '.items[0:5]'
# 4. 백업 볼륨의 디스크 여유 공간(BACKUPS_ROOT는 백엔드 컨테이너에서
# /opt/trustedoss/backups에 마운트됨)
docker-compose -f docker-compose.yml exec backend df -h /opt/trustedoss/backups
복구
-
수동 트리거(UI:
/admin/backup→ Run manual backup now, 또는):curl -fsS -X POST "https://<your-host>/v1/admin/backup/trigger" \-H "Authorization: Bearer $ACCESS_TOKEN" -
수동도 실패하면 — 호스트 백업 스크립트를 직접 실행:
scripts/backup.sh는 호스트 스크립트입니다.pg_dump를docker-compose ... exec로 호출하고 워크스페이스 마운트를 tar로 묶으므로, 컨테이너 안이 아니라 호스트에서 실행하십시오.BACKUP_DIR이 설정되면 그 경로에, 아니면 레포 루트의backups/<stamp>(/opt/trustedoss/backups에 마운트됨)에 기록합니다.# docker-compose.yml + .env가 있는 호스트의 배포 디렉터리에서 실행합니다.BACKUP_DIR=backups/debug-$(date +%Y%m%d-%H%M%S) bash scripts/backup.sh --no-prune 2>&1.env not found→ 배포 디렉터리에서 실행하거나, 설치가 완료되지 않았습니다.- Server version mismatch → postgres 이미지에
postgresql-client-17미설치(회귀 — 에스컬레이션). - 디스크 가득참 → 시나리오 4 참고.
에스컬레이션
bash scripts/backup.sh가 디스크·권한 외 사유로 실패하거나,- 가장 최근 성공 백업이 7일 이상 지난 경우(자동 정리 윈도 — 복원 옵션이 좁아짐).
시나리오 3 — 스캔이 running 에서 4시간 이상 멈춤
증상
PagerDuty: TRUSCA scan running > 4h for project X.
고객 영향
- 해당 프로젝트: 신규 스캔이 차단됩니다(한 번에 1건 실행 정책).
- 다른 프로젝트: 워커 동시성=1 인 경우(기본값 2)가 아니면 영향 없음.
진단
# 1. 어느 단계에서 멈췄는가?
curl -fsS "https://<your-host>/v1/scans/<scan_id>" \
-H "Authorization: Bearer $ACCESS_TOKEN" | jq '.progress_payload, .latest_log_frame'
# 2. Celery active task 목록
docker-compose exec worker celery -A apps.backend.tasks.celery_app inspect active
# 3. 워커 프로세스 트리(고아 서브프로세스 확인)
docker-compose exec worker ps -ef | grep -E 'cdxgen|ort|trivy'
복구
- 스캔 강제 취소(권장 — 워커 전반 영향 없음):
curl -fsS -X POST "https://<your-host>/v1/admin/scans/<scan_id>/cancel" \-H "Authorization: Bearer $ACCESS_TOKEN"
- 취소로도 태스크가 해제되지 않으면(워커가 진짜로 행 상태):
같은 워커에서 실행 중이던 다른 스캔은 failed 로 기록되며 수동 재실행이 필요합니다.# 최후의 수단 — 이 워커의 실행 중 모든 태스크를 죽입니다.docker-compose restart worker