배포 방식을 기존의 서버에서 git pull + 빌드 방식에서,
CI에서 이미지 빌드 + GHCR 푸시 + 서버는 pull만 하는 구조로 바꿨다.
작지만 확실한 개선이었고, 실제로 겪은 오류와 해결 과정을 정리해본다.
왜 바꿨나?
기존 방식은 서버가 직접 빌드했다.
- 서버 상태(자바/그레이들/캐시)에 따라 결과가 달라질 수 있음
- /home/ubuntu/BE 같은 경로 의존성이 큼
- 배포 실패 시 원인 추적이 어려움
- 롤백이 명확하지 않음
그래서 목표를 이렇게 잡았다.
- 빌드는 CI에서만
- 서버는 이미지 pull/run만
- 커밋 태그 기반 배포
- 실패 시 자동 롤백
기존 방식 (Before)
- GitHub Actions가 SSH로 서버 접속
- 서버에서 git pull
- ./gradlew clean build -x test
- 기존 프로세스 kill 후 java -jar 실행
즉, 서버가 코드/빌드/실행을 모두 담당했다.
변경한 방식 (After)
핵심 구조
- build_and_push Job
- Docker 이미지 빌드
- GHCR에 두 태그 푸시
- ghcr.io/<org>/<repo>:<sha12>
- ghcr.io/<org>/<repo>:latest
- deploy Job
- SSH 허용 IP를 보안그룹에 임시 추가
- 서버에 docker-compose.prod.yml, deploy.sh 전송(scp)
- 서버에서 배포 스크립트 실행
- commit 태그 pull 우선
- 실패 시 latest fallback
- docker compose up -d
- health check 실패 시 이전 이미지 롤백
- 마지막에 보안그룹 IP 제거
서버 레포 의존성 제거
처음에는 서버에 /home/ubuntu/BE가 있어야 했는데,
배포 중 아래 오류를 만났다.
cd: /home/ubuntu/BE: No such file or directory
해결은 간단했다.
- 서버 고정 배포 디렉토리를 /opt/qroad로 변경
- 매번 필요한 파일(deploy.sh, docker-compose.prod.yml)을 CI가 scp로 전달
- 서버에 git clone/pull 필요 없도록 전환
로그 경로도 정리
처음엔 /log/qroad-be를 썼다가 운영 편의상 ~/log/qroad-be로 변경했다.
- 컨테이너 내부: /log
- 호스트: /home/ubuntu/log/qroad-be
- 파일명: YYYY-MM-DD.log
실제로 겪은 오류와 해결
1) ECR 로그인 권한 오류
기존 ECR 시도 때 ecr:GetAuthorizationToken 권한 에러 발생.
→ GHCR(private)로 전환해서 해결.
2) deploy job에서 scp 실패
오류:
scp: stat local "docker-compose.prod.yml": No such file or directory
원인:
- deploy job에 checkout이 없어서 워크스페이스에 파일이 없었음
해결:
- deploy job에도 actions/checkout@v4 추가
3) Logback %clr 에러로 앱 부팅 실패
오류:
There is no conversion class registered for composite conversion word [clr]
원인:
- logback-spring.xml에 %clr 사용하면서 conversionRule 미등록
해결:
<conversionRule conversionWord="clr" class="org.springframework.boot.logging.logback.ColorConverter"/>
감정 공감 기능도 같이 개선
새로고침하면 상태가 풀리는 이슈가 있어 점검했다.
기존:
- 감정 식별자 기반이 IP
개선:
- qroad_uid 쿠키(UUID) 기반으로 통일
- 기사 상세 응답에 myEmotion 추가해서 프론트가 새로고침 후 상태 복원 가능하게 변경
DB 스키마 변경은 필요 없었다.
보안 체크
배포/로깅 수정 후 gitleaks로 히스토리 스캔도 수행했다.
- 결과: no leaks found
전환 후 체감 효과
- 서버 환경 의존도 감소
- 배포 재현성 향상
- 롤백 전략 명확
- 경로/권한 이슈 디버깅 쉬워짐
- 운영 로그 관리 편해짐
이 방식이 특히 좋았던 이유
핵심은 한 줄이다.
마무리
이번 전환에서 얻은 결론:
- CI에서 빌드하고
- 레지스트리에 버전 고정하고
- 서버는 pull/run만 하자
비슷한 구조를 쓰는 팀이라면, 작은 프로젝트라도 이 패턴으로 빨리 옮기는 걸 추천한다.
'💻 프로젝트 > QRoad' 카테고리의 다른 글
| AWS 기반 운영 모니터링 확장기(Prometheus + Grafana로 API 성능 · 비용 · 알람까지 구축하기) - 2편 (0) | 2026.02.19 |
|---|---|
| AWS 기반 운영 모니터링 환경 구축기 (EC2 + CloudWatch + Grafana) - 1편 (0) | 2026.02.19 |
| 3분 이상 걸리는 기사 발행 API를 Job 기반 비동기로 전환하며 고민한 것들 (0) | 2026.02.16 |