— SonarCloud 품질 게이트와 GHCR 도커 이미지 자동 배포까지
📌 본문
1. 왜 GitHub Actions로 CI를 구성했는가
프로젝트 규모가 커질수록 다음 문제가 발생한다.
- 테스트가 깨져도 모르고 merge 되는 문제
- 커버리지가 점점 낮아지는 문제
- 코드 품질 관리가 개발자 감에 의존하는 문제
- 배포 시점에 도커 이미지 수동 빌드
이를 해결하기 위해 GitHub Actions 기반의 CI 파이프라인을 구성했다.
목표는 단순했다.
push → 테스트 → 커버리지 분석 → Sonar 품질 검사 → 도커 이미지 생성 → GHCR 저장
2. 전체 CI 구조
워크플로는 다음 세 단계로 구성했다.
① Backend CI
- Gradle build
- JUnit 테스트 실행
- JaCoCo 커버리지 리포트 생성
- SonarCloud 분석
- Quality Gate 통과 여부 확인
② Backend Docker Build & Push
- Docker Buildx 사용
- ghcr.io에 이미지 push
- pull_request에서는 push 하지 않음
③ Frontend Docker Build & Push
- frontend/** 경로 변경 시에만 실행
- Node 20 기반 build
- GHCR에 별도 frontend 이미지 저장
3. 커버리지 70% 강제 정책에 대한 판단
초기에는 JaCoCo에서 70% 미만이면 빌드를 실패하도록 설정했다.
tasks.jacocoTestCoverageVerification {
violationRules {
rule {
limit {
minimum = "0.70".toBigDecimal()
}
}
}
}
violationRules {
rule {
limit {
minimum = "0.70".toBigDecimal()
}
}
}
}
하지만 프로젝트 초기 단계에서는 테스트 코드가 충분하지 않아 CI가 계속 실패했다.
따라서 다음 전략으로 변경했다.
- Gradle의 커버리지 강제 검증은 CI에서 제외
- SonarCloud Quality Gate로 품질 관리
- 단계적으로 커버리지 상승 전략 채택
이 방식은 개발 속도와 품질 균형을 맞추는 현실적인 접근이다.
4. SonarCloud 연동에서 겪은 문제
SonarCloud 설정 시 다음 오류가 발생했다.
- projectKey 불일치
- default branch 미설정
- Automatic Analysis와 CI 분석 충돌
해결 방법은 다음과 같다.
- SonarCloud → Administration → Information에서 실제 projectKey 복사
- Automatic Analysis OFF
- 기본 브랜치(main/master)에서 한 번 성공적으로 분석 수행
이 과정을 거치면 Quality Gate가 정상 동작한다.
5. GHCR를 사용하는 이유
Docker Hub 대신 GHCR를 선택한 이유:
- GitHub와 완전 통합
- 별도 토큰 없이 GITHUB_TOKEN으로 인증 가능
- 레포지토리 권한과 패키지 권한 연동
- CI/CD 흐름이 단순해짐
배포 구조는 다음과 같다.
코드 push
↓
GitHub Actions
↓
Docker image build
↓
ghcr.io 업로드
↓
서버에서 docker pull 실행
↓
GitHub Actions
↓
Docker image build
↓
ghcr.io 업로드
↓
서버에서 docker pull 실행
6. 최종적으로 얻은 것
- 테스트 자동 실행
- 커버리지 가시화
- 정적 코드 품질 관리
- 도커 이미지 자동 생성
- PR 단계에서 품질 게이트 확인
CI는 단순 자동화가 아니다.
개발자가 코드를 작성하는 순간부터 품질을 강제하는 구조다.
7. 결론
GitHub Actions 기반 CI는 단순 빌드 도구가 아니다.
- 아키텍처 보호 장치
- 품질 유지 장치
- 배포 자동화 기반
- 협업 안정성 확보 수단
특히 도메인 복잡도가 높은 결제·정산 시스템에서는
CI가 없다면 기술 부채는 빠르게 누적된다.
CI는 선택이 아니라 필수다.
LIST
'Spring & Backend' 카테고리의 다른 글
| 멀티 쓰레딩에 대해서 설명해 주세요. (0) | 2026.02.26 |
|---|---|
| Slack 알림 연동으로 운영 대응 자동화하기 (0) | 2026.02.24 |
| JIRA의 복잡한 프로세스를 work.md 하나로 관리할 수 있을까? (0) | 2026.02.24 |
| SonarQube 사용법 완전 정리 (0) | 2026.02.24 |
| 통합 자동화 구성 프롬프트 (0) | 2026.02.24 |
