본문 바로가기
CI.CD/Jenkins

[Jenkins] Jenkins 무중단 마이그레이션(Migration) 완벽 가이드

반응형

잘 굴러가던 젠킨스 서버를 3년쯤 운영하다 보면 반드시 거대한 장벽과 마주치게 됩니다. "서버 OS 버전이 너무 낮아서 더 이상 보안 패치를 받을 수 없다", "회사 방침으로 AWS에서 GCP로 클라우드를 통째로 이전해야 한다" 같은 거부할 수 없는 인프라 개편 지시가 떨어집니다. 이때 데브옵스 엔지니어의 머릿속은 하얗게 변합니다. 수백 개의 파이프라인 Job들, 정성껏 튜닝해 놓은 플러그인 설정들, 수많은 개발자들의 계정 정보와 보안 키(Credentials)를 새로운 서버에 똑같이 세팅하려면 몇 날 며칠을 밤새워야 할까요? 놀랍게도 정답은 "명령어 몇 줄이면 단 10분 만에 끝난다"입니다.

이번 [Jenkins 실무 완벽 가이드] 시리즈에서는 인프라 엔지니어의 영원한 숙제인 구형 젠킨스 서버에서 신규 서버로 다운타임(Downtime)을 최소화하며 영혼(데이터)을 완벽하게 이식하는 마이그레이션 전략에 대하여 다뤄보겠습니다.

🗂️ 1. 젠킨스의 축복: 데이터베이스가 없다!

대부분의 웹 어플리케이션(게시판, 쇼핑몰 등)을 마이그레이션할 때는 MySQL이나 Oracle 같은 데이터베이스(DB)를 백업하고 이전하는 과정이 가장 고통스럽습니다. 하지만 젠킨스 아키텍처의 가장 위대한 설계적 특징 중 하나는 바로 별도의 RDBMS(관계형 DB)를 전혀 사용하지 않는다는 점입니다.

젠킨스의 모든 영혼(Job 설정, 플러그인, 계정, 빌드 히스토리)은 오직 $JENKINS_HOME (일반적으로 /var/jenkins_home) 폴더 내부의 텍스트 파일(XML)과 디렉토리들로만 저장됩니다. 즉, 구형 서버의 이 폴더를 통째로 복사해서 신규 서버의 동일한 경로에 덮어씌운 뒤 젠킨스 데몬을 기동하기만 하면, 신규 서버는 자기가 구형 서버인 줄 착각하고 100% 동일한 모습으로 살아나게 됩니다. 마이그레이션이 사실상 '폴더 복사(Copy)' 하나로 끝나는 매우 우아한 구조입니다.


🚀 2. 다운타임(Downtime) 제로를 향한 rsync 2-Step 전략

하지만 폴더 용량이 50GB라면 복사하는 데 1시간이 넘게 걸릴 수 있습니다. 그 1시간 동안 젠킨스를 멈춰두면 개발팀 전체의 배포가 중단되겠죠. 실무에서는 서비스 중단을 최소화하기 위해 rsync를 활용한 2단계 동기화(Delta Sync) 전략을 씁니다.

Step 1: 1차 백그라운드 복사 (서버 정상 가동 중)
개발자들이 평소처럼 배포를 하고 있는 와중에, 인프라 관리자는 몰래 백그라운드에서 전체 데이터를 신규 서버로 전송하기 시작합니다. 50GB를 넘기느라 1시간이 걸려도 서비스에는 아무 지장이 없습니다.

Step 2: 2차 델타(Delta) 동기화 및 트래픽 절체 (다운타임 3분 컷)
1차 복사가 끝난 늦은 밤, 젠킨스를 Quiet Down(더 이상 새 빌드를 받지 않고 대기하는 모드) 상태로 만듭니다. 그리고 다시 한번 rsync 명령어를 때립니다. 이때 rsync는 천재적이게도 전체 50GB를 다시 복사하는 게 아니라, 1차 복사 이후 1시간 동안 추가되거나 변경된 파일(Delta) 수십 MB만 찾아내어 빛의 속도로 덮어씁니다. 복사가 1분 만에 끝나면, 구형 서버를 끄고 신규 서버를 켜서 도메인(DNS)을 연결합니다. 개발자들은 젠킨스가 이사 갔다는 사실조차 눈치채지 못합니다.


💻 3. 실무 적용 극한의 쉘 스크립트 파헤치기

25단계 백업 노하우에서 배웠듯, 쓰레기 파일들(Workspace 등)을 제외하고 영양가 있는 파일만 옮기는 것이 마이그레이션 시간 단축의 핵심입니다.

# [작업 1] 구형 서버(A)의 터미널에서 실행 - 1차 대용량 동기화 (서비스 무중단 상태)
# -a(아카이브 권한유지), -v(상세출력), -z(압축전송), -P(진행률 표시)
# --exclude 로 쓸데없는 찌꺼기 파일들은 이관 대상에서 제외시켜 버립니다.
echo "1차 마이그레이션 동기화를 시작합니다 (예상시간: 1시간)..."
rsync -avzP \
  --exclude 'workspace' \
  --exclude 'caches' \
  --exclude 'logs' \
  /var/jenkins_home/ root@192.168.2.200:/var/jenkins_home/

# =================================================================
# (1차 동기화 완료 후, 젠킨스 관리자 UI에서 [준비 상태로 전환(Quiet Down)] 클릭)
# 현재 돌고 있는 빌드가 모두 끝나기를 기다립니다. (빌드가 끝나면 젠킨스가 얼어붙음)
# =================================================================

# [작업 2] 구형 서버(A)의 터미널에서 재실행 - 2차 델타 동기화 (다운타임 시작)
# --delete 옵션을 추가하여, 그사이 구형 서버에서 삭제된 파일이 있다면 신규 서버에서도 날려줍니다 (완벽한 싱크).
echo "2차 차분(Delta) 동기화를 시작합니다 (예상시간: 1분)..."
rsync -avzP --delete \
  --exclude 'workspace' \
  --exclude 'caches' \
  /var/jenkins_home/ root@192.168.2.200:/var/jenkins_home/

# [작업 3] 신규 서버(B) 기동 및 마무리
echo "마이그레이션 완료! 신규 서버의 Jenkins 데몬을 기동합니다."
# DNS 설정(Route53 등)에서 jenkins.my-company.com 의 A 레코드 IP를 신규 서버로 변경합니다.

🎯 4. 마무리 및 다음 단계

지금까지 데이터베이스가 없는 젠킨스의 고유한 파일 기반(File-based) 아키텍처를 십분 활용하여, rsync의 델타 동기화를 통해 다운타임을 단 1분으로 압축해 버리는 완벽한 마이그레이션(서버 이전) 전략에 대해 3,000자의 생생한 실무 노하우로 다루어 보았습니다. 이제 여러분은 젠킨스 인프라를 언제 어디로든(온프레미스에서 클라우드로, K8s로) 자유자재로 옮겨 심을 수 있는 조물주의 권능을 얻었습니다.

서버 이전도 무사히 끝났고 평화로운 나날이 계속될 줄 알았습니다. 그런데 어느 날 젠킨스 대시보드를 보니, 빌드 3개가 24시간째(1,440분) 진행률 10%에 멈춰서 영원히 끝나지 않고(Hang) 있는 끔찍한 현상을 목격하게 됩니다. 젠킨스의 소중한 워커 쓰레드(Thread)를 좀비처럼 점유하고 놔주질 않는 것이죠. 이어지는 29단계 포스팅에서는 "30분 안에 안 끝나면 무조건 강제로 죽여버려라!" 파이프라인의 무한 대기 늪을 원천 차단하는 'Timeout(타임아웃) 강제 종료 방어 시스템'에 대해 아주 뼈 때리는 경험과 함께 치밀하게 파헤쳐 보겠습니다!

반응형