[CL] 2단계: CI(지속적 통합) 파이프라인 구축 설계 - 100-hours-a-week/6-nemo-wiki GitHub Wiki
1. CI 도입 개요
1-1. GitHub 도입 과정
- 기존에는 로컬 개발 → scp → 서버 복사 방식으로 배포했기 때문에 버전 이력이 단절되고, 코드 리뷰나 롤백이 어려움
- GitHub 도입을 통해 다음과 같은 구조로 개선:
- 중앙화된 버전 관리: 팀원 간 작업 내역 통합 가능
- 브랜치 전략 수립: feature/release/hotfix 전략으로 병렬 개발
- 워크플로우 기반 자동화 연동: GitHub Actions를 통한 CI 자동화 구성 용이
- 배포 이력 추적 및 롤백 가능: GitHub commit log 기준으로 언제든지 이전 버전으로 복원 가능
→ GitHub는 단순 저장소가 아닌, 개발 흐름을 통합하고 자동화 기반 CI의 중심으로 활용 가능하다는 점에서 선택됨
1-2. CI 도입 필요성 및 적용 이유
✅ 평가자 관점
- 현재 수작업 기반의 Big Bang 배포 방식을 사용하고 있음
- 반복적인 수동 배포와 테스트 누락 등으로 인해 지속적인 품질 관리 어려움 발생
- CI 도입을 통해 아래와 같은 핵심 역량을 평가하고자 함:
- 자동화된 품질 관리 체계 → 빌드 실패, 테스트 누락, 코드 충돌 등의 위험 요소를 사전에 차단할 수 있는 구조를 갖췄는가?
- 협업 기반 통합 프로세스의 설계 능력 → 다수의 브랜치가 동시에 작업되는 환경에서 일관된 기준으로 통합할 수 있는가?
- 도구 적합성과 효율성 고려 → Github와 연계하여 자연스럽고 유지보수 가능한 CI 체계를 구성했는가?
✅ 실무자 관점 (서비스 적용 이유)
-
현재 우리 서비스는 GCP EC2 기반 수작업 배포 방식을 사용하고 있으며, 다음과 같은 구조적 문제와 운영 이슈가 반복됨.
🔧현 구조의 문제점
- ssh 접속 → 빌드 → 실행 과정을 매번 수동 반복
- 테스트 자동화가 없어 운영 중 오류 발생 빈도 높음
- 로컬/서버 간 버전 차이로 인해 배포 후 에러 발생
- git 이력과 배포가 분리되어 있어 롤백이 불가능
📈 개발 규모 확대에 따른 문제
- feature/, bugfix/ 등 다수 브랜치에서 동시 작업 중
- 병합 및 배포 시점에 충돌 및 의존성 문제 빈발
- 개발자가 많아질수록 일관된 기준 부재가 문제로 작용
🕒 배포 주기 단축 필요
- MVP → 기능 확장 단계로 진입하면서 기능 릴리즈 속도와 품질 모두 유지할 수 있는 구조 필요
🧪 테스트/피드백 자동화 필요
- 커밋 시 자동 빌드/테스트를 수행하여 QA 단계 이전에 오류를 조기 감지 및 해결 가능
1-3. CI 도입 전략 (GitHub Actions 활용)
🔍 주요 도구 비교
항목 | GitHub Actions | GitLab CI/CD | Jenkins |
---|---|---|---|
설정 간편성 | ✅ 매우 쉬움 | ✅ 쉬움 | ❌ 복잡함 |
GitHub 연동성 | ✅ 네이티브 | ❌ 별도 필요 | ❌ Webhook 필요 |
러닝 커브 | ✅ 낮음 | ⚪ 중간 | ❌ Groovy 필요 |
유지보수 | ✅ 완전 관리형 | ✅ 관리형 | ❌ 자체 서버 필요 |
Marketplace | ✅ 풍부 | ⚪ 제한적 | ⚪ 플러그인 많음 |
CI/CD 통합 | ✅ 통합 가능 | ✅ 자체 통합 | ✅ 가능 |
✅ GitHub Actions 선택 사유:
- GitHub 저장소를 사용 중이므로 GitHub Actions 도입이 자연스럽고 설정이 간단함
- 러닝 커브가 낮고 빠르게 도입 가능
- 다양한 오픈소스 액션으로 유연한 파이프라인 구성 가능
- YAML 기반 워크플로우 구성으로 코드 버전 관리와 배포 연결
2. 파이프라인 설계 및 구성
2-1. GitFlow 브랜치 전략
- 기능 개발 →
feature/*
→develop
- 개발 통합/테스트 →
develop
- 운영 버그 긴급 수정 →
hotfix/*
→main
+develop
- 버그 수정 (개발 중) →
bugfix/*
→develop
✅ 기존 GitFlow 브랜츠와 다르게 현재 전략에서는 release/*
브랜치를 생략하는 이유:
develop
브랜치 자체가 기능 통합 + 테스트용으로 쓰이기 때문에, 별도로release/*
브랜치를 만들어 QA나 문서 작업을 하지 않아도 될 것 같다고 판단.
2-2. GitHub Actions 트리거 설정
- 모든 작업은 결국
main
또는develop
에 병합되어야 함 feature/*
,bugfix/*
→develop
hotfix/*
→main, develop
- 병합 전에 Pull Request 기반 테스트로 충분히 사전 검증 가능 → 즉,
main
과develop
에 대해서만 CI를 걸어도 전체 흐름이 커버될 것이라고 판단
브랜치 | 목적 | 병합 대상 | CI 트리거 |
---|---|---|---|
main |
운영/배포 기준 브랜치 | - | push , pull_request |
develop |
모든 개발 통합 브랜치 | main |
push , pull_request |
feature/* |
기능 개발 브랜치 | develop |
- |
bugfix/* |
개발 중 버그 수정 브랜치 | develop |
- |
hotfix/* |
운영 중 긴급 수정 브랜치 | main ,develop |
- |
on:
push:
branches:
- main
- develop
pull_request:
branches:
- main
- develop
→ Git Flow 구조는 유지: 기능/릴리스/핫픽스 역할 분담은 그대로 가져감
→ CI 트리거는 최소화해서 main
, develop
만 설정해서 효율성 확보
→ 실무 적합도 높음: 테스트 중복 줄이고, 필요한 시점에만 실행됨
2-3. CI 흐름도
- Pull Request 또는 Push 발생 (main / develop 브랜치 기준)
- [Pull Request일 경우]
- Lint & Unit Test 실행 (FE: ESLint, BE: Gradle Test, AI: pytest)
- 실패 시 병합 차단, 성공 시 병합 가능
- [Push 발생 시]
- 코드 checkout → 의존성 설치 (Node, Gradle, Python)
- 빌드 실행 (npm run build, ./gradlew build, pytest)
- 빌드 산출물을 GCS에 업로드
2-4. GCS 업로드 도입 이유
☁️ GCS 업로드 도입 배경: CI/CD 책임 분리 및 안정성 강화
- 기존에는 GitHub Actions 기반의 CI가 빌드 + 서버 전송까지 모두 수행하는 구조였지만 이 구조는 다음과 같은 문제를 야기했다:
❗️기존 구조의 문제점
CI가 CD까지 과도하게 책임짐 | scp로 직접 서버에 배포 → CD는 실질적 기능이 없음. |
---|---|
서버 장애 시 배포 실패 | 빌드 → 전송 중 서버가 다운되면, 전체 파이프라인 실패 & 복구 어려움 |
버전 추적 불가 | CI 산출물을 GCS에 남기지 않으면, 어떤 파일이 어떤 버전인지 관리 어려움 |
여러 서버 확장 불가 | scp 방식은 대상 서버가 늘어나면 관리 복잡도 급증 |
❗️GCS 도입 후 변화
CI/CD 책임 분리 | CI는 빌드/업로드, CD는 다운로드/배포로 역할 분리 |
---|---|
확장성 향상 | GCS에서 병렬 다운로드 → 멀티 서버, 롤백, 버전 관리 가능 |
장애 대응력 | 서버 다운되더라도 GCS에 아티팩트가 남아 복구 용이 |
GCP 친화성 | GCS는 GCE와 동일 프로젝트 내에서 빠르고 안전하게 연동됨 |
.github/workflows/
)
2-5. GitHub Actions 워크플로우 파일 (-
pr-ci.yml
name: CI - PR Lint & Test on: pull_request: branches: [main, develop] jobs: pr-test: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v3 - name: Set up JDK uses: actions/setup-java@v3 with: java-version: '21' distribution: temurin - name: Grant execute permission run: chmod +x gradlew # - name: Run Tests # run: ./gradlew test
-
ci.yml
name: CI - Backend Build & Upload to GCS on: push: branches: [main, develop] jobs: build: runs-on: ubuntu-22.04 steps: - name: Checkout code uses: actions/checkout@v3 - name: Set up JDK 21 uses: actions/setup-java@v3 with: java-version: '21' distribution: temurin - name: Grant execute permission to Gradle run: chmod +x gradlew - name: Build with Gradle run: ./gradlew clean bootJar - name: Authenticate to GCP uses: google-github-actions/auth@v1 with: credentials_json: ${{ secrets.GCP_KEY_JSON }} - name: Set up gcloud CLI uses: google-github-actions/setup-gcloud@v1 with: project_id: ${{ secrets.GCP_PROJECT_ID }} - name: Set environment prefix run: | if [ "${{ github.ref_name }}" == "main" ](/100-hours-a-week/6-nemo-wiki/wiki/-"${{-github.ref_name-}}"-==-"main"-); then echo "TARGET_ENV=prod" >> $GITHUB_ENV else echo "TARGET_ENV=dev" >> $GITHUB_ENV fi - name: Upload .jar to GCS run: | FILE_PATH=$(ls ./build/libs/*.jar | head -n 1) gsutil cp "$FILE_PATH" gs://${{ secrets.GCS_BUCKET }}/$TARGET_ENV/backend/app.jar - name: Upload deploy scripts to GCS run: | gsutil cp ./deploy/*.sh gs://${{ secrets.GCS_BUCKET }}/$TARGET_ENV/backend/
3. CI 도입 기대 효과 및 정량적 개선
3.1. 도입 기대 효과
- 반복 작업 자동화 → 배포 시간 단축
- 커밋/PR 시점에서 테스트 수행 → 오류 조기 발견
- 코드 스타일 및 품질 일관성 유지 (lint/test 공통 적용)
- git과 배포 연결 → 롤백 및 이력 관리 용이
- 브랜치별 CI → 협업 시 역할 분담 명확화
3.2. 정량 개선 지표
개선 항목 | 기존 수작업 방식 (Before) | CI 도입 이후 (After) | 개선 효과 |
---|---|---|---|
배포 준비 시간 | 평균 15~30분 (빌드, 전송, 실행 수동 진행) | 평균 2~3분 (자동 빌드 및 테스트 완료) | ⏱ 약 80% 단축 |
테스트 누락률 | 테스트 수동 실행 → 누락 빈번 | 커밋/PR 시 자동 테스트 실행 | 🧪 테스트 커버리지 +30% 예상 |
릴리즈 주기 | 하루 1회 이하 제한적 수동 릴리즈 | 기능 완료 후 즉시 배포 가능 | 🚀 릴리즈 속도 2배 향상 |
오류 발견 시점 | 운영 중 오류 발견 → 배포 후 대응 | CI 단계에서 사전 감지 | 🔍 배포 후 오류 발생률 50%↓ |
롤백 대응 | 수동 복원, 버전 추적 불가 | git 커밋 기반 자동 추적 가능 | 🔁 롤백 시간 → 수 초 수준 |
협업 효율성 | 브랜치 간 배포 기준 불명확 | develop / main 기준 분리 명확 | 👥 작업 책임 구분 용이 |