💻 프로젝트/QRoad

서버 git pull 배포에서 GHCR 기반 Docker 배포로 전환한 기록

SoloQuest 2026. 3. 30. 03:22

배포 방식을 기존의 서버에서 git pull + 빌드 방식에서,
CI에서 이미지 빌드 + GHCR 푸시 + 서버는 pull만 하는 구조로 바꿨다.

작지만 확실한 개선이었고, 실제로 겪은 오류와 해결 과정을 정리해본다.

왜 바꿨나?

기존 방식은 서버가 직접 빌드했다.

  • 서버 상태(자바/그레이들/캐시)에 따라 결과가 달라질 수 있음
  • /home/ubuntu/BE 같은 경로 의존성이 큼
  • 배포 실패 시 원인 추적이 어려움
  • 롤백이 명확하지 않음

그래서 목표를 이렇게 잡았다.

  • 빌드는 CI에서만
  • 서버는 이미지 pull/run만
  • 커밋 태그 기반 배포
  • 실패 시 자동 롤백

기존 방식 (Before)

  1. GitHub Actions가 SSH로 서버 접속
  2. 서버에서 git pull
  3. ./gradlew clean build -x test
  4. 기존 프로세스 kill 후 java -jar 실행

즉, 서버가 코드/빌드/실행을 모두 담당했다.


변경한 방식 (After)

핵심 구조

  1. build_and_push Job
    • Docker 이미지 빌드
    • GHCR에 두 태그 푸시
      • ghcr.io/<org>/<repo>:<sha12>
      • ghcr.io/<org>/<repo>:latest
  2. deploy Job
    • SSH 허용 IP를 보안그룹에 임시 추가
    • 서버에 docker-compose.prod.ymldeploy.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.shdocker-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만 하자

비슷한 구조를 쓰는 팀이라면, 작은 프로젝트라도 이 패턴으로 빨리 옮기는 걸 추천한다.