website: 롤백 마커 정리를 스모크 테스트 통과 후로 이동
CD 파이프라인에서 헬스체크만 통과하면 롤백용 마커 파일을 지워버리던 문제를 고쳐, 그 뒤에 도는 스모크 테스트가 실패해도 롤백이 정상 작동하도록 수정한 PR입니다. 실제 prod 장애를 겪은 뒤 원인을 찾아 수정했고 바로 병합됐습니다.
요약
이 PR은 .github/workflows/cd.yml에서 롤백용 .prev_backend_tag_* 마커 파일을 지우는 시점을 "헬스체크 통과 직후"에서 "스모크 테스트 통과 후"로 옮긴 작업입니다. 변경량은 크지 않지만(15줄 추가, 2줄 삭제) 배포 안전장치의 동작 여부를 좌우하는 핵심 수정이었고, 실제 prod 사고를 겪고 나서 바로 작성되어 생성 후 2분 만에 병합됐습니다.
배경 및 목적
PR #161로 dev→main 승격을 거쳐 prod에 배포하던 중, members 테이블에 student_id 컬럼을 추가하는 작업이 SQLite의 ALTER 제약(#133에서 이미 지적된 원인)으로 실패해 /api/members가 500 에러를 냈습니다. 마침 얼마 전(#160) 새로 추가한 스모크 테스트가 이 문제를 정확히 잡아 job을 실패시켰는데, 정작 롤백 스텝은 "백업된 이전 태그 정보가 없어 롤백을 건너뜁니다"라는 메시지만 남기고 아무 것도 하지 않았습니다. 그 결과 깨진 새 코드가 그대로 서비스되고 있었고, 이는 SSH로 직접 들어가 확인해서 알게 됐습니다.
원인을 추적해보니 "OCI 배포 및 헬스체크" 스텝이 헬스체크 통과 직후 .prev_backend_tag_* 마커 파일을 삭제하고 있었습니다. 문제는 스모크 테스트가 그 다음 스텝이라는 것 — 헬스체크만으로 "배포 확정"이라 판단해 마커를 지워버리니, 정작 스모크 테스트가 실패했을 때는 롤백 스텝이 참조할 이전 태그 정보가 이미 사라진 뒤였습니다.
구현 내용
수정 방향은 단순합니다. 마커 삭제 로직을 헬스체크 스텝에서 떼어내고, 스모크 테스트 뒤에 새로운 스텝("배포 확정")을 만들어 그곳으로 옮겼습니다.
- rm -f .prev_backend_tag_${{ steps.config.outputs.env }}
-
- name: 스모크 테스트
...
+ - name: 배포 확정 (롤백 마커 정리)
+ uses: appleboy/ssh-action@v1
+ with:
+ host: ${{ secrets.OCI_HOST }}
+ username: ${{ secrets.OCI_USER }}
+ key: ${{ secrets.OCI_SSH_KEY }}
+ script: |
+ cd ${{ secrets.OCI_DEPLOY_PATH }}
+ rm -f .prev_backend_tag_${{ steps.config.outputs.env }}
이 새 스텝에는 의도적으로 if: 조건을 걸지 않았습니다. GitHub Actions는 앞 스텝이 실패하면(=job 실패) if: 조건이 없는 뒤 스텝을 자동으로 스킵하는 기본 동작이 있기 때문에, 스모크 테스트가 실패하면 이 "배포 확정" 스텝 자체가 실행되지 않고 마커가 그대로 남습니다. 그러면 기존 롤백 스텝(if: failure())이 정상적으로 이전 태그를 찾아 되돌릴 수 있게 됩니다. 별도의 조건 분기를 추가하지 않고 CI 플랫폼의 기본 동작을 그대로 활용한 점이 이 수정의 핵심입니다.
변경된 파일은 두 개입니다.
.github/workflows/cd.yml: 마커 삭제 로직 이동pm/docs/learnings.md: 이번 사고와 교훈 기록 추가
커밋도 두 개로, 첫 번째가 실제 워크플로 수정이고 두 번째는 이 사고를 팀 학습 기록에 남기는 문서화 커밋입니다. 시행착오라기보다는 사고 원인 파악 → 수정 → 기록이 한 번에 깔끔하게 이어진 흐름입니다.
배운 점 및 개선점
PR 본문에도 적혀 있듯이, 이번 사고는 "헬스체크 통과 = 배포 확정"이라는 암묵적 가정이 얼마나 위험한지 보여준 사례였습니다. 다단계 배포 검증 파이프라인에서는 중간 단계의 성공(헬스체크)을 최종 성공으로 착각하면 안전장치 자체가 무력화될 수 있다는 것 — 롤백에 필요한 정보는 가장 마지막 검증이 끝날 때까지 살려둬야 한다는 원칙을 다시 확인했습니다.
또한 이번 장애는 members.student_id 컬럼 추가가 SQLite ALTER 제약으로 실패한 것이 직접 원인인데, 이는 이미 #133에서 지적됐던 "ddl-auto가 DDL 실패를 삼킨다"는 문제가 실제로 재현된 사례이기도 합니다. 이 PR과는 별개로 prod는 수동으로 이전 태그(prod-9796d67...)로 롤백해 복구했고, members 스키마도 stage와 동일하게 수동 패치한 뒤 재배포해 4개 스모크 엔드포인트 모두 200을 확인했습니다. 근본적으로는 Flyway 같은 마이그레이션 도구 도입이 필요하다는 점이 다시 한번 실증된 셈입니다.
Test plan에 남긴 대로, 다음 실제 배포에서 "배포 확정" 스텝이 스모크 테스트 성공 시에만 실행되는지 Actions 로그로 확인하는 것과, 의도적으로 스모크 테스트를 실패시켜 롤백이 실제로 도는지 검증하는 것이 남은 과제입니다.