[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 브랜치 전략

  1. 기능 개발feature/*develop
  2. 개발 통합/테스트develop
  3. 운영 버그 긴급 수정hotfix/*main + develop
  4. 버그 수정 (개발 중)bugfix/*develop

✅ 기존 GitFlow 브랜츠와 다르게 현재 전략에서는 release/* 브랜치를 생략하는 이유:

  • develop 브랜치 자체가 기능 통합 + 테스트용으로 쓰이기 때문에, 별도로 release/* 브랜치를 만들어 QA나 문서 작업을 하지 않아도 될 것 같다고 판단.

2-2. GitHub Actions 트리거 설정

  • 모든 작업은 결국 main 또는 develop에 병합되어야 함
  • feature/*, bugfix/*develop
  • hotfix/*main, develop
  • 병합 전에 Pull Request 기반 테스트로 충분히 사전 검증 가능 → 즉, maindevelop에 대해서만 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만 설정해서 효율성 확보

→ 실무 적합도 높음: 테스트 중복 줄이고, 필요한 시점에만 실행됨 gffffff drawio

2-3. CI 흐름도

  1. Pull Request 또는 Push 발생 (main / develop 브랜치 기준)
  2. [Pull Request일 경우]
    • Lint & Unit Test 실행 (FE: ESLint, BE: Gradle Test, AI: pytest)
    • 실패 시 병합 차단, 성공 시 병합 가능
  3. [Push 발생 시]
    • 코드 checkout → 의존성 설치 (Node, Gradle, Python)
    • 빌드 실행 (npm run build, ./gradlew build, pytest)
    • 빌드 산출물을 GCS에 업로드 Final_Archieticture-CD 파이프라인 v2 drawio

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와 동일 프로젝트 내에서 빠르고 안전하게 연동됨

2-5. GitHub Actions 워크플로우 파일 (.github/workflows/)

  1. 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
    
  2. 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 기준 분리 명확 👥 작업 책임 구분 용이