☁️ 2단계 : CI 파이프라인 구축 설계 - 100-hours-a-week/7-team-ddb-wiki GitHub Wiki

1. 개요 (Overview)

현재 서비스가 빠르게 확장됨에 따라 여러 개발자가 동시에 기능을 개발하고 커밋하는 상황이 늘어나고 있다.

기존에는 수동으로 빌드와 테스트를 수행한 뒤 배포 전 오류를 확인했으나, 시간이 지체되고 사람이 직접 확인하다 보니 통합 오류를 놓치기 쉬운 문제가 있었다.

본 단계에서는 Jenkins를 기반으로 한 CI(지속적 통합) 파이프라인을 설계하여, 코드 커밋 시 자동으로 빌드와 테스트를 수행하고, 테스트 결과를 Discord로 알림으로 공유함으로써 개발 생산성과 품질을 높이는 데 초점을 맞추고자 한다.

2. 도입 배경 및 필요성

항목 설명
수동 빌드·테스트 부담 기존 수작업 빌드로 개발자의 시간이 낭비되고, 오류 발견 시점이 늦어지는 문제가 있다.
협업 시 통합 오류 증가 여러 개발자가 동시에 작업할 경우 버전 충돌이나 빌드 실패 등의 문제를 빠르게 파악하기 어렵다.
지속적 검증 요구 서비스가 점차 복잡해지고, 짧은 주기로 기능 업데이트해야 하는 상황에서 자동화된 빌드 및 테스트는 필수적이다.
조기 피드백 커밋 이후 즉시 테스트가 실행되고 결과가 공유되면, QA 및 수정 사이클을 크게 단축할 수 있어 서비스 품질 향상으로 이어진다.

3. 목표 & 적용 범위

  • 목표
    • Pull Request/Commit 발생 시 자동 빌드 → 테스트 → 결과 보고 흐름을 자동화
    • 빌드 실패 및 테스트 실패를 팀 전원이 빠르게 인지하도록 알림 시스템(Discord) 연동
    • 빌드·테스트 시간을 30% 이상 단축하여, 릴리즈 사이클을 가속화
  • 적용 범위
    • 개발/운영 브랜치에 대한 CI 파이프라인 적용
    • Jenkins 서버 운영 & 관리 (플러그인, WebHook 등)
    • Discord를 통한 빌드·테스트 결과 공유

4. 설계 상세

4.1 CI 파이프라인

Jenkins

  • 온프레미스 설치 가능성과 자유로운 제어

    Jenkins는 온프레미스 도구이므로 GCP VM 인스턴스 등에 직접 설치해 사용할 수 있다. 반면 GitHub Actions나 GitLab CI는 SaaS 기반이라 외부 네트워크 접근 및 보안 정책 제어에 한계가 있다. 따라서 Jenkins는 기업 환경이나 보안 요구가 높은 프로젝트에서 네트워크, 접근 권한, 실행 환경을 모두 직접 통제할 수 있다는 점에서 유리하다.

  • 플러그인 생태계의 폭넓은 확장성

    Jenkins는 수천 개 이상의 플러그인을 통해 Lint, 테스트 커버리지(Jacoco, Cobertura), 정적 분석(SonarQube), 빌드 도구(Gradle, npm, Maven) 등을 완전히 통합할 수 있다. 반면 GitHub Actions나 GitLab CI는 자체 Action/Runner의 제약이 있으며 외부 도구 연동 시 설정이 복잡하거나 비용이 추가된다.

  • 로컬 테스트 및 디버깅 편의성

    Jenkins는 자체 VM에서 로컬 환경을 미러링해 동일한 CI 환경에서 테스트 및 디버깅을 수행할 수 있다. 반면 GitHub Actions, GitLab CI는 클라우드 상에서만 실행되므로, 동일 환경 디버깅을 위해서는 별도 CI Runner 구성이나 로컬 액션 테스트 도구를 추가로 사용해야 한다.

  • 향후 CD까지 확장 용이

    Jenkins는 CI뿐 아니라 CD로 확장하기 위한 구성도 잘 갖춰져 있어, 배포 단계 조건 제어, 승인 흐름, Blue‑Green 전략 등을 유연하게 구성할 수 있다. SaaS 기반 CI 도구는 GitOps 또는 클라우드 배포 서비스에 의존해야 해 커스터마이징 자유도가 제한된다.

Discord

  • 실시간 CI/CD 알림 허브

    Jenkins Webhook과 연동해 빌드·테스트 성공/실패 결과가 채팅방에 즉시 게시된다. 개발자는 IDE를 벗어나지 않고도 파이프라인 상태를 파악할 수 있어 장애 대응 속도가 크게 향상된다.

  • 프로젝트·채널별 Webhook 분리 관리

    Discord는 Webhook URL을 무제한으로 생성할 수 있어, 서비스·환경(Dev/Prod)·팀별로 알림 채널을 세분화할 수 있다. 잡마다 알림 대상을 정확히 지정해 “필요한 사람”에게만 노이즈 없이 정보를 전달한다.

  • 알림 기반 협업 가속

    PR 머지·배포 승인·테스트 실패 등 주요 이벤트가 자동으로 공유되므로, 팀원이 같은 맥락을 실시간으로 공유하고 빠르게 의사결정을 내릴 수 있다. 결과적으로 개발 주기가 단축되고 코드 품질 확보가 용이해진다.

  • 저비용·범용성

    Discord는 기본 기능이 무료이며, 데스크톱·모바일·웹 클라이언트를 지원해 접속 환경 제약이 없다. 별도의 SaaS 연동 비용이나 라이선스 없이 손쉽게 CI 알림 허브를 구축할 수 있다는 점에서 스타트업·소규모 팀에 특히 적합하다.

4.2 CI 파이프라인 상세

파이프라인 절차 상세

단계 작업 내용 주요 도구 담당자/역할 산출물
1 코드 커밋 & PR 생성 개발자가 GitHub에 변경 사항 푸시 Git, GitHub 개발자 소스 코드 (PR)
2 빌드 트리거 & 코드 체크아웃 Jenkins가 Commit/PR 이벤트 감지 최신 소스를 체크아웃 Jenkins, Git Plugin Jenkins 빌드 준비 (소스 코드)
3 빌드 & 컴파일 의존성 다운로드, Gradle/Maven 또는 npm 등으로 빌드 수행 Jenkins Jenkins 빌드 산출물 (jar/war 등)
4 테스트 실행 Unit 테스트, 통합 테스트 실행 결과 리포트 생성 Jenkins, Test Runner Jenkins 테스트 결과 리포트
5 알림 전송 빌드/테스트 결과(성공/실패)를 Discord로 전송 Discord WebHook Jenkins 메시지 알림

4.3 설정 · 스크립트 명세

BE

/*------------------------------------------------------------------
   Jenkins Declarative Pipeline – Backend
   · Gradle로 JAR 빌드 → 테스트 → Discord 알림
------------------------------------------------------------------*/
pipeline {
    /*--------------- 어떤 노드에서도 실행 ---------------*/
    agent any

    /*--------------- JDK 21(TEMURIN) 사용 ---------------*/
    tools {
        jdk 'temurin-21'
    }

    /*--------------- 단계 정의 ---------------*/
    stages {
        /* 1. Git 소스 체크아웃 */
        stage('Checkout') {
            steps {
                /* 파라미터로 넘어온 브랜치를 그대로 사용 */
                git branch: env.BRANCH_NAME,
                    url: 'https://github.com/100-hours-a-week/7-team-ddb-be.git'
            }
        }

        /* 2. Gradle 빌드 (테스트 제외) */
        stage('Build') {
            steps {
                script {
                    sh 'chmod +x gradlew'                 // gradlew 실행권한 부여
                    sh './gradlew clean build -x test'    // JAR 빌드
                }
            }
        }

        /* 3. Gradle 단위 테스트 */
        stage('Test') {
            steps {
                script {
                    sh './gradlew test'                   // JUnit 등 테스트 실행
                }
            }
        }
    }

    /*--------------- 빌드 결과 Discord 전송 ---------------*/
    post {
        /* 파이프라인 성공 시 */
        success {
            withCredentials([string(credentialsId: 'Discord-Webhook',
                                    variable: 'DISCORD')]) {
                discordSend description: """
                제목 : ${currentBuild.displayName}
                결과 : ${currentBuild.result}
                실행 시간 : ${currentBuild.duration / 1000}s
                """,
                link: env.BUILD_URL,
                result: currentBuild.currentResult,
                title: "${env.JOB_NAME} : ${currentBuild.displayName} 성공",
                webhookURL: "$DISCORD"
            }
        }
        /* 파이프라인 실패 시 */
        failure {
            withCredentials([string(credentialsId: 'Discord-Webhook',
                                    variable: 'DISCORD')]) {
                discordSend description: """
                제목 : ${currentBuild.displayName}
                결과 : ${currentBuild.result}
                실행 시간 : ${currentBuild.duration / 1000}s
                """,
                link: env.BUILD_URL,
                result: currentBuild.currentResult,
                title: "${env.JOB_NAME} : ${currentBuild.displayName} 실패",
                webhookURL: "$DISCORD"
            }
        }
    }
}

FE

/*------------------------------------------------------------------
   Jenkins Declarative Pipeline – Frontend
   · npm CI → 빌드 → 테스트 → Discord 알림
------------------------------------------------------------------*/
pipeline {
    agent any                                // 모든 가용 노드에서 실행

    /* Node 21 버전 사용 (Global Tool Config) */
    tools {
        nodejs 'node-21'
    }

    stages {
        /* 1. Git 체크아웃 */
        stage('Checkout') {
            steps {
                git branch: env.BRANCH_NAME,
                    url: 'https://github.com/100-hours-a-week/7-team-ddb-fe.git'
            }
        }

        /* 2. 의존성 설치 (package‑lock.json 기반) */
        stage('Install Deps') {
            steps { sh 'npm ci' }
        }

        /* 3. 정적 빌드 (Next.js 등) */
        stage('Build') {
            steps { sh 'npm run build' }
        }

        /* 4. 테스트 (스크립트가 있을 때만 실행) */
        stage('Test') {
            steps { sh 'npm test --if-present' }
        }
    }

    /* 빌드 결과 Discord 전송 */
    post {
        success {
            withCredentials([string(credentialsId: 'Discord-Webhook',
                                    variable: 'DISCORD')]) {
                discordSend description: """
                제목 : ${currentBuild.displayName}
                결과 : ${currentBuild.result}
                실행 시간 : ${currentBuild.duration / 1000}s
                """,
                link: env.BUILD_URL,
                result: currentBuild.currentResult,
                title: "${env.JOB_NAME} : ${currentBuild.displayName} 성공",
                webhookURL: "$DISCORD"
            }
        }
        failure {
            withCredentials([string(credentialsId: 'Discord-Webhook',
                                    variable: 'DISCORD')]) {
                discordSend description: """
                제목 : ${currentBuild.displayName}
                결과 : ${currentBuild.result}
                실행 시간 : ${currentBuild.duration / 1000}s
                """,
                link: env.BUILD_URL,
                result: currentBuild.currentResult,
                title: "${env.JOB_NAME} : ${currentBuild.displayName} 실패",
                webhookURL: "$DISCORD"
            }
        }
    }
}

AI

/*------------------------------------------------------------------
   Jenkins Declarative Pipeline – AI
   · Python venv → 의존성 설치 → pytest → Discord 알림
------------------------------------------------------------------*/
pipeline {
    agent any                                // 어디서나 실행

    /* Python 3.11 버전 사용 */
    tools {
        python 'python3.11'
    }

    stages {
        /* 1. Git 체크아웃 */
        stage('Checkout') {
            steps {
                git branch: env.BRANCH_NAME,
                    url: 'https://github.com/100-hours-a-week/7-team-ddb-ai.git'
            }
        }

        /* 2. 가상환경 생성 및 패키지 설치 */
        stage('Setup venv') {
            steps {
                sh '''
                   python -m venv venv                       # 가상환경 생성
                   . venv/bin/activate                      # venv 활성화
                   pip install --upgrade pip                # pip 최신화
                   pip install -r requirements.txt          # 의존성 설치
                '''
            }
        }

        /* 3. pytest 실행 */
        stage('Test') {
            steps {
                sh '''
                   . venv/bin/activate
                   pip install pytest
                   pytest                                    # 단위 테스트
                '''
            }
        }
    }

    /* Discord 알림 (성공/실패) */
    post {
        success {
            withCredentials([string(credentialsId: 'Discord-Webhook',
                                    variable: 'DISCORD')]) {
                discordSend description: """
                제목 : ${currentBuild.displayName}
                결과 : ${currentBuild.result}
                실행 시간 : ${currentBuild.duration / 1000}s
                """,
                link: env.BUILD_URL,
                result: currentBuild.currentResult,
                title: "${env.JOB_NAME} : ${currentBuild.displayName} 성공",
                webhookURL: "$DISCORD"
            }
        }
        failure {
            withCredentials([string(credentialsId: 'Discord-Webhook',
                                    variable: 'DISCORD')]) {
                discordSend description: """
                제목 : ${currentBuild.displayName}
                결과 : ${currentBuild.result}
                실행 시간 : ${currentBuild.duration / 1000}s
                """,
                link: env.BUILD_URL,
                result: currentBuild.currentResult,
                title: "${env.JOB_NAME} : ${currentBuild.displayName} 실패",
                webhookURL: "$DISCORD"
            }
        }
    }
}

4.4 WebHook 설정

  • Jenkins 설치 & 기본 플러그인
    • Git Plugin, Pipeline Plugin, Discord Notification Plugin 등
  • Credential & 환경 변수 설정
    • Git 접근 토큰, Discord WebHook URL
    • 빌드 도구(예: Gradle, npm) PATH 등
  • GitHub → Jenkins
    • Repository Settings에서 WebHook 등록, 커밋/PR 발생 시 Jenkins 파이프라인 트리거
  • Jenkins → Discord
    • Jenkinsfile 내에서 discordSend 함수를 통해 결과 전송

5. 한계 및 리스크

항목 설명
Jenkins 서버 의존도 Jenkins 자체 장애가 발생할 경우 빌드와 테스트를 수행할 수 없으므로 HA 구성 또는 백업용 컨트롤러 도입 검토가 필요하다.
테스트 커버리지 부족 CI 자동화가 구축되어 있어도 테스트 코드가 미비하면 통합 오류나 버그를 놓칠 위험이 여전히 존재한다.
플러그인 호환성 Jenkins에 다양한 플러그인을 설치할 경우, 버전 간 충돌이나 설정 오류가 발생할 수 있다.

6. 기대 효과 & 적용 후 평가

항목 설명
지속적 통합 & 빠른 피드백 커밋 직후 빌드·테스트가 실행되어 오류를 조기에 발견, 수정할 수 있다.
팀 협업 강화 Discord 알림으로 팀 전원이 빌드 및 테스트 결과를 실시간으로 공유하고 문제 발생 시 신속 대응한다.
배포 안정성 향상 빌드 단계에서 미리 결함을 제거하고, 1단계의 수작업 배포 전에 품질 검증이 가능하다.

실제 운영 후 모니터링

  • 빌드 성공률, 빌드 소요 시간, 테스트 성공률 등을 정기적으로 확인한다.
  • 오류 로그 축적 후, 반복되는 문제나 취약한 부분(테스트 범위 부족 등)을 개선한다.

7. 결론 및 향후 계획

결론

  • Jenkins 기반 CI 파이프라인 도입으로 개발 자동화를 실현하고, Discord 알림으로 팀 협업 효율을 높인다.
  • 이는 코드 품질과 배포 안정성 향상에 직접 기여할 것으로 기대된다.

향후 계획

  • 테스트 스펙 보강: 단위 테스트 외에 통합 테스트, 성능 테스트 추가 등 커버리지를 확대한다.
  • CD(지속적 배포) 도입 연계: 3단계에서 배포/운영 환경에 자동으로 배포하는 CD 파이프라인을 구축한다.
  • Jenkins 서버 고가용성(HA) 구성 또는 다른 CI 도구와 연동 가능성 검토한다.