본문 바로가기
CI.CD/Jenkins

[Jenkins] Maven / Gradle 빌드 캐시 최적화 (빌드 시간 10배 단축의 비밀)

반응형

"코드는 고작 한 줄 수정했는데, 젠킨스 빌드 시간은 무려 15분이나 걸린다?" 자바(Java/Spring Boot) 프로젝트나 Node.js 프로젝트의 파이프라인을 운영하다 보면 가장 많이 듣게 되는 불만 중 하나입니다. 코드를 컴파일하고 테스트하는 데 걸리는 시간은 1분도 안 되지만, 스프링 프레임워크와 수많은 서드파티 라이브러리(.jar 파일들)를 Maven Central이나 원격 저장소에서 다운로드하는 데 14분이 걸리기 때문입니다. 특히 앞서 우리가 칭송했던 'Docker Agent(1회용 멸균 빌드 환경)'를 사용할 경우, 이 문제는 최악의 형태로 발현됩니다. 컨테이너가 뜰 때마다 백지상태이므로 매 빌드마다 수백 메가바이트의 라이브러리를 인터넷에서 새로 받아와야 하니까요. 이번 [Jenkins 실무 완벽 가이드] 시리즈에서는 인프라 병목의 주범을 완벽하게 색출하고, 볼륨 마운트(Volume Mount)를 통한 무적의 빌드 캐시(Cache) 재활용 전략에 대하여 3,000자 분량으로 아주 치밀하게 딥다이브 해보겠습니다.

🚫 1. Docker Agent의 양날의 검 (멸균 환경의 저주)

9단계 포스팅에서 우리는 서버 환경 오염을 막기 위해 agent { docker { image 'maven:3.8-jdk-11' } } 처럼 컨테이너 기반으로 빌드하는 것을 Best Practice로 배웠습니다. 빌드가 끝나면 컨테이너는 rm(삭제) 되며 흔적 없이 사라집니다.

이것은 보안과 환경 격리 측면에서는 완벽하지만, '캐시(Cache)' 관점에서는 끔찍한 재앙입니다. Maven은 라이브러리를 다운받으면 컨테이너 내부의 /root/.m2/repository 경로에 저장해 둡니다. 그런데 빌드가 끝나고 컨테이너가 삭제되면? 기껏 받아놓은 라이브러리들도 함께 우주 미아가 되어 증발해 버립니다. 다음 빌드 때 새로운 컨테이너가 뜨면, Maven은 "어? 라이브러리가 하나도 없네?"라며 또다시 10분에 걸쳐 인터넷에서 다운로드를 시작합니다. 이른바 무한 다운로드의 저주에 빠지는 것입니다.


💾 2. 해결책: 볼륨 마운트(Volume Mount)를 통한 캐시 영속화

해결책은 의외로 간단합니다. 다운로드받은 라이브러리를 곧 삭제될 컨테이너 내부에 저장하지 말고, 젠킨스가 설치된 호스트 서버(물리 장비)의 안전한 디렉토리에 저장하도록 연결(Mount)해 주면 됩니다. 컨테이너가 삭제되더라도 호스트 서버에 저장된 .jar 파일들은 영원히 남아(영속화) 있게 됩니다. 다음번 빌드 때 새로 뜨는 컨테이너에게 "야, 인터넷에서 받지 말고 저기 호스트 서버 폴더에 있는 라이브러리들 그대로 가져다 써!"라고 다리를 놔주기만 하면 됩니다.

핵심 디렉토리 매핑 지식:

  • Maven (Java): 호스트 폴더 $HOME/.m2 ↔ 컨테이너 폴더 /root/.m2
  • Gradle (Java): 호스트 폴더 $HOME/.gradle ↔ 컨테이너 폴더 /home/gradle/.gradle
  • NPM (Node.js): 호스트 폴더 $HOME/.npm ↔ 컨테이너 폴더 /root/.npm

💻 3. 실무 적용 극한의 예제 파헤치기

이러한 볼륨 마운트는 파이프라인의 docker 블록 내부에 args 속성을 사용하여 도커 런(Docker Run) 파라미터를 강제로 주입함으로써 달성할 수 있습니다.

pipeline {
    agent {
        docker {
            // Java 17 환경의 Maven 공식 이미지 사용
            image 'maven:3.8.5-openjdk-17'
            
            // 🔥 실무 핵심 최적화 라인 🔥
            // -v 옵션으로 호스트의 ~/.m2 폴더와 컨테이너의 /root/.m2 폴더를 동기화(마운트)시킵니다.
            // 이렇게 하면 Maven이 다운받는 모든 파일이 호스트 서버의 디스크에 쌓이게 됩니다.
            args '-v $HOME/.m2:/root/.m2'
        }
    }
    stages {
        stage('Maven Build with Cache') {
            steps {
                echo '🚀 캐시가 적용된 초고속 빌드를 시작합니다...'
                
                // 첫 번째 빌드: 호스트 폴더가 비어있으므로 인터넷에서 다운로드함 (약 10분 소요)
                // 두 번째 빌드: 호스트 폴더에 이미 파일이 꽉 차있으므로 다운로드 스킵! (약 30초 컷)
                sh 'mvn clean package -DskipTests'
            }
        }
    }
}

💡 실무 꿀팁: 만약 Gradle을 쓴다면 args '-v $HOME/.gradle:/home/gradle/.gradle'로 변경해 주면 됩니다. 이렇게 단 한 줄의 args 속성을 추가하는 것만으로, 15분 걸리던 무거운 엔터프라이즈급 자바 프로젝트의 빌드 시간이 1분대로 드라마틱하게 단축되는 기적을 목격하실 수 있습니다.


🎯 4. 마무리 및 다음 단계

지금까지 Docker Agent 환경의 최대 단점인 '캐시 증발 현상'을 정확히 분석하고, 볼륨 마운트(Volume Mount)를 통해 다운로드 시간을 0에 가깝게 소거하는 극강의 빌드 캐시 최적화 기법에 대해 3,000자 분량으로 밀도 높게 다루어 보았습니다. 이제 개발자들은 커피 머신에 다녀오기도 전에 배포가 끝나는 쾌적한 CI/CD 속도에 감탄하며 인프라 팀을 찬양하게 될 것입니다.

이렇게 빠르고 완벽한 젠킨스 서버를 수년간 애지중지 키웠는데, 어느 날 회사에서 "기존 서버 장비를 폐기하고 최신형 클라우드 서버로 인프라를 이전(Migration)하라"는 미션이 떨어졌습니다. 수십 개의 파이프라인, 수백 명의 계정, 플러그인 세팅을 다운타임(Downtime) 없이 새로운 서버로 이사하려면 어떻게 해야 할까요? 새로 하나하나 다 손으로 세팅해야 할까요? 이어지는 28단계 포스팅에서는 서버 이전의 두려움을 완벽히 없애주는 'Jenkins 무중단 데이터 마이그레이션(Migration) 전략과 rsync 동기화 비법'에 대해 아주 뼈 때리는 생생한 실무 노하우와 함께 파헤쳐 보겠습니다!

반응형