# Staging 502 원인 분석 및 재발방지 조치 ## 개요 - 대상: `https://sso.hmac.kr` - 관련 Actions run: `https://gitea.hmac.kr/baron/baron-sso/actions/runs/962` - 관련 이슈: `https://gitea.hmac.kr/baron/baron-sso/issues/1025` - 확인일: 2026-06-08 Gitea Actions run 962는 성공으로 종료됐지만, `https://sso.hmac.kr`는 `502 Bad Gateway`를 반환했습니다. 장애는 애플리케이션 코드 레벨의 단일 오류가 아니라 스테이징 Docker Compose의 restart policy 누락으로 인해 호스트 또는 Docker 데몬 재시작 후 장기 실행 컨테이너가 자동 복구되지 않은 문제였습니다. ## 근본 원인 `docker/staging_pull_compose.template.yaml`에서 일부 장기 실행 서비스에 `restart: unless-stopped` 또는 `restart: always`가 없었습니다. 호스트 상태 확인 결과, 재시작 정책이 있던 `baron_gateway`, Postgres, Redis, ClickHouse, Oathkeeper는 자동 복구됐지만, 정책이 없던 다음 컨테이너는 종료 상태로 남았습니다. - `baron_backend` - `baron_userfront` - `baron_adminfront` - `baron_devfront` - `baron_orgfront` - `ory_kratos` - `ory_hydra` - `ory_keto` - `ory_postgres` - `ory_clickhouse` 결과적으로 외부 reverse proxy와 `baron_gateway`는 살아 있었지만, gateway의 upstream인 UserFront/Backend/AdminFront/DevFront/OrgFront가 없어 외부 도메인이 502를 반환했습니다. `/auth`, `/oidc` 계열 요청은 Oathkeeper가 살아 있어 JSON 404까지 도달했습니다. ## 조치 - `docker/staging_pull_compose.template.yaml`의 장기 실행 서비스에 `restart: unless-stopped`를 추가했습니다. - 마이그레이션/유틸 컨테이너에는 restart policy를 추가하지 않았습니다. - `kratos-migrate` - `hydra-migrate` - `keto-migrate` - `ory_stack_check` - `init-rp` - `oathkeeper_logs_init` - `infra_check` - `.gitea/workflows/staging_code_pull.yml`의 배포 후 검증 범위를 확장했습니다. - `baron_backend` health 확인 - `baron_userfront` 확인 - `baron_gateway` 확인 - 이 검증은 배포 직후 smoke test이며, 배포 이후 장애를 감지하는 운영 알람 대책은 아닙니다. ## 재발방지 테스트 추가된 정책 테스트: ```sh sh test/staging_pull_restart_policy_test.sh ``` 기존 배포 정책 테스트 강화: ```sh sh test/staging_frontend_deploy_policy_test.sh ``` 두 테스트는 다음을 보장합니다. - 스테이징 장기 실행 서비스에는 restart policy가 있어야 합니다. - 마이그레이션/유틸 컨테이너는 restart 대상에 포함하지 않습니다. - 배포 성공 판정은 내부 프론트엔드뿐 아니라 backend, userfront, gateway까지 확인해야 합니다. ## 남은 과제 배포 이후 발생하는 장애를 감지하고 알림을 보내려면 별도 상시 모니터링 구성이 필요합니다. 배포 워크플로 내부 health check는 post-deploy smoke test일 뿐이므로, 머신 재시작 이후 장애 감지나 알림의 대체 수단으로 사용하지 않습니다. ## 검증 결과 복구 후 다음 외부 URL이 정상 응답을 반환했습니다. - `https://sso.hmac.kr/` -> 200 - `https://sso.hmac.kr/ko/signin` -> 200 - `https://sadmin.hmac.kr/` -> 200 - `https://sdev.hmac.kr/` -> 200 - `https://sorg.hmac.kr/` -> 200