멀티 모듈 프로젝트를 위한 Jenkins + Docker + K8s CI/CD 파이프라인 최적화

궁금하면 500원·2025년 9월 18일

미생의 개발 이야기

목록 보기
58/73

SmartCampus 실서비스를 위한 CI/CD 완벽 구축 가이드

(Issue/PR 템플릿 + Jenkins + Kubernetes)

혼자 하는 프로젝트라도 실서비스를 목표로 한다면 "어제 내가 뭘 했지?" 혹은 "이 코드가 운영 서버를 터뜨리진 않을까?" 하는 불안함에서 벗어나야 합니다.

이번 포스팅에서는 GitHub Actions 없이 Jenkins만 활용하여, SmartCampus와 같은 멀티 모듈 프로젝트(market-api, market-chat 등)의 Issue 관리부터 Kubernetes 배포까지 한 줄기 흐름으로 자동화하는 방법을 정리하였습니다.


1. 프로젝트 구조

SmartCampus는 하나의 레포지토리에 여러 백엔드 서비스가 포함된 멀티 모듈 구조입니다. 각 모듈의 독립성을 유지하면서 CI/CD를 통합 관리하는 것이 핵심입니다.

모듈명주요 역할포트
market-api메인 서비스 (상품/회원/쿠폰 등)8080
market-chatAI 채팅 & RAG (벡터 스토어 연동)8082
market-batch배치 작업 (정산/메일링)8081
frontend프론트화면80

2. Issue & PR 템플릿 자동화

팀 프로젝트는 물론 1인 프로젝트에서도 "정해진 규격"은 필수입니다.
.github 폴더를 통해 이슈와 PR 생성을 규격화합니다.

2.1 Issue 템플릿 (bug.yml, feature.yml 등)

이전의 텍스트 방식보다 직관적인 YAML 기반 Form을 사용하면 작성자가 빼먹는 정보 없이 정확하게 입력할 수 있습니다.

  • 경로: .github/ISSUE_TEMPLATE/bug.yml (Feature, Refactor도 동일 구조로 생성)
name: "🐛 Bug Report"
description: "발생한 버그를 보고합니다."
title: "[Bug]: "
labels: ["bug", "triage"]
body:
  - type: textarea
    id: reproduction
    attributes:
      label: "재현 단계"
      placeholder: "1. 로그인을 한다. 2. 장바구니를 누른다..."
    validations:
      required: true
  - type: dropdown
    id: module
    attributes:
      label: "관련 모듈"
      options:
        - market-api
        - market-chat
        - market-batch

2.2 Pull Request 템플릿

PR은 "무엇을 고쳤는가"와 "테스트를 했는가"를 증명하는 서류입니다.

  • 경로: .github/PULL_REQUEST_TEMPLATE.md
## 🔗 관련 이슈
- Closes #

## 📝 변경 사항
- [ ] 기능 추가: 
- [ ] 버그 수정: 
- [ ] 리팩토링: 

## 🛠 체크리스트
- [ ] Local Test 완료 (`./gradlew test`)
- [ ] Jenkins CI 통과 후 Merge 예정
- [ ] 환경 변수(Secret) 변경 여부

3. Jenkins & GitHub 연동

Jenkins가 내 저장소를 감시하고 상태를 업데이트하려면 Personal Access Token이 필요합니다.

  1. GitHub Settings: Developer Settings → Personal access tokens → Tokens
  2. 권한 설정: repo 전체 권한
  3. Jenkins 등록: Manage Jenkins → Credentials → Secret text 타입으로 저장

Tip: 실서비스 환경이라면 토큰 만료일을 설정하고, 달력에 갱신 일을 기록해두세요.
만료되는 순간 배포가 멈춥니다!


4. Jenkins 파이프라인

가장 핵심인 Jenkinsfile입니다. PR 시에는 테스트만, Merge시에는 배포까지 수행하는 로직입니다.

pipeline {
    agent any
    environment {
        DOCKER_REGISTRY = "your-repo.com"
        APP_NAME = "smartcampus"
    }
    
    stages {
        stage('1. Checkout') {
            steps { checkout scm }
        }

        stage('2. Build & Test') {
            parallel { // 멀티 모듈 병렬 테스트로 시간 단축
                stage('Test API') {
                    steps { dir('backend/market-api') { sh './gradlew clean test' } }
                }
                stage('Test Chat') {
                    steps { dir('backend/market-chat') { sh './gradlew clean test' } }
                }
            }
        }

        stage('3. Dockerize & Push') {
            when { branch 'develop' } // develop 브랜치 Merge 시에만 실행
            steps {
                script {
                    def services = ['market-api', 'market-chat']
                    services.each { svc ->
                        dir("backend/${svc}") {
                            sh "./gradlew bootJar"
                            sh "docker build -t ${DOCKER_REGISTRY}/${APP_NAME}-${svc}:${env.BUILD_NUMBER} ."
                            sh "docker push ${DOCKER_REGISTRY}/${APP_NAME}-${svc}:${env.BUILD_NUMBER}"
                        }
                    }
                }
            }
        }

        stage('4. Deploy to K8s') {
            when { branch 'develop' }
            steps {
                // kubectl set image를 통한 롤링 업데이트
                sh "kubectl set image deployment/market-api api=${DOCKER_REGISTRY}/${APP_NAME}-market-api:${env.BUILD_NUMBER} -n dev"
                sh "kubectl rollout status deployment/market-api -n dev"
            }
        }
    }
}

5. Kubernetes 배포 전략

실서비스에서는 kubectl apply를 일일이 하기보다, 환경별 설정을 관리하기 쉬운 Kustomize를 권장합니다.

  • base/deployment.yaml: 공통 리소스 정의
  • overlays/dev/kustomization.yaml: 개발 환경용 이미지 태그 및 환경 변수 오버라이드
# resources 설정 예시 (실서비스 필수)
resources:
  requests:
    memory: "512Mi"
    cpu: "200m"
  limits:
    memory: "1Gi"
    cpu: "500m"

6. 한 끝 차이

  1. Branch Protection Rule: GitHub 설정에서 Require status checks to pass before merging을 켜세요.
    Jenkins 테스트가 실패하면 Merge 버튼이 비활성화됩니다.
  2. Graceful Shutdown: Kubernetes 배포 시 Pod가 갑자기 죽지 않도록 Spring Boot에 server.shutdown: graceful 설정을 반드시 추가하세요.
  3. Secret 관리: application.yml의 DB 비번 등은 절대 Git에 올리지 말고, Kubernetes Secret이나 Vault를 연동하세요.

적용 체크리스트

  • .github 폴더 내 템플릿 배치 완료
  • Jenkins-GitHub Webhook 연결 (Push 이벤트 수신 확인)
  • Jenkinsfile 내 작업 디렉토리(dir()) 경로 확인
  • Docker Registry 접근 권한 확인
  • K8s Namespace 생성 및 kubectl 권한 확인

마무리하며

이렇게 구축된 CI/CD는 개발자가 코드에만 집중할 수 있게 해줍니다.
처음엔 복잡해 보여도 한 번 구축해두면 "코드 Push -> 자동 테스트 -> 자동 배포"라는 쾌적한 개발 환경을 누릴 수 있습니다.

profile
그냥 코딩할래요 재미있어요

0개의 댓글