
혼자 하는 프로젝트라도 실서비스를 목표로 한다면 "어제 내가 뭘 했지?" 혹은 "이 코드가 운영 서버를 터뜨리진 않을까?" 하는 불안함에서 벗어나야 합니다.
이번 포스팅에서는 GitHub Actions 없이 Jenkins만 활용하여, SmartCampus와 같은 멀티 모듈 프로젝트(market-api, market-chat 등)의 Issue 관리부터 Kubernetes 배포까지 한 줄기 흐름으로 자동화하는 방법을 정리하였습니다.
SmartCampus는 하나의 레포지토리에 여러 백엔드 서비스가 포함된 멀티 모듈 구조입니다. 각 모듈의 독립성을 유지하면서 CI/CD를 통합 관리하는 것이 핵심입니다.
| 모듈명 | 주요 역할 | 포트 |
|---|---|---|
| market-api | 메인 서비스 (상품/회원/쿠폰 등) | 8080 |
| market-chat | AI 채팅 & RAG (벡터 스토어 연동) | 8082 |
| market-batch | 배치 작업 (정산/메일링) | 8081 |
| frontend | 프론트화면 | 80 |
팀 프로젝트는 물론 1인 프로젝트에서도 "정해진 규격"은 필수입니다.
.github 폴더를 통해 이슈와 PR 생성을 규격화합니다.
이전의 텍스트 방식보다 직관적인 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
PR은 "무엇을 고쳤는가"와 "테스트를 했는가"를 증명하는 서류입니다.
.github/PULL_REQUEST_TEMPLATE.md## 🔗 관련 이슈
- Closes #
## 📝 변경 사항
- [ ] 기능 추가:
- [ ] 버그 수정:
- [ ] 리팩토링:
## 🛠 체크리스트
- [ ] Local Test 완료 (`./gradlew test`)
- [ ] Jenkins CI 통과 후 Merge 예정
- [ ] 환경 변수(Secret) 변경 여부
Jenkins가 내 저장소를 감시하고 상태를 업데이트하려면 Personal Access Token이 필요합니다.
repo 전체 권한Tip: 실서비스 환경이라면 토큰 만료일을 설정하고, 달력에 갱신 일을 기록해두세요.
만료되는 순간 배포가 멈춥니다!
가장 핵심인 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"
}
}
}
}
실서비스에서는 kubectl apply를 일일이 하기보다, 환경별 설정을 관리하기 쉬운 Kustomize를 권장합니다.
# resources 설정 예시 (실서비스 필수)
resources:
requests:
memory: "512Mi"
cpu: "200m"
limits:
memory: "1Gi"
cpu: "500m"
Require status checks to pass before merging을 켜세요.server.shutdown: graceful 설정을 반드시 추가하세요.application.yml의 DB 비번 등은 절대 Git에 올리지 말고, Kubernetes Secret이나 Vault를 연동하세요..github 폴더 내 템플릿 배치 완료Jenkinsfile 내 작업 디렉토리(dir()) 경로 확인kubectl 권한 확인이렇게 구축된 CI/CD는 개발자가 코드에만 집중할 수 있게 해줍니다.
처음엔 복잡해 보여도 한 번 구축해두면 "코드 Push -> 자동 테스트 -> 자동 배포"라는 쾌적한 개발 환경을 누릴 수 있습니다.