본문으로 건너뛰기

온콜 런북

프로덕션 TRUSCA 스택에서 가장 자주 나오는 PagerDuty·알림에 대한 빠른 참조 플레이북입니다. 각 시나리오는 다음을 나열합니다:

  • 증상 — 페이지를 트리거한 것
  • 고객 영향 — 사용자가 지금 할 수 있는 / 할 수 없는 것
  • 진단 — 실행할 정확한 명령(호스트 + 컨테이너)
  • 복구 — 순서대로 수행할 조치
  • 에스컬레이션 — 포털 개발팀을 깨워야 하는 시점

아래 나오는 PagerDuty 알림 이름은 예시입니다. 이 저장소가 스스로 연결해 주는 것이 아닙니다. 근거 데이터(/metrics, Slack/Teams 웹훅)는 발행하지만 Prometheus 서버·Alertmanager·페이징 연동은 어디에도 포함돼 있지 않습니다. 지금 돌고 있는 Prometheus에서 같은 이름의 알림을 만들어 내는 예시 규칙 파일과, 아래 시나리오 중 아직 근거 지표가 없는 것이 무엇인지는 알림을 봅니다.

모든 명령은 docker-compose V1(하이픈)과 bash 호스트 셸을 가정합니다.

Super-admin 토큰 발급(대부분 curl 예시에서 사용)
# 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: TrustedOSSVulnDbStale(예시 규칙, 알림 참고) 또는 TRUSCA Trivy DB missing on worker. /admin/health → Vulnerability data의 Trivy DB 패널이 같은 신선도 판정을 보여줍니다.

고객 영향​

  • 신규 스캔 큐잉은 여전히 가능합니다 — cdxgen + scancode가 SBOM과 라이선스 finding을 계속 생성합니다.
  • DB refresh가 성공할 때까지 신규 CVE 탐지가 멈춥니다.
  • 기존 vulnerability_findings 행은 변경 없음 — 갭은 forward-only.

진단​

# 0. METRICS_ENABLED라면 이게 실제로 알림을 울린 값입니다. worker를 보러 가기 전에
# 먼저 확인합니다.
curl -fsS "https://<your-host>/metrics" \
| grep -E 'trusca_vuln_db_(last_update_timestamp_seconds|refresh_interval_hours)'
# 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"

복구(순서대로)​

  1. 일회성 refresh 강제(권장 — 단일 명령, 재시작 없음):
    docker-compose -f docker-compose.yml exec worker \
    celery -A apps.backend.tasks.celery_app call tasks.trivy_db.refresh
    sleep 30
    docker-compose -f docker-compose.yml exec worker \
    cat /var/lib/trivy/db/metadata.json | jq '.Created'
  2. 비우고 재다운로드(메타데이터 손상 시):
    docker-compose -f docker-compose.yml exec worker \
    rm -rf /var/lib/trivy/db
    docker-compose -f docker-compose.yml restart worker
    부팅 시 trivy --download-db-only가 실행되어 1~3분 내 디렉터리를 재채움.
  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: TrustedOSSAutoBackupNotSucceeding(예시 규칙, 알림 참고).

고객 영향​

  • 호스트가 크래시하면 포털의 모든 데이터가 위험합니다(복원할 최근 백업 없음). 신선한 백업이 도착할 때까지 다운스트림 작업(컴플라이언스 동결 등)을 계획하세요.

진단​

# 0. METRICS_ENABLED라면 이게 실제로 알림을 울린 값입니다.
curl -fsS "https://<your-host>/metrics" \
| grep -A2 '^trusca_task_runs_24h{outcome="success",task="trustedoss.backup.run"'
# 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

복구​

  1. 수동 트리거(UI: /admin/backup → Run manual backup now, 또는):

    curl -fsS -X POST "https://<your-host>/v1/admin/backup/trigger" \
    -H "Authorization: Bearer $ACCESS_TOKEN"
  2. 수동도 실패하면 — 호스트 백업 스크립트를 직접 실행:

    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. 알림에는 아직 이걸 만들어 내는 규칙이 없습니다. /metrics는 상태별 스캔 개수만 발행하고 개별 스캔이 얼마나 오래 실행 중인지는 발행하지 않아서, 이 페이지는 지금은 /metrics가 아니라 API나 DB에 직접 질의해서 확인해야 합니다.

고객 영향​

  • 해당 프로젝트: 신규 스캔이 차단됩니다(한 번에 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'

복구​

  1. 스캔 강제 취소(권장 — 워커 전반 영향 없음):
    curl -fsS -X POST "https://<your-host>/v1/admin/scans/<scan_id>/cancel" \
    -H "Authorization: Bearer $ACCESS_TOKEN"
  2. 취소로도 태스크가 해제되지 않으면(워커가 진짜로 행 상태):
    # 최후의 수단 — 이 워커의 실행 중 모든 태스크를 죽입니다.
    docker-compose restart worker
    같은 워커에서 실행 중이던 다른 스캔은 failed로 기록되며 수동 재실행이 필요합니다.

에스컬레이션​

  • 동일 프로젝트가 같은 단계에서 연속 2회 멈출 때(콘텐츠 측 문제 — 거대한 git 이력, 잘못된 lockfile, trivy sbom 타임아웃 등 시사). <scan_id>와 해당 태스크로 필터링한 마지막 200 라인 worker 로그를 첨부해 포털 개발팀에 호출.

시나리오 4 — 호스트 디스크 95% 이상​

증상​

PagerDuty: TrustedOSSWorkspaceDiskCritical(예시 규칙, 알림 참고. workspace 마운트만 다룹니다. 호스트 전체 디스크 알림은 노드 단위 exporter가 필요합니다 - /metrics는 그건 발행하지 않습니다).

고객 영향​

  • 실행 중 스캔은 계속 진행됩니다. 신규 스캔은 DISK_HARD_LIMIT_PCT 임계(기본 95%)에서 차단됩니다 — /admin/scans에 무한 큐 상태로 표시됩니다.

진단​

# 0. METRICS_ENABLED라면 이게 알림을 울린 값 중 workspace 마운트 쪽입니다.
curl -fsS "https://<your-host>/metrics" | grep trusca_workspace_disk_used_ratio
# 1. 호스트 전체
df -h /opt/trustedoss
docker system df
# 2. 포털을 통한 카드별 분해
curl -fsS "https://<your-host>/v1/admin/disk" \
-H "Authorization: Bearer $ACCESS_TOKEN" | jq
# 3. Workspace 분해(가장 흔한 원인)
docker-compose exec worker du -sh /workspace/* | sort -h | tail -10
# 4. Postgres 데이터베이스 크기
docker-compose exec postgres psql -U trustedoss -d trustedoss \
-c "SELECT pg_size_pretty(pg_database_size('trustedoss'));"

복구​

  1. Workspace 정리(거의 항상 정답):
    docker-compose exec worker find /workspace -mindepth 1 -mtime +30 -delete
  2. Postgres bloat(pg_database_size > 2 GB 이고 최근 급증한 경우): 무거운 테이블을 VACUUM.
    docker-compose exec postgres psql -U trustedoss -d trustedoss \
    -c "VACUUM FULL audit_logs, vulnerability_findings;"
  3. Trivy DB 볼륨(/admin/disk가 trivy_db를 원인으로 표시): Trivy DB는 약 500 MB이며 더 이상 자라선 안 됩니다. 만약 커졌다면 캐시를 비우고 재다운로드 (docker-compose -f docker-compose.yml exec worker rm -rf /var/lib/trivy/db && docker-compose restart worker).
  4. 일시적인 임계 상향(임시 방편일 뿐, 근본 해결책이 아닙니다):
    # .env 편집: DISK_HARD_LIMIT_PCT=98
    docker-compose up -d backend worker

에스컬레이션​

  • workspace 정리 후에도 디스크가 90% 초과로 남아 있거나,
  • audit_logs가 24시간마다 두 배로 늘어나는 Postgres 증가세(근본 원인 필요 — 폭주하는 통합이 이벤트를 쏟아내는 가능성).

시나리오 5 — 큐 적체 알림 발생​

증상​

trustedoss.scan 또는 trustedoss.default에 대해 "Queue backlog alert" 제목의 Slack/Teams 메시지(기존 알림 채널이며 새로 붙인 연동이 아닙니다). QUEUE_BACKLOG_ALERT_ENABLED와 QUEUE_BACKLOG_METRICS_ENABLED가 둘 다 켜져 있어야 발생합니다. 환경변수 - 큐 적체 알림과 Docker Compose - 스캔 용량을 참고하세요.

고객 영향​

  • trustedoss.scan: 새 스캔이 기존 스캔 뒤로 밀려 시작까지 더 오래 걸립니다. 아무것도 실패하지는 않습니다 - 오류가 아니라 용량 신호입니다.
  • trustedoss.default: 알림, 백업, 감사 반출, 티켓 웹훅이 지연됩니다. 오래 지속된다면 단순 과부하보다 워커가 멈춘 상황을 먼저 의심하세요(진단 참고).

진단​

# 1. 현재 적체량과 가장 오래 기다린 스캔의 대기 시간(METRICS_ENABLED도 필요)
curl -fsS "https://<your-host>/metrics" | grep -E 'trusca_broker_queue_backlog|trusca_scan_queue_wait_seconds'
# 2. worker-scan 레플리카가 실제로 떠서 소비하고 있는가?
docker-compose -f docker-compose.yml ps worker-scan
docker-compose -f docker-compose.yml exec worker-scan celery -A apps.backend.tasks.celery_app inspect active
# 3. 최근 스캔 처리량 - 스캔이 끝나고는 있는가, 아니면 쌓이기만 하는가?
curl -fsS "https://<your-host>/v1/admin/scans?status=queued" \
-H "Authorization: Bearer $ACCESS_TOKEN" | jq '.total'

복구​

  1. 도착률이 용량을 넘어선 경우(흔한 경우): 알림이 지목한 워커 서비스를 확장하세요. 스캔 처리량은 worker-scan, 나머지는 worker-default입니다 - 엉뚱한 쪽을 확장하면 아무것도 나아지지 않습니다(위에 링크한 용량 가이드 참고):
    docker-compose -f docker-compose.yml up -d --scale worker-scan=4
  2. 실제 부하가 아니라 워커가 멈춘 경우: celery inspect active에 정상 스캔보다 훨씬 오래 도는 태스크가 보이면(SCAN_HARD_TIME_LIMIT_SECONDS와 비교) 그 스캔부터 시나리오 3의 복구 절차를 따르세요. 멈춘 태스크를 정리하면 필요하지도 않은 용량을 영구히 늘리지 않고도 슬롯이 풀립니다.
  3. 정상화 확인: 여전히 적체 상태라면 알림은 쿨다운 간격(QUEUE_BACKLOG_ALERT_COOLDOWN_SECONDS, 기본 1시간)마다 다시 발생하고, 이후 어느 beat 틱(5분 간격)에서 적체량이 임계값 이하로 내려가면 멈춥니다.

에스컬레이션​

  • worker-scan을 확장해도 스캔 한 건 소요 시간만큼의 주기 안에 적체가 줄지 않을 때(디스크·Postgres·브로커 자체가 병목일 가능성), 또는
  • 같은 큐에 대해 쿨다운을 넘겨서도 며칠에 걸쳐 알림이 계속 재발할 때.

시나리오 6 — 워커가 부팅하자마자 task_registry.empty로 재시작합니다​

증상​

워커 컨테이너가 뜨지 못하고 재시작을 반복합니다. 로그 끝에 task_registry.empty가 있거나, 프로세스 stderr에 다음 줄이 나옵니다.

FATAL task_registry.empty: this worker registered none of the portal's tasks

Compose에서는 재시작 반복으로, Kubernetes에서는 CrashLoopBackOff로 나타납니다. 이건 /metrics가 아니라 오케스트레이터 자체의 재시작 횟수 신호(Kubernetes 자체 값, cAdvisor, kube-state-metrics)로 알림을 걸어야 합니다. 부팅 중 크래시 루프에 빠진 워커는 /metrics가 사는 코드에 도달할 만큼 오래 살지 못해 스크레이핑조차 되지 않습니다. 알림을 봅니다.

컨테이너는 종료 코드 78로 끝납니다. 로그에 아무것도 없더라도 그 숫자만으로 진단이 됩니다. 포털의 태스크가 하나도 없어서 워커가 멈춘 것입니다. 다른 이유로 죽을 때는 거의 다 1이 나오므로 78은 이 경우만 씁니다. 거부 절차의 모든 단계는 출력이 실패해도 끝까지 진행되도록 되어 있습니다.

고객 영향​

그 워커가 맡을 스캔이 돌지 않습니다. 다만 큐에 남아 있고 사라지지는 않습니다. 워커가 멈추는 이유가 그것입니다. 태스크가 없는 워커가 계속 돌면 그 메시지들을 가져가서 실행하지 못하고 버리고, 나중에 정상 워커를 붙여도 할 일이 남아 있지 않습니다.

같은 종류의 다른 워커가 정상이면 그쪽이 일을 가져가므로 고객 영향은 없고 재시작하는 컨테이너만 남습니다.

진단​

워커의 태스크 목록은 애플리케이션 안의 include 목록으로 만들어집니다. 그래서 이것은 설정 문제가 아니라 배포나 패키징 문제입니다. 목록이 비었거나, 목록의 어떤 모듈도 import되지 않았다는 뜻입니다.

# 1. 내려가면서 워커가 남긴 말
docker-compose -f docker-compose.yml logs --tail=50 worker-scan | grep -i task_registry
# 2. 그 이미지 안에서 모듈이 import되는지
docker-compose -f docker-compose.yml run --rm --entrypoint python worker-scan \
-c "from tasks.celery_app import celery_app; celery_app.loader.import_default_modules(); \
print(len([t for t in celery_app.tasks if t.startswith('trustedoss.')]))"

두 번째 명령이 가드가 보는 개수를 그대로 찍습니다. 정상 이미지는 20~30대의 수를 찍습니다. 0이거나 트레이스백이면 그것이 원인입니다.

복구​

  1. 이미지가 어긋났거나 일부만 담긴 경우입니다. 태그 이미지를 다시 받아 서비스를 재생성합니다. 불완전한 트리에서 빌드된 이미지가 흔한 원인입니다.
  2. import에 실패하는 모듈이 있는 경우입니다. 위 두 번째 명령이 트레이스백을 보여 줍니다. 설정으로 우회할 것이 아니라 릴리스의 결함이므로 이전 태그로 되돌립니다.

에스컬레이션​

정식 릴리스 이미지에서 두 번째 명령이 트레이스백을 보이면 즉시 올립니다. 그 태그를 쓰는 모든 배포의 해당 워커가 전부 같은 상태입니다.

시나리오 7 - Redis readiness 필드가 degraded를 보고합니다​

증상​

GET /health/ready는 계속 200을 반환하지만, 응답 본문의 redis 필드가 "ok"가 아니라 "degraded"로 나옵니다. 이 자체는 PagerDuty를 울리는 알림이 아닙니다. 오늘 기준으로 이 필드만 따로 알림을 걸어 두지는 않았습니다 - 이 필드는 /metrics가 아니라 /health/ready에 있는 값이라 알림의 예시 규칙 파일에도 들어 있지 않습니다. 다른 문제를 진단하다가(시나리오 5 큐 적체 조사에서 원인이 Redis로 밝혀지는 경우, 요청 빈도 제한이 느슨해졌다는 문의 등) 보게 되거나, 운영자가 이 필드에 직접 모니터를 걸어 두었다면 그때 알림이 울립니다.

고객 영향​

요청 경로의 제어 중 Redis 장애로 닫히는(fail closed) 것은 하나도 없으므로, 동작이 멈추는 기능은 없습니다. 다만 다음이 조용히 느슨해집니다.

  • 요청 빈도 제한(core/ratelimit.py)과 로그인 시도 제한(core/login_throttle.py) 모두 열어 두도록(fail open) 설계돼 있어, Redis에 닿지 않는 동안은 모든 요청이 제한 없이 통과합니다.
  • WebSocket 연결 레지스트리(core/ws_registry.py)도 열어 두도록 설계돼 있습니다: 새 연결은 거부되지 않고 그대로 받아들여지며, Redis에 닿지 않는 동안은 사용자당/전체 연결 수 상한이 적용되지 않습니다. 스캔 실시간 진행률 스트리밍 자체는 이 상황에서도 계속 동작합니다(스캔 상태는 Postgres에 있습니다).
  • Redis를 쓰는 다른 구성 요소(Celery의 브로커/결과 저장소)는 이것과는 별개의 장애이고 증상도 다릅니다. 그쪽은 이 필드보다는 시나리오 5의 큐 적체 알림으로 먼저 드러날 가능성이 큽니다.

redis 필드는 그 순간의 핑 결과라, 장애 사이에 확인하면 "ok"로 보일 수 있습니다. 값이 있을 때는 응답에 redis_fail_open 객체도 같이 실립니다 ({"ratelimit": {"count": N, "last_degraded_at": "<ISO 8601>", "worker_pid": P}, "login_throttle": {...}, "ws_registry": {...}}). 요청 경로에서 실제로 fail-open으로 넘어간 적 있는 제어마다 한 항목씩 있고, 이번 호출 자체의 핑과는 별개로 쌓입니다. 이 필드 자체가 없다면 프로세스가 시작된 뒤로 세 제어 중 어느 것도 아직 한 번도 저하된 적이 없다는 뜻입니다. redis: "ok"로 보이는 시점보다 last_degraded_at이 더 과거라면, 장애가 이미 끝난 게 아니라 간헐적으로 반복되고 있다는 신호입니다(불안정한 네트워크 경로, 일부 명령만 거부하는 REDIS_URL 비밀번호 설정 오류 등).

이 상태는 프로세스마다 따로 있습니다. UVICORN_WORKERS가 2 이상이면 워커마다 자기 몫의 상태를 따로 갖고 있고, HTTP 응답 하나는 그 요청을 받은 워커의 상태만 보여줍니다. worker_pid가 그 워커를 가리키므로, 이 엔드포인트를 여러 번 조회했을 때 필드가 나타났다 사라졌다 하면서 worker_pid 값이 매번 다르다면, 장애가 반복해서 시작되고 끝난 것이 아니라 워커 여럿이 각자 따로 그 장애를 겪었다는 뜻입니다. 워커 사이의 집계는 이 필드가 대신해 주지 않으므로, 전체 합계가 필요하면 worker_pid별로 count를 직접 더해야 합니다.

진단​

# 1. 필드를 직접 확인합니다(이 엔드포인트는 인증이 필요 없습니다).
curl -fsS https://<your-host>/health/ready | jq

# 2. 백엔드 컨테이너에서 Redis에 실제로 닿는지 확인합니다.
docker-compose -f docker-compose.yml exec backend python -c \
"from redis import Redis; from core.config import redis_url; print(Redis.from_url(redis_url(), socket_timeout=1).ping())"

# 3. Redis 컨테이너 자체가 떠 있는지 확인합니다.
docker-compose -f docker-compose.yml ps redis
docker-compose -f docker-compose.yml logs --tail=100 redis

복구​

  1. Redis 컨테이너가 죽었거나 재시작 중인 경우: 다시 올리고 (docker-compose -f docker-compose.yml up -d redis) 위 2번 명령이 True를 반환하는지 확인합니다. /health/ready의 redis 필드는 다음 요청에서 바로 "ok"로 바뀝니다. 백엔드 쪽에서 따로 지울 캐시나 재시작할 서비스는 없습니다. 이 필드는 요청마다 실시간으로 읽습니다.
  2. Redis는 떠 있지만 backend에서 닿지 않는 경우(네트워크 정책, DNS, 잘못된 REDIS_URL): 네트워크 경로나 URL을 고치고 backend 설정을 재배포합니다. 요청 빈도 제한과 로그인 시도 제한도 같은 REDIS_URL을 쓰므로, 이걸 고치면 셋 다 한 번에 복구됩니다.
  3. Redis도 떠 있고 닿기도 하는데 여전히 degraded인 경우: 이 점검은 연결/응답 제한 시간을 1초로 짧게 잡습니다(core/readiness.py). Redis가 부하로 PING 응답이 1초를 넘게 걸리면 이때도 degraded로 읽힙니다. 네트워크 장애로 단정하기 전에 Redis 자체의 지연이나 CPU 사용률부터 확인하십시오.

에스컬레이션​

위 2~3단계에서 대응되는 Redis 장애를 찾지 못했는데도 degraded가 몇 시간 넘게 이어질 때만 올립니다. 그럴 때는 인프라 장애가 아니라 점검 로직 자체의 결함입니다.

표준 에스컬레이션 양식​

포털 개발팀에 호출 시 다음을 첨부:

  • 시나리오 번호(1-5)와 PagerDuty 알림 URL.
  • 포털 버전: docker-compose -f docker-compose.yml exec backend python -c "from main import app; print(app.version)"
  • 관련 컨테이너의 마지막 2000 라인: docker-compose logs --tail=2000 <svc>
  • Trivy DB 이슈: 워커의 /var/lib/trivy/db/metadata.json 내용 + docker-compose logs --tail=500 worker | grep trivy_db.
  • 스캔 이슈: <scan_id>와 /v1/scans/<scan_id> 전체 JSON.

함께 보기​