☰ Categories

CI/CD Strategy for SpringBoot REST APIs Deployment

a DevOps Consultant. You are an expert in CI/CD processes and Kubernetes deployments, specializing in SpringBoot applications.

CategoryDevelopment › Deploy & operations
TagsAnalyzingDraftingDeveloperCode
Prompt
Act as a DevOps Consultant. You are an expert in CI/CD processes and Kubernetes deployments, specializing in SpringBoot applications.

Your task is to provide guidance on setting up a CI/CD pipeline using CloudBees Jenkins to deploy multiple SpringBoot REST APIs stored in a monorepo. Each API, such as notesAPI, claimsAPI, and documentsAPI, will be independently deployed as Docker images to Kubernetes, triggered by specific tags.

You will:
- Design a tagging strategy where a NOTE tag triggers the NoteAPI pipeline, a CLAIM tag triggers the ClaimsAPI pipeline, and so on.
- Explain how to implement Blue-Green deployment for each API to ensure zero-downtime during updates.
- Provide steps for building Docker images, pushing them to Artifactory, and deploying them to Kubernetes.
- Ensure that changes to one API do not affect the others, maintaining isolation in the deployment process.

Rules:
- Focus on scalability and maintainability of the CI/CD pipeline.
- Consider long-term feasibility and potential challenges, such as tag management and pipeline complexity.
- Offer solutions or best practices for handling common issues in such setups.

What this prompt does

This prompt assigns a DevOps Consultant role for deploying SpringBoot REST APIs with CloudBees Jenkins and Kubernetes. It covers per-API isolation, Blue-Green deployment, and tag-management complexity.

Model comparison

ChatGPT is the most complete but has an image-tagging error, while Gemini is practical yet flawed in its deployment example. Claude shows strong design quality but is heavily penalized because it is truncated.

ChatGPT
40/ 50

+ Covers isolation, zero downtime, rollback, and long-term operations.

- It incorrectly uses slash-containing Git tags as Docker tags.

Gemini
40/ 50

+ Connects the overall workflow with practical examples clearly.

- Preview-slot and service-port errors can break the smoke test.

Claude
29/ 50

+ Provides a concrete config-driven design and image promotion strategy.

- The deployment code is truncated, leaving the core implementation incomplete.

CriterionChatGPTClaudeGeminiLeader
Instruction following959Tie
Accuracy776Tie
Specificity999Tie
Structure959Tie
Right length637Gemini +17%

Scored 1–10 by gpt-5.6-sol with model names hidden (2026-09-25). This is an AI review, not a measurement.

Read full answers

We gave three models the same input and copied their answers unedited. Each ran in its CLI (an agent harness), and answers in the ChatGPT or Claude apps or on the web may differ. Outputs are in Korean.

gpt-5.6-luna (codex CLI · 에이전트 하네스) · Run on 2026-09-24

CloudBees Jenkins 기반 CI/CD 설계

모노레포 안에 여러 SpringBoot REST API가 존재한다고 가정합니다.

repo/
├── notesAPI/
├── claimsAPI/
├── documentsAPI/
├── deploy/
│   ├── notes/
│   ├── claims/
│   └── documents/
└── Jenkinsfile

각 API는 독립적인 Docker 이미지와 Kubernetes Deployment로 관리합니다.

1. 태그 전략

단순히 NOTE, CLAIM 같은 고정 태그를 사용하는 것보다 서비스명과 버전을 포함하는 불변 태그를 권장합니다.

notes-v1.4.0
claims-v2.1.3
documents-v1.0.7

또는 요청한 접두어를 유지하려면 다음 형식을 사용할 수 있습니다.

NOTE/v1.4.0
CLAIM/v2.1.3
DOCUMENT/v1.0.7

태그 규칙:

  • NOTE/v1.4.0 → notesAPI 파이프라인 실행
  • CLAIM/v2.1.3 → claimsAPI 파이프라인 실행
  • DOCUMENT/v1.0.7 → documentsAPI 파이프라인 실행
  • 태그는 Git annotated tag 및 가능하면 서명된 태그 사용
  • 이미 생성된 릴리스 태그는 변경하거나 재사용하지 않음
  • 이미지 태그는 Git 태그와 동일하게 유지
  • latest, stable 같은 가변 태그는 배포 기준으로 사용하지 않음

예시:

git tag -a NOTE/v1.4.0 -m "Release notesAPI v1.4.0"
git push origin NOTE/v1.4.0

CloudBees Jenkins에서는 Git webhook으로 태그 생성 이벤트를 받고, 각 파이프라인이 자신의 태그 패턴만 처리하도록 구성합니다.

2. 파이프라인 분리 방식

가장 유지보수하기 좋은 방식은 API별 Jenkins Pipeline Job을 별도로 구성하는 것입니다.

notesAPI-pipeline
claimsAPI-pipeline
documentsAPI-pipeline

각 Job의 태그 필터:

notesAPI-pipeline      → NOTE/.*
claimsAPI-pipeline     → CLAIM/.*
documentsAPI-pipeline  → DOCUMENT/.*

모노레포의 공통 Jenkinsfile을 사용하되, 파이프라인 실행 시 서비스명을 파라미터로 전달할 수 있습니다.

pipeline {
    agent { label 'docker-k8s-builder' }

    parameters {
        string(name: 'SERVICE_NAME')
        string(name: 'TAG_NAME')
    }

    environment {
        REGISTRY = 'artifactory.example.com/docker-release'
    }

    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        stage('Validate Tag') {
            steps {
                sh '''
                  case "$TAG_NAME" in
                    NOTE/*)     test "$SERVICE_NAME" = "notesAPI" ;;
                    CLAIM/*)    test "$SERVICE_NAME" = "claimsAPI" ;;
                    DOCUMENT/*) test "$SERVICE_NAME" = "documentsAPI" ;;
                    *) exit 1 ;;
                  esac
                '''
            }
        }

        stage('Test') {
            steps {
                sh "./gradlew :${SERVICE_NAME}:test"
            }
        }

        stage('Build Image') {
            steps {
                sh """
                  docker build \
                    -f ${SERVICE_NAME}/Dockerfile \
                    -t ${REGISTRY}/${SERVICE_NAME}:${TAG_NAME} \
                    ${SERVICE_NAME}
                """
            }
        }

        stage('Push Image') {
            steps {
                withCredentials([usernamePassword(
                    credentialsId: 'artifactory-docker',
                    usernameVariable: 'ART_USER',
                    passwordVariable: 'ART_PASSWORD'
                )]) {
                    sh """
                      echo "$ART_PASSWORD" | docker login ${REGISTRY} \
                        -u "$ART_USER" --password-stdin

                      docker push ${REGISTRY}/${SERVICE_NAME}:${TAG_NAME}
                    """
                }
            }
        }

        stage('Deploy') {
            steps {
                sh "./deploy/deploy.sh ${SERVICE_NAME} ${TAG_NAME}"
            }
        }
    }
}

실제 운영에서는 Docker socket을 Jenkins Agent에 직접 연결하기보다 다음을 고려하는 것이 좋습니다.

  • Kaniko
  • BuildKit
  • Cloud Native Buildpacks
  • Kubernetes 기반 ephemeral agent
  • 이미지 서명 및 SBOM 생성

3. 변경 범위 검증

태그가 생성되었다고 해서 항상 해당 API를 빌드하도록 두지 말고, 태그와 소스 변경 경로를 검증하는 것이 좋습니다.

예를 들어 NOTE/v1.4.0 태그라면 다음 조건을 확인합니다.

notesAPI/**
공통 라이브러리 변경
루트 build.gradle 또는 settings.gradle 변경
공통 Docker 설정 변경

그 외 claimsAPI/**만 변경된 상태에서 NOTE/v1.4.0 태그가 생성되면 파이프라인을 실패시키거나 승인을 요구합니다.

다만 태그는 특정 커밋을 가리키므로, 기준은 “태그 생성 이후 변경”이 아니라 “태그가 가리키는 커밋의 변경 파일”이어야 합니다.

예시 검증 로직:

git diff-tree --no-commit-id --name-only -r "$TAG_NAME"

공통 모듈을 사용하는 경우에는 다음 매핑 파일을 관리할 수 있습니다.

services:
  notesAPI:
    paths:
      - notesAPI/**
      - common/**
      - build.gradle
  claimsAPI:
    paths:
      - claimsAPI/**
      - common/**
      - build.gradle

이렇게 하면 한 API의 배포가 다른 API의 Docker 이미지나 Kubernetes 리소스를 변경하지 않습니다.

4. Docker 이미지 빌드 및 Artifactory Push

각 API는 자체 Dockerfile을 갖습니다.

FROM eclipse-temurin:21-jre

WORKDIR /app
COPY build/libs/notesAPI.jar app.jar

USER 10001

ENTRYPOINT ["java", "-jar", "/app/app.jar"]

권장 이미지 이름:

artifactory.example.com/docker-release/notesAPI:NOTE-v1.4.0
artifactory.example.com/docker-release/claimsAPI:CLAIM-v2.1.3
artifactory.example.com/docker-release/documentsAPI:DOCUMENT-v1.0.7

빌드 단계에서 수행할 작업:

  1. 해당 API의 단위 테스트 실행
  2. 정적 분석 및 취약점 검사
  3. SpringBoot JAR 생성
  4. Docker 이미지 생성
  5. 이미지 취약점 검사
  6. SBOM 생성
  7. Artifactory Push
  8. 이미지 digest 기록
  9. Kubernetes 배포

운영 배포 시에는 태그보다 digest를 최종 기준으로 사용하는 것이 안전합니다.

notesAPI@sha256:abc123...

Jenkins가 Push 직후 digest를 조회하고 Kubernetes에는 다음처럼 전달합니다.

kubectl -n production set image deployment/notes-api-green \
  notes-api=artifactory.example.com/docker-release/notesAPI@sha256:abc123

5. Kubernetes Blue-Green 배포

각 API마다 Blue와 Green Deployment를 별도로 둡니다.

notes-api-blue
notes-api-green
claims-api-blue
claims-api-green
documents-api-blue
documents-api-green

트래픽은 하나의 Service가 선택된 색상으로만 전달하도록 구성합니다.

apiVersion: v1
kind: Service
metadata:
  name: notes-api
spec:
  selector:
    app: notes-api
    version: blue
  ports:
    - port: 80
      targetPort: 8080

Blue Deployment:

metadata:
  name: notes-api-blue
spec:
  replicas: 3
  selector:
    matchLabels:
      app: notes-api
      version: blue
  template:
    metadata:
      labels:
        app: notes-api
        version: blue
    spec:
      containers:
        - name: notes-api
          image: artifactory.example.com/docker-release/notesAPI:NOTE-v1.3.0
          ports:
            - containerPort: 8080
          readinessProbe:
            httpGet:
              path: /actuator/health/readiness
              port: 8080
          livenessProbe:
            httpGet:
              path: /actuator/health/liveness
              port: 8080

Green에는 새 이미지가 배포됩니다.

배포 절차:

  1. 현재 활성 색상 확인
  2. 비활성 색상의 Deployment에 새 이미지 적용
  3. 비활성 색상의 Pod 기동 대기
  4. readiness 및 애플리케이션 smoke test 실행
  5. 내부 Service 또는 테스트 Ingress로 검증
  6. Service selector를 새 색상으로 변경
  7. 일정 시간 모니터링
  8. 문제가 없으면 이전 색상 유지 또는 축소
  9. 문제가 있으면 Service selector를 이전 색상으로 복구

예시:

kubectl -n production apply -f deploy/notes/green.yaml

kubectl -n production rollout status \
  deployment/notes-api-green --timeout=5m

curl --fail https://notes-api-green.internal/actuator/health

kubectl -n production patch service notes-api \
  -p '{"spec":{"selector":{"app":"notes-api","version":"green"}}}'

Blue-Green의 핵심은 이미지 교체와 트래픽 전환을 분리하는 것입니다. 새 Pod가 정상인지 확인하기 전에는 Service selector를 변경하지 않습니다.

6. SpringBoot 애플리케이션 설정

무중단 배포를 위해 다음 설정을 권장합니다.

management:
  endpoint:
    health:
      probes:
        enabled: true

server:
  shutdown: graceful

spring:
  lifecycle:
    timeout-per-shutdown-phase: 30s

추가 권장 사항:

  • /actuator/health/readiness와 /actuator/health/liveness 분리
  • readiness 실패 시 새 요청을 받지 않도록 구성
  • terminationGracePeriodSeconds 설정
  • preStop hook으로 연결 종료 시간 확보
  • 애플리케이션이 세션을 로컬 메모리에 저장하지 않도록 설계
  • 파일 업로드나 임시 파일은 외부 스토리지 사용
  • 외부 의존성 장애 시 readiness 정책을 명확히 정의

7. 데이터베이스 마이그레이션 주의사항

Blue-Green 배포에서 가장 자주 문제가 되는 부분은 데이터베이스 스키마입니다.

새 버전과 이전 버전이 잠시 동시에 실행되므로, 마이그레이션은 다음 방식으로 진행해야 합니다.

  1. 하위 호환 가능한 컬럼 또는 테이블 추가
  2. 애플리케이션 배포
  3. 신규 코드가 새 구조를 사용하도록 전환
  4. 충분한 안정화 후 기존 컬럼 제거

Flyway 또는 Liquibase를 사용하되, 삭제·이름 변경처럼 즉시 호환성을 깨는 마이그레이션은 피해야 합니다.

8. 장애 시 롤백

롤백은 Kubernetes Deployment의 이전 ReplicaSet으로 되돌리는 것보다 Service selector를 이전 색상으로 복구하는 방식이 빠르고 명확합니다.

kubectl -n production patch service notes-api \
  -p '{"spec":{"selector":{"app":"notes-api","version":"blue"}}}'

롤백 조건은 사전에 정의합니다.

  • readiness 실패
  • HTTP 5xx 증가
  • latency 증가
  • 주요 smoke test 실패
  • 로그 오류율 증가
  • Prometheus 알림 발생

Blue-Green 유지 시간을 정해 두고, 예를 들어 30분 동안 문제가 없을 때만 이전 색상을 축소합니다.

9. 보안 및 운영 권장사항

CloudBees Jenkins와 Kubernetes 사이에는 최소 권한 원칙을 적용합니다.

  • API별 Kubernetes ServiceAccount 사용
  • Namespace별 Role 및 RoleBinding 사용
  • Jenkins에 cluster-admin 권한 부여 금지
  • Artifactory credential은 Jenkins Credentials에 저장
  • Secret을 Git에 저장하지 않음
  • 이미지 서명 및 검증 적용
  • Trivy, Xray 등으로 이미지 취약점 검사
  • 배포 이력과 이미지 digest를 감사 로그에 기록
  • 운영 배포에는 승인 단계 추가

예를 들어 개발·스테이징은 자동 배포하고, 운영은 다음 조건을 요구할 수 있습니다.

테스트 통과
이미지 취약점 기준 통과
변경 승인 완료
운영 배포 승인

10. 장기적인 유지보수 전략

API 수가 증가하면 서비스별 Jenkinsfile을 복사하는 방식은 복잡해집니다. 다음 구조가 적합합니다.

shared-library/
├── vars/
│   └── springBootServicePipeline.groovy
└── src/

각 Job은 서비스명과 태그 패턴만 선언합니다.

springBootServicePipeline(
    serviceName: 'notesAPI',
    tagPattern: 'NOTE/*',
    namespace: 'production',
    deployment: 'notes-api'
)

또는 서비스 정의 파일을 중앙에서 관리합니다.

services:
  notesAPI:
    tagPrefix: NOTE
    imageRepository: docker-release/notesAPI
    deployment: notes-api
    namespace: production

  claimsAPI:
    tagPrefix: CLAIM
    imageRepository: docker-release/claimsAPI
    deployment: claims-api
    namespace: production

서비스 수가 많아지면 Jenkins가 Kubernetes manifest를 직접 문자열로 조작하기보다 다음 중 하나를 사용하는 편이 좋습니다.

  • Helm
  • Kustomize
  • Argo CD 또는 Flux 기반 GitOps
  • CloudBees CI의 공통 Pipeline Library

특히 운영 규모가 커지면 Jenkins는 테스트와 이미지 빌드까지만 수행하고, 배포는 GitOps 도구에 맡기는 구조가 관리하기 쉽습니다.

Git Tag
  ↓
CloudBees Jenkins
  ↓
테스트 · 이미지 빌드 · Artifactory Push
  ↓
배포 리포지토리 이미지 digest 변경
  ↓
Argo CD / Flux
  ↓
Kubernetes Blue-Green 배포

권장 최종 구조

NOTE/v1.4.0 생성
        ↓
notesAPI Jenkins Pipeline만 실행
        ↓
notesAPI 테스트 및 이미지 빌드
        ↓
Artifactory Push
        ↓
notes-api-green 배포
        ↓
readiness 및 smoke test
        ↓
notes-api Service를 green으로 전환

이 구조에서는 claimsAPI와 documentsAPI의 이미지, Deployment, Service가 변경되지 않으므로 API별 배포 격리가 보장됩니다. 핵심은 서비스별 태그 규칙, 불변 이미지 식별자, 별도 Kubernetes 리소스, 그리고 트래픽 전환 전 검증입니다.

More in this category

AI Agent Architect — Design Production-Ready Agents in 15 Steps
AI Agent Security Evaluation Checklist
AI Provider Research Expert
AI Trying to Escape the Box
Analyze code scanning security issues and dependency updates if vulnerable