훅: 헬스체크가 401을 실패로 보고 있었다
기존 헬스체크 동작
- 앱 재시작 후
/monitor/health호출 - 응답이 오면 성공 처리
until "${SSH_CMD[@]}" "$REMOTE_USER@$REMOTE_HOST" \
"curl -fsS 'http://127.0.0.1:$APP_PORT$HEALTH_ENDPOINT' >/dev/null"; do
...
done
-
curl -f— 4xx/5xx를 실패로 처리 - 해당 엔드포인트 — Spring Security 인증이 걸려 있어 401 반환
- 즉, 애플리케이션이 완전히 정상 기동한 상태에서 401
401이 실제로 증명하는 것
- 요청이 애플리케이션에 도달
- 서블릿 컨테이너 생존
-
필터 체인 동작
- 헬스체크가 알고 싶은 것 — “앱이 떴는가” — 은 이미 충족
- 인증 실패 여부는 그 다음 층위의 얘기
200만이 성공이라고 가정한 게 문제였다.
- 헬스체크의 질문 — “이 앱이 요청을 처리할 수 있는가”
- 헬스체크의 질문이 아닌 것 — “내가 이 리소스에 접근할 권한이 있는가”
조치 — 성공으로 인정할 코드를 목록화
HEALTH_SUCCESS_CODES="${HEALTH_SUCCESS_CODES:-200,401}"
until false; do
HTTP_CODE="$(... "curl -s -o /dev/null -w '%{http_code}' 'http://127.0.0.1:$APP_PORT$HEALTH_ENDPOINT' || true")"
if [[ ",$HEALTH_SUCCESS_CODES," == *",$HTTP_CODE,"* ]]; then
echo "헬스체크 성공: HTTP $HTTP_CODE"
break
fi
echo "헬스체크 대기중: HTTP $HTTP_CODE"
...
done
같이 고친 것
- 기존 타임아웃 동작 — “수동 점검 필요” 출력 후
exit 1. 실패한 배포본이 서버에 그대로 올라간 채 사람을 기다리는 상태 - 변경 — 타임아웃 시
rollback즉시 호출
자동 롤백이 없는 자동 배포는 절반만 자동이다.
-
curl실패로 코드를 못 읽는 경우 대비|| true추가 - 이유:
set -euo pipefail아래에서는 curl 실패가 스크립트 전체를 죽여 롤백 로직에 미도달
더 큰 문제: 스크립트가 두 벌이었다
-
deploy.sh존재 -
scripts/deploy/deploy-to-web2.sh— 266줄짜리가 별도 존재 -
두 파일이 SSH 접속·빌드·전송·재시작을 각자의 방식으로 중복 구현
- 이 상태에서 헬스체크 수정 시 한쪽만 반영
- 실증 — 위의 401 수정도 한쪽에만 적용된 상태
어떻게 고쳤나: 서브커맨드 오케스트레이터
deploy.sh를 진입점 하나로 통일 + 실제 로직은 파일로 분리
deploy.sh <backend | frontend admin|user|all | all>
│
├── scripts/deploy/_common.sh SSH 실행, 로그 출력
├── scripts/deploy/_backend.sh 빌드 → 전송 → 헬스체크 → 롤백
└── scripts/deploy/_frontend.sh git 사전 검증 → 원격 pull/build/restart
-
_접두사 — “직접 실행하는 파일이 아니라 source되는 라이브러리”라는 표시 - 진입점은
deploy.sh하나뿐이라는 걸 파일명만 보고 판별 가능
분리 기준 — 배포 대상이 달라지면 절차가 달라진다
| 대상 | 절차 |
|---|---|
| 백엔드 | 로컬에서 jar 빌드 → 전송 |
| 프론트엔드 | 원격에서 git pull → 빌드 |
- 공통은 SSH와 로그뿐 →
_common.sh는 54줄로 작음. 억지로 더 공통화하지 않음 -
집계 — 396줄 삭제, 418줄 추가
- 총량은 거의 동일
- 얻은 것 — 중복 한 벌 제거 + 파일 경계 확보
프론트엔드에는 git 사전 검증을 붙였다
- FE 배포 방식 — 원격에서
git pull후 빌드 - 함정 — 로컬에서 아무리 확인해도, 푸시하지 않은 커밋은 서버에 안 감
로컬: 수정하고 확인 → "잘 되네" → 배포 실행
원격: git pull → 변경 없음 → 이전 코드 그대로 빌드
결과: 배포는 성공했는데 아무것도 안 바뀜
배포 전 검사 3종
| 검사 | 막는 상황 |
|---|---|
| uncommitted 변경 | 커밋 안 한 수정이 반영 안 됨 |
| 브랜치 확인 | 다른 브랜치에서 배포 |
| unpushed 커밋 | 로컬에만 있는 커밋이 반영 안 됨 |
- 셋 다 “배포는 성공하는데 결과가 틀린” 부류의 실패
- 에러 발생 시 — 인지 가능
- 이 부류 — 조용히 통과
- 결론: 사전 검증으로 막는 게 값이 큼
남는 교훈
헬스체크는 무엇을 확인하는지 정확히 정의해야 한다.
- “200이면 정상” — 정의가 아니라 가정
- 이 엔드포인트에서 앱 생존의 증거 = 401
- 성공 조건의 분기점 — 프로세스 생존 / 요청 처리 가능성 / 의존 서비스 연결 중 무엇을 보느냐
자동 배포의 완결 조건은 자동 롤백이다.
- 실패 감지 후 사람 호출 vs 실패 감지 후 되돌리기
- 둘의 격차 = 장애 지속 시간 전부
중복된 스크립트는 수정을 반쪽으로 만든다.
- 증거 — 401 수정이 한쪽에만 반영된 사실
- 스크립트 두 벌 → 버그도 두 벌
- 고치는 사람이 아는 것 — 한 벌뿐
조용한 실패를 사전 검증으로 바꾼다.
- unpushed 커밋 배포 — 에러 0건, 결과만 오답
- 이 부류는 사후 감지 난이도 높음
- 유일하게 싼 방법 — 앞에서 차단