과감한 Jenkins 폐기와 CI/CD 마이그레이션
사내 하네스 인프라 대공사의 마지막 퍼즐은 가장 무겁고 오래된 레거시, Jenkins 서버의 철거 였습니다. 수많은 기업들이 관성적으로 Jenkins를 사용합니다. 우리 역시 마찬가지였습니다. 하지만 "우리가 과연 Jenkins의 강력한 기능들을 100% 활용하고 있는가?", "이 도구가 지금 우리 비즈니스 규모에 맞는가?"라는 근본적인 의구심이 들기 시작했고, 결국 서버리스 CI/CD인 GitHub Actions 로의 전면 마이그레이션을 결단했습니다.
그 결단의 배경과 비용 최적화, 그리고 배포 파이프라인을 고도화한 과정을 공유합니다.
The Problem: 배보다 배꼽이 더 큰 인프라와 핫픽스 병목
과거 우리 팀은 배포 트래픽 비용을 최소화하겠다는 목적 하에, 배포 타겟 서버 혹은 프로젝트별로 Jenkins 인스턴스를 분리하여 총 3대의 서버를 운영하고 있었습니다.
- NHN Cloud:
r2.c2m8(2vCPU, 8GB) - AWS:
t4g.micro,t2.small
트래픽 비용은 아꼈을지 몰라도, 이 3대의 인스턴스를 항시 띄워두는 데 매월 약 50만 원의 고정 유지비 가 발생하고 있었습니다. 비용도 문제였지만, 진짜 고통은 '개발자 경험'의 하락이었습니다. 인스턴스의 스펙이 대체로 낮고 파편화되어 있다 보니 메모리 부족으로 배포가 중간에 뻗어버리는 일이 잦았습니다. 특히 보안 이슈로 긴급 핫픽스를 배포해야 할 때, 낮은 스펙 탓에 여러 프로젝트의 동시 빌드가 불가능해 빌드 큐(Queue)에서 하염없이 대기해야 하는 치명적인 병목 현상을 겪었습니다.
The Solution: 서버리스 전환과 파이프라인 고도화
더 이상 Jenkins를 고집할 이유가 없었습니다. 고정비가 없고 병렬 빌드가 자유로운 GitHub Actions 로 모든 파이프라인을 옮기기 시작했습니다. 마이그레이션 자체는 까다롭지 않았습니다. 자체 슬랙 봇을 연동하는 데 1시간 남짓 소요되었을 뿐, 배포의 논리적 흐름은 동일했기 때문입니다. 오히려 저는 단순히 툴을 바꾸는 것을 넘어, 배포 속도와 스크립트의 유지보수성을 고도화 하는 데 집중했습니다.
1. npm ci와 캐싱을 통한 빌드 속도 최적화
매번 무거운 모듈을 새로 다운로드하는 시간을 줄이기 위해 Actions의 actions/cache를 적극 도입했습니다. package-lock.json의 해시값을 키로 삼아 node_modules와 Next.js 빌드 캐시를 저장하고, npm ci 명령어를 통해 캐시 적중률을 높여 CI/CD의 생명인 '빌드 속도'를 비약적으로 끌어올렸습니다.
2. 셸 스크립트의 범용화 및 추상화
기존에는 서버마다, 프로젝트마다 압축을 풀고 PM2를 재시작하는 하드코딩된 .sh 파일이 파편화되어 존재했습니다. 이를 하나의 공통 server-deploy.sh로 통합하고, GitHub Actions에서 실행 시 인자값 으로 DEPLOY_DIR, TAR_FILE, APP_NAME, APP_TYPE(pm2/static)을 주입하도록 리팩토링했습니다. 이제 새로운 프로젝트가 추가되더라도 서버의 스크립트를 건드릴 필요 없이 파이프라인 설정만으로 즉각 대응이 가능한 유연한 구조를 완성했습니다.
The Result & Retrospective
현재 Jenkins에서 GitHub Actions로의 전환 작업을 점진적으로 진행 중이지만, 이미 그 효과는 명확합니다. 가장 직관적인 성과는 매월 50만 원씩 빠져나가던 인프라 유지 비용을 0원으로 수렴 시킨 것입니다. 나아가 Jenkins의 물리적 스펙 한계에 갇혀 있던 '1 빌드' 제약에서 벗어나 다수의 프로젝트를 동시에 병렬로 빌드할 수 있게 되면서, 핫픽스 대기 시간이라는 치명적인 병목을 완벽하게 해소할 수 있을 것으로 기대하고 있습니다.
관성적으로 쓰던 도구를 버리고 현재의 비즈니스 체급과 비용에 가장 알맞은 아키텍처를 새로 그리는 것, 이것이 진정한 의미의 DevOps이자 인프라 최적화임을 깨달았습니다.