데브옵스(DevOps) 엔지니어의 가장 큰 덕목은 배포 속도를 빠르게 만드는 것도 중요하지만, '최악의 장애 상황에서도 인프라를 신속하게 복구(Disaster Recovery)해 내는 것'입니다.
수십 개의 프로젝트 파이프라인과 플러그인, 계정 정보, 복잡한 인증키(Credentials)들이 세팅된 젠킨스 서버의 하드디스크가 어느 날 갑자기 물리적 장애로 뻗어버린다면 어떻게 될까요? 백업이 없다면 전사의 배포 프로세스는 수일 동안 올스톱되며 당신은 시말서를 피할 수 없을 것입니다.
1. 무엇을 백업하고, 무엇을 버릴 것인가? (용량 최적화)
초보 인프라 관리자들은 "백업? 그냥 /var/jenkins_home 디렉토리 전체를 통째로 압축해서 보관하면 되잖아?"라고 생각합니다. 이는 매우 무식하고 위험한 발상입니다.
jenkins_home 내부에는 파이프라인 설정 파일뿐만 아니라, workspace/ (수십 GB에 달하는 소스코드와 node_modules), caches/, logs/ 같은 엄청난 찌꺼기 파일들이 함께 들어있습니다. 이 전체를 압축하려고 시도하면 압축에만 수십 분이 걸려 서버 CPU를 잡아먹고, 백업 파일 용량이 100GB를 훌쩍 넘어 스토리지 비용이 폭발하게 됩니다. 우리가 백업해야 할 진짜 '영혼'은 불과 수십 MB 내외의 XML 설정 파일들입니다.
반드시 백업해야 할 4대 핵심 타겟:
*.xml(최상위 루트에 있는 젠킨스 글로벌 시스템 설정 파일들)jobs/(개별 파이프라인들의 설정(config.xml) 및 빌드 히스토리)plugins/(설치된 플러그인 바이너리.jpi파일 모음)secrets/및credentials.xml(가장 중요한 보안 암호화 키와 금고 데이터)
2. ThinBackup 플러그인 (간편한 대안)
직접 쉘 스크립트를 짜는 것이 부담스럽다면 가장 유명한 ThinBackup 플러그인을 추천합니다. 이 녀석을 설치하고 설정에 들어가면, 딱 젠킨스 구동에 필요한 알짜배기 설정 파일들만 쏙쏙 뽑아내어 매일 밤 12시(Cron 스케줄링)에 지정된 서버 경로로 예쁘게 압축해서 뱉어냅니다. 초보자에게는 훌륭한 선택입니다.
3. 상위 1% 실무의 정석: 수동 쉘 스크립트 + AWS S3 전송
하지만 백업 파일을 젠킨스가 떠 있는 똑같은 서버 /tmp 폴더에만 놔두면, 서버 하드가 타버렸 때 백업본도 같이 타버립니다. 백업의 철칙인 '오프사이트 백업(물리적으로 떨어진 안전한 클라우드에 복사본 저장)'을 달성하려면 결국 커스텀 쉘 스크립트를 작성하여 AWS S3 같은 스토리지로 쏘아 올려야 합니다.
아래는 실무 서버의 크론탭(Crontab)에 등록하여 매일 새벽 3시에 돌리는 완벽한 백업 스크립트 예제입니다.
#!/bin/bash
# 파일명: jenkins_backup_to_s3.sh
JENKINS_HOME="/var/jenkins_home"
BACKUP_TEMP_DIR="/tmp/jenkins_backup_temp"
DATE=$(date +"%Y%m%d_%H%M")
ARCHIVE_NAME="jenkins_backup_${DATE}.tar.gz"
echo "1. 임시 백업 디렉토리 생성 중..."
mkdir -p $BACKUP_TEMP_DIR
echo "2. rsync를 이용해 핵심 파일만 동기화 (workspace, caches, logs 등 찌꺼기는 철저히 배제)"
# --exclude 옵션을 통해 불필요한 공룡 폴더들을 과감히 버립니다.
rsync -avz \
--exclude 'workspace' \
--exclude 'caches' \
--exclude 'logs' \
--exclude 'tools' \
$JENKINS_HOME/ $BACKUP_TEMP_DIR/
echo "3. 추출된 알짜배기 설정들을 압축(Tar) 중..."
tar -czvf /tmp/$ARCHIVE_NAME -C $BACKUP_TEMP_DIR .
echo "4. AWS S3 버킷으로 백업 아카이브 전송 시작..."
# AWS CLI가 서버에 설치되어 있고 권한이 설정되어 있어야 합니다.
aws s3 cp /tmp/$ARCHIVE_NAME s3://my-company-jenkins-backup-bucket/
echo "5. 전송 완료! 로컬에 남은 임시 파일과 압축본 청소 중..."
rm -rf $BACKUP_TEMP_DIR
rm -f /tmp/$ARCHIVE_NAME
echo " Jenkins 백업이 성공적으로 S3에 안전하게 보관되었습니다!"
이제 새 서버를 띄운 뒤, S3에서 저 tar.gz 파일을 다운받아 빈 jenkins_home 경로에 압축만 풀어주고 데몬을 재시작하면, 불과 3분 만에 모든 파이프라인과 플러그인, 계정이 완벽하게 복구된 좀비 젠킨스를 만나실 수 있습니다.
4. 마무리 및 주요 발전 방향
지금까지 용량 폭발을 막기 위해 찌꺼기를 걸러내고 영혼(설정 파일)만 추출하는 압축의 미학부터, 클라우드 스토리지로 쏘아 올려 물리적 재앙까지 대비하는 완벽한 젠킨스 백업 스크립트 작성 기법에 대해 다루어 보았습니다. 오늘 당장 서버에 접속하여 이 스크립트를 크론탭에 등록해 두십시오. 미래의 당신을 구원할 동아줄이 될 것입니다.
백업 스크립트도 Cron(크론)이라는 스케줄링을 통해 매일 새벽에 자동으로 돌게 만들었습니다. 그렇다면 파이프라인 자체도 누군가 커밋을 하거나 버튼을 누르지 않아도 "매일 자정에 데이터베이스 덤프를 떠라", "매주 월요일 아침 9시에 보안 스캔을 돌려라" 하고 주기적으로 알아서 돌게 만들 순 없을까요?
우리가 지금까지 구축한 파이프라인은 대부분 누군가 Github에 코드를 푸시(Push)하거나, 젠킨스 화면에서 수동으로 Build Now 버튼을 눌렀을 때(Event-Driven) 동작하는 방식이었습니다. 하지만 실무에서는 사람의 개입이나 특별한 이벤트 없이도 정해진 시간(스케줄)에 스스로 깨어나 묵묵히 돌아가야 하는 백그라운드 작업들이 매우 많습니다. 매일 밤 자정에 도는 무거운 대규모 E2E 통합 테스트, 매일 새벽 3시에 수행되는 데이터베이스 덤프 백업, 매주 월요일 아침 8시에 슬랙으로 전송되는 주간 빌드 통계 리포트 등이 대표적입니다.
5. Build periodically vs Poll SCM (과거의 유산)
젠킨스의 트리거(Trigger) 메뉴를 보면 스케줄링을 설정할 수 있는 옵션이 크게 두 가지가 있습니다. 이 둘의 차이를 명확히 알아야 실무에서 헤매지 않습니다.
1. Poll SCM (더 이상 쓰지 않음):
"매 5분마다 Github에 들어가서 코드가 바뀌었는지 물어보고(Poll), 바뀌었으면 빌드해라"라는 뜻입니다. 과거 Github Webhook 기능이 빈약하던 시절에 쓰던 구시대적 유물입니다. 5분마다 젠킨스가 무의미하게 Github API를 찔러대므로 네트워크 낭비가 심합니다. 현대 CI/CD에서는 코드가 바뀌면 Github이 젠킨스를 먼저 찔러주는(Webhook) 방식을 사용하므로 Poll SCM은 실무에서 퇴출되었습니다.
2. Build periodically (이것이 진짜 Cron):
"코드가 바뀌었든 말든 묻지도 따지지도 않고, 내가 지정한 시간에 무조건 파이프라인을 1회 실행하라"는 뜻입니다. 백업, 통계 생성, 자정 통합 테스트 등 진정한 의미의 스케줄링(배치 작업)을 원할 때는 무조건 이 옵션을 사용해야 합니다.
6. 리눅스 Cron과의 차이점: 마법의 키워드 'H'
젠킨스의 스케줄링 문법은 리눅스의 표준 crontab 문법(분 시 일 월 요일)을 베이스로 합니다. 하지만 리눅스 크론을 그대로 쓰다 보면 대형 인프라 환경에서 심각한 서버 폭주(Spike) 현상이 발생합니다.
예를 들어, "매일 밤 12시 정각에 각 서비스의 백업을 수행해라"라는 뜻으로 50개의 Job에 0 0 * * * 라고 적어두었다고 칩시다. 11시 59분 59초에서 12시 00분 00초가 되는 순간, 젠킨스 서버는 50개의 무거운 파이프라인을 '동시에' 시작하려 들 것이고, CPU와 메모리가 임계점을 돌파하며 서버가 기절해 버립니다.
이러한 DDoS급 자폭을 막기 위해 젠킨스는 H (Hash)라는 독자적이고 천재적인 키워드를 도입했습니다. H 0 * * * 라고 적으면 "매일 밤 12시 00분부터 12시 59분 사이의 아무 랜덤한 시간(Hash 연산 기반)에 한 번 돌려라"라는 뜻이 됩니다. 50개의 Job에 모두 똑같이 H 0 * * *를 적어두면, 젠킨스는 내부 알고리즘에 따라 A 잡은 12시 5분에, B 잡은 12시 13분에, C 잡은 12시 42분에 스스로 시간을 분산시켜 차례대로 실행합니다. 서버 부하 분산(Load Balancing)이 코드 한 글자로 완벽하게 해결되는 마법입니다. 실무에서는 숫자를 명시하는 것보다 H를 쓰는 것을 강력한 Best Practice로 권장합니다.
7. Declarative Pipeline 적용 코드 파헤치기
웹 UI 설정창(텍스트 박스)에 적을 수도 있지만, 우리는 모든 것을 코드로 관리하는 IaC(Infrastructure as Code)를 지향하므로 Jenkinsfile 내부에 직접 명시해야 합니다. pipeline 블록 최상단에 triggers 블록을 선언하여 스케줄을 박아 넣습니다.
pipeline {
agent any
// 이 파이프라인은 지정된 시간에 스스로 깨어납니다.
triggers {
// 1. 매일 밤 12시 ~ 새벽 1시 사이 랜덤 분산 실행 (가장 추천)
cron('H 0 * * *')
// 2. 주말(토, 일)을 제외하고, 평일(월~금) 새벽 2시 정각에 칼같이 실행하고 싶을 때
// cron('0 2 * * 1-5')
// 3. (극단적 예시) 2시간마다 1번씩 하루에 12번 실행
// cron('H H/2 * * *')
}
stages {
stage('Nightly Massive E2E Test') {
steps {
echo " 심야 정기 통합 테스트(약 2시간 소요)를 시작합니다..."
// sh 'npm run test:e2e-all'
}
}
stage('Generate Daily Report') {
steps {
echo "테스트 통계를 집계하여 PDF 리포트를 생성합니다..."
}
}
}
post {
always {
echo "사장님과 팀장님이 계신 슬랙 채널로 리포트를 쏩니다!"
// slackSend ...
}
}
}
8. 마무리 및 주요 발전 방향
지금까지 서버 부하를 막아주는 지능형 분산 키워드 `H`의 원리와, 파이프라인 코드로 배치 작업을 완벽하게 자동화하는 주기적 빌드(Cron Trigger) 설정법에 대해 3,000자의 밀도 높은 내용으로 살펴보았습니다. 이제 여러분은 새벽에 졸린 눈을 비비며 서버에 접속해 백업 스크립트를 누르던 노예 생활을 청산하고 진정한 데브옵스의 자유를 얻었습니다.
스케줄링을 통해 새벽에 빌드를 빵빵하게 돌리는 것까지는 좋았는데, 아침에 출근해 보니 "빌드가 1번 도는 데 30분이나 걸린다"는 충격적인 리포트를 받게 되었습니다. 원인을 분석해 보니, 젠킨스가 빌드를 할 때마다 수 기가바이트에 달하는 자바 라이브러리(Maven/Gradle)를 인터넷에서 처음부터 싹 다 새로 다운받고 있었던 것입니다!
다음 글에서는 빌드 속도를 10배 이상 끌어올리는 'Maven/Gradle 빌드 캐시(Cache) 완벽 마운트 전략'에 대해 다뤄보겠습니다.
'CI. CD > Jenkins' 카테고리의 다른 글
| [Jenkins] Timeout의 파이프라인 무한 루프 방어 (0) | 2026.10.12 |
|---|---|
| [Jenkins] Maven Gradle 빌드 캐시 최적화 빌드 시간 10배 단축의 비밀 (0) | 2026.10.08 |
| [Jenkins] 쿠버네티스(KubernetesK8s) 완벽 연동 무중단 배포 자동화 (0) | 2026.10.07 |
| [Jenkins] SonarQube 연동 불량 코드 자동 차단 시스템 Quality Gate (0) | 2026.10.05 |
| [Jenkins] 병렬 빌드로 파이프라인 속도 혁신하기(Parallel Build) (0) | 2026.10.05 |