[CI/CD] Jenkins로 처음 구축해본 CI/CD 파이프라인3

2026. 3. 27. 19:23·Infra
더보기

인프런-애플리케이션 배포 자동화와 CI/CD 강의를 듣고 작성된 글입니다.

CI/CD는 왜 필요할까?

CI/CD가 없던 시절에는 개발자가 직접 빌드와 배포를 진행했다.

코드 수정
↓
직접 빌드
↓
직접 서버 접속
↓
파일 복사
↓
직접 실행

하지만 프로젝트 규모가 커지고 개발자가 많아질수록 여러 문제가 발생한다.

  • 배포 과정이 사람마다 달라질 수 있다.
  • 테스트 없이 배포가 진행될 수 있다.
  • 반복 작업으로 인해 실수가 발생할 수 있다.
  • 장애 발생 시 원인 추적이 어려워진다.

CI/CD는 이러한 반복 작업을 자동화하고 사람이 실수할 수 있는 부분을 줄이기 위해 등장했다.

CI (Continuous Integration)

CI는 지속적 통합(Continuous Integration)을 의미한다.

여기서 통합이란 개발자가 작업한 코드를 메인 브랜치에 병합하는 과정을 말한다. 예를 들어 여러 개발자가 각자의 브랜치에서 기능을 개발하고 있다고 가정해보자.

feature/login
feature/payment
feature/order
        ↓
       main

각 브랜치의 코드를 메인 브랜치에 병합하기 전에 테스트를 수행하여 기존 기능이 정상적으로 동작하는지 확인한다.

테스트가 실패하면 병합을 막고, 테스트가 성공하면 메인 브랜치로 병합한다.

즉, CI의 핵심은 다음과 같다.

새로운 코드가 지속적으로 통합되더라도 기존 기능은 계속 정상적으로 동작해야 한다.

 

CI는 단순히 테스트가 아니다

CI를 테스트 자동화라고 생각하는 경우가 많지만, 정확히는 코드 통합 과정을 자동화하는 것이다. 일반적으로 CI 파이프라인은 다음과 같은 과정을 수행한다.

코드 통합
↓
빌드
↓
테스트
↓
품질 검사

테스트뿐만 아니라 다음과 같은 작업도 함께 수행할 수 있다.

  • Unit Test
  • Integration Test
  • 정적 분석(SonarQube)
  • 코드 스타일 검사(Lint)
  • 보안 취약점 검사
  • 빌드 검증

즉, CI는 테스트만 수행하는 것이 아니라 코드가 메인 브랜치에 통합될 수 있는 상태인지 검증하는 과정이라고 볼 수 있다.

CI 테스트는 언제 실행될까?

1. Push 시점

개발자가 코드를 Push하면 자동으로 테스트를 수행한다.

Developer
    ↓ Push
GitHub
    ↓
CI Test

2. Pull Request 생성 시

PR(Pull Request)을 생성하면 병합 전에 테스트를 수행한다.

Feature Branch
       ↓
      PR
       ↓
   CI Test

3. Merge 후

메인 브랜치에 병합된 이후에도 테스트를 수행할 수 있다. 병합 과정에서 예상하지 못한 문제가 발생할 수 있기 때문이다.

 

4. 배포 시작 전

실제 배포 직전에 한 번 더 테스트를 수행하기도 한다.

테스트가 실패하면 배포를 중단하여 문제가 있는 버전이 운영 환경으로 나가는 것을 방지할 수 있다.

 

Jenkins Pipeline

Jenkins Pipeline에서는 CI 과정을 stage 단위로 나누어 작성할 수 있다. 위 예시는 GitHub에서 코드를 가져오는 Checkout, 애플리케이션을 빌드하는 Build, 테스트 코드를 실행하는 Test 단계로 구성되어 있다.

pipeline {
    agent any

    stages {
        stage('Checkout') {
            steps {
                git url: 'https://github.com/lleellee0/deploy-test', branch: 'main'
            }
        }

        stage('Build') {
            steps {
                script {
                    echo 'Building the project...'
                    sh 'mvn clean package'
                }
            }
        }

        stage('Test') {
            steps {
                script {
                    echo 'Running tests...'
                    sh 'mvn test'
                }
            }
        }
    }
}

CI 테스트는 왜 빨라야 할까?

CI 테스트가 너무 오래 걸리면 개발 속도가 느려진다. 예를 들어 코드 한 줄 수정할 때마다 테스트에 30분이 걸린다면 개발자는 결과를 확인하기 위해 계속 기다려야 한다.

그래서 실무에서는 테스트 시간을 줄이기 위해 다양한 방법을 사용한다.

  • 테스트 병렬 실행
  • 필요한 테스트만 실행
  • Spring Context 최소화
  • Mock 사용
  • 애플리케이션 전체 기동 없이 테스트 수행

테스트의 신뢰성도 중요하지만, 빠른 피드백 역시 매우 중요하기 때문이다.

 

CD (Continuous Delivery / Continuous Deployment)

CD는 보통 지속적 배포라고 번역되지만 사실 두 가지 의미로 사용된다.

Continuous Delivery

배포 직전 단계까지 자동화하는 방식이다.

코드 Push
↓
CI
↓
Build
↓
배포 준비 완료
↓
운영자 승인
↓
배포

최종 배포는 사람이 직접 수행한다.

Continuous Deployment

배포까지 완전히 자동화하는 방식이다.

코드 Push
↓
CI
↓
Build
↓
Deploy
↓
운영 반영

모든 과정이 자동으로 진행된다.

CD 테스트

CD 단계에서는 단순히 애플리케이션이 실행되는지만 확인하지 않는다. 실제 운영 환경에서도 정상적으로 동작하는지 검증해야 한다.

코드에는 문제가 없지만 서버 환경 때문에 장애가 발생하는 경우도 많다.

대표적인 예시는 다음과 같다.

 

1. 인증 토큰 만료

외부 API 호출에 사용하는 토큰이 만료된 경우

 

2. 방화벽 설정 문제

특정 포트가 차단되어 통신이 불가능한 경우

 

3. 네트워크 장애

외부 시스템과 연결되지 않는 경우

 

4. 저장소 장애

DB 또는 Redis 연결에 실패하는 경우

 

즉,

  • CI는 "코드가 정상인가?"
  • CD는 "실제 운영 환경에서도 정상 동작하는가?"

를 검증하는 과정이라고 볼 수 있다.

 

롤백

배포가 성공했다고 해서 항상 서비스가 정상 동작하는 것은 아니다. 예를 들어, 애플리케이션은 정상적으로 실행되었지만 특정 기능이 동작하지 않거나 외부 시스템 연동에 문제가 발생할 수 있다.

 

이때 중요한 것이 롤백(Rollback)이다. 롤백은 문제가 발생한 버전을 제거하고 이전에 정상 동작하던 버전으로 되돌리는 작업을 의미한다.

강의에서는 배포 전에 기존 JAR 파일을 백업해두고, CD 테스트 실패 시 해당 파일로 복구하는 방식을 사용하였다.

def deployAndTest(serverIp) {
	// CD 테스트 수행
    int cdTestResult = sh script: "curl -s -o /dev/null -w '%{http_code}' http://$serverIp/ui/create-shortenurl.html", returnStatus: true
    if (cdTestResult != 200) {
        echo "CD test failed for $serverIp. Rolling back to previous version."
        rollbackToPreviousVersion(serverIp, backupJarFile, deployPath, runAppCommand, checkLogCommand)
        error "Deployment to $serverIp failed due to CD test failure."
    } else {
        echo "CD test passed for $serverIp."
    }
}

def rollbackToPreviousVersion {
    // 백업된 JAR 파일로 롤백
    sshagent(['deploy_ssh_key']) {
        sh script: "ssh -o StrictHostKeyChecking=no root@$serverIp 'mv $deployPath/$backupJarFile $deployPath/shortenurlservice-0.0.1-SNAPSHOT.jar'", returnStatus: true
        sh "ssh -o StrictHostKeyChecking=no root@$serverIp '$runAppCommand'"

        // 로그 파일을 주기적으로 확인하여 애플리케이션 실행 확인
        def attempts = 0
        def rollbackSuccess = false
        while (attempts < maxAttempts) {
            int result = sh script: "ssh -o StrictHostKeyChecking=no root@$serverIp '$checkLogCommand'", returnStatus: true
            if (result == 0) {
                echo "Rollback to previous version on $serverIp was successful."
                rollbackSuccess = true
                break
            }
            attempts++
            sleep sleepInterval
        }

        if (!rollbackSuccess) {
            error "Rollback to previous version on $serverIp failed."
        }
    }
 }

배포 전략

서비스를 운영하는 환경에서는 단순히 배포하는 것뿐만 아니라 어떻게 배포할 것인지도 중요하다.

Rolling Deployment

서버를 한 대씩 순차적으로 교체하는 방식이다.

Server1 → 신규 버전
Server2 → 기존 버전
Server3 → 기존 버전

장점은 추가 서버 없이도 배포가 가능하다는 점이다.

하지만 배포가 진행되는 동안 여러 버전이 동시에 서비스될 수 있다.

Blue-Green Deployment

새로운 버전을 먼저 실행한 뒤 한 번에 트래픽을 전환하는 방식이다.

Blue (현재 운영)
Green (신규 버전)
         ↓
     정상 확인
         ↓
    트래픽 전환

보통 Nginx와 같은 리버스 프록시를 이용해 트래픽을 전환한다. 장점은 롤백이 쉽고 다운타임이 거의 없다는 것이다.

Canary Deployment

새로운 버전을 일부 사용자에게만 먼저 배포하는 방식이다.

기존 버전 90%
신규 버전 10%

문제가 없는지 확인하면서 점진적으로 비율을 늘려간다.

10%
↓
30%
↓
50%
↓
100%

대규모 서비스에서 자주 사용된다.

 

 

짧은 강의였지만 생각보다 많은 내용을 얻어갈 수 있었다. Jenkins가 어떤 방식으로 동작하는지, CI/CD는 무엇인지, 그리고 무중단 배포가 왜 필요한지에 대해 전체적인 흐름을 이해할 수 있었다.

지금은 실습 환경에서 따라 해보는 수준이었지만, 다음에는 직접 진행한 프로젝트에 Jenkins와 Nginx를 적용해보며 실제 배포 환경을 구축해볼 생각이다.

'Infra' 카테고리의 다른 글

[NGINX] Jenkins로 처음 구축해본 CI/CD 파이프라인2  (3) 2026.03.24
[Jenkins] Jenkins로 처음 구축해본 CI/CD 파이프라인1  (0) 2026.03.22
[k8s] 로컬로 쿠버네티스 구축하기 - minikube, kubectl  (0) 2026.03.08
[k8s] 쿠버네티스란?  (0) 2026.03.04
[AWS] Elastic Beanstalk로 FastAPI + Redis CRUD API 배포하기(2)  (1) 2025.06.07
'Infra' 카테고리의 다른 글
  • [NGINX] Jenkins로 처음 구축해본 CI/CD 파이프라인2
  • [Jenkins] Jenkins로 처음 구축해본 CI/CD 파이프라인1
  • [k8s] 로컬로 쿠버네티스 구축하기 - minikube, kubectl
  • [k8s] 쿠버네티스란?
지-토리
지-토리
  • 지-토리
    지토리의 개발이야기
    지-토리
  • 전체
    오늘
    어제
    • 분류 전체보기 (46)
      • [AND] 사용자 정의 지표 기반 실시감 감지 및.. (13)
        • 기획 (4)
        • 기술 (8)
      • [Linkompany] 뉴스와 공시를 통합 기업 .. (4)
      • [Candly] 차트 공부 및 예측 웹 프로젝트 (2)
      • JAVA (4)
        • 코딩테스트 (1)
      • 대규모 시스템 설계 (1)
      • Infra (12)
      • ELK (3)
      • AI (2)
      • FrontEnd (1)
      • TIP (2)
      • 자격증 (1)
  • 블로그 메뉴

    • 홈
    • Github
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    kdt교육
    부트캠프
    kpt
    쿠버네티스
    프디아
    인증/인가
    알파코
    Firebase
    프로디지털아카데미
    SpringSecurity
    인프런
    K8S
    EC2
    And
    알파코캠퍼스
    프로젝트
    Issue
    신한투자증권
    K디지털트레이닝
    신투
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
지-토리
[CI/CD] Jenkins로 처음 구축해본 CI/CD 파이프라인3
상단으로

티스토리툴바