Jenkins Dev 파이프라인
develop 브랜치 푸시 시 Jenkins가 자동으로 빌드하고 K8s dev namespace에 배포합니다.
Jenkins 접속
| 항목 | 값 |
|---|---|
| URL | 사내 Jenkins 서버 (VPN 필요) |
| 뷰 | InfoLineage |
| Job 목록 | infolineage-platform-api, infolineage-platform-worker, infolineage-platform-frontend |
| Credentials | harbor (Harbor 레지스트리 로그인) |
Jenkinsfile 위치
infra/jenkins/
├── Jenkinsfile.api
├── Jenkinsfile.worker
└── Jenkinsfile.frontend
각 Job의 Pipeline 설정에서 SCM → 해당 Jenkinsfile 경로를 지정합니다.
podTemplate 패턴
모든 Jenkinsfile은 Kubernetes podTemplate을 사용합니다. 빌드 Pod에 컨테이너를 여러 개 묶어 단계별로 실행합니다.
podTemplate(
label: label,
containers: [
containerTemplate(name: 'java', image: 'eclipse-temurin:25-jre', ...),
containerTemplate(name: 'docker', image: 'docker:20.10', privileged: true, ...),
containerTemplate(name: 'kubectl', image: 'lachlanevenson/k8s-kubectl', ...),
],
volumes: [
hostPathVolume(hostPath: '/var/run/docker.sock', mountPath: '/var/run/docker.sock'),
]
)
| 컨테이너 | 역할 | 이미지 |
|---|---|---|
java | Gradle 빌드 | eclipse-temurin:25-jre (API), eclipse-temurin:25 (Worker) |
docker | 이미지 빌드 & Harbor 푸시 | docker:20.10 |
kubectl | K8s 배포 | lachlanevenson/k8s-kubectl |
API Job은
nodeSelector: jenkins.kubernetes.io/dedicated=true를 추가로 지정합니다.
파이프라인 단계
1단계: Git Pull
stage('Git Pull') {
checkout scm
}
2단계: Check Changed Paths
git diff HEAD~1 HEAD로 변경된 파일 목록을 확인합니다.
SKIP_BUILD 조건
| Job | SKIP_BUILD=true (건너뛰기) |
|---|---|
| API | backend/infolineage-api 및 backend/infolineage-common 변경 없음 |
| Worker | backend/infolineage-worker 및 backend/infolineage-common 변경 없음 |
| Frontend | frontend/ 변경 없음 |
SKIP_BUILD=true이면 Gradle Build와 Docker Build를 건너뜁니다. K8s Deploy는 항상 실행됩니다.
3단계: Gradle Build (API / Worker)
./gradlew :infolineage-api:bootJar \
-x test \
--build-cache \
-Dorg.gradle.jvmargs="--enable-preview -Xmx1g"
--build-cache 옵션으로 캐시를 활용해 증분 빌드를 수행합니다. Frontend는 Docker 멀티스테이지 빌드로 처리하므로 별도 Gradle 단계가 없습니다.
4단계: Docker Build & Push
docker login scr.softcamp.co.kr -u $HARBOR_USR --password-stdin
# API / Worker
docker build -f backend/<module>/Dockerfile -t <IMAGE> backend/
# Frontend
docker build -f frontend/Dockerfile \
--build-arg VITE_USE_MOCKS=false \
--build-arg VITE_API_BASE_URL=/platform/api \
--build-arg VITE_AUTH_DISABLED=false \
--build-arg VITE_SHIELD_ID_BASE_URL=https://devlogin.softcamp.co.kr \
--build-arg VITE_CLIENT_NAME=InfoLineage \
-t <IMAGE> frontend/
docker push <IMAGE>
docker rmi <IMAGE> || true
이미지 태그는 항상 :latest를 사용합니다.
5단계: K8s Deploy
# API / Worker
kubectl apply -f infra/k8s/dev/configmap.yaml -n dev
kubectl apply -f infra/k8s/dev/secret.yaml -n dev
kubectl apply -f infra/k8s/dev/<module>-service.yaml -n dev
kubectl apply -f infra/k8s/dev/<module>-deployment.yaml -n dev
kubectl rollout restart deployment/infolineage-platform-<module> -n dev
kubectl rollout status deployment/infolineage-platform-<module> -n dev --timeout=120s
특정 브랜치 선택 빌드
Jenkins Job 설정 → Branch Specifier를 수정하여 특정 브랜치를 대상으로 빌드합니다.
*/develop # 기본값
*/feature/api-* # feature 브랜치 패턴
수동 빌드 시 Build with Parameters → Branch 입력으로 원하는 브랜치를 지정할 수 있습니다.
트러블슈팅
containerCap 초과로 Pod 생성 실패
Jenkins Kubernetes 플러그인 설정에서 containerCap 값이 낮으면 Pod 생성이 실패합니다.
# 증상
ERROR: Error allocating a new node ... containerCap exceeded
해결: Jenkins 관리 → Clouds → Kubernetes → Container Cap 값 상향 (기본 10 → 50 이상).
이전 빌드 Pod가 Pending/Running으로 남아 있는 경우
# 정리
kubectl get pods -n jenkins | grep infolineage
kubectl delete pod <stuck-pod-name> -n jenkins
git diff HEAD~1 HEAD 실패 (첫 커밋)
최초 커밋이거나 shallow clone인 경우 HEAD~1을 참조할 수 없어 SKIP_BUILD 판단이 실패합니다. Jenkinsfile은 || git diff --name-only HEAD로 폴백합니다.