CI/CD
빌드·배포 프로세스 자동화
빌드부터 재기동까지 전부 수동으로 하던 개발 서버 배포를, Jenkins 파이프라인으로 자동화했습니다. GitLab에 푸시하면 알아서 빌드·배포가 돌아갑니다.
- 배포 시간
- 20분 → 4분
- 자동화 범위
- 3단계
- 트리거
- GitLab Webhook
- 인프라
- Docker + Jenkins
약 80% 단축
Checkout · Build · Deploy
브랜치 기반 자동 감지
Declarative Pipeline
Problem
배포 한 번에 15~20분, 이력도 추적 불가
개발 서버 배포가 빌드부터 전송·재기동까지 전부 사람 손으로 돌아가고 있었습니다. 한 번 배포하는 데 15~20분 — 그 시간 동안 다른 개발자들도 같이 눈치 보면서 기다렸고, 누가 언제 뭘 배포했는지 기록은 어디에도 안 남았습니다. 자주 배포하다 보면 명령어 오타나 환경 착각 같은 실수가 한 번씩 섞이고, 그럴 때마다 롤백·재배포 오버헤드가 덤으로 붙었습니다.
배포 1회 평균 15~20분
빌드·전송·재기동을 순서대로 직접 수행
배포 이력 추적 불가
누가 언제 뭘 배포했는지 확인 방법 없음
대기 시간 발생
배포 중에는 다른 작업도 같이 멈춤
수동 작업 실수
명령어 오타·환경 착각으로 장애가 간혹 발생
Approach
Jenkins 파이프라인 기반 CI/CD 구축
Jenkins Declarative Pipeline을 써서 빌드·배포 절차를 Jenkinsfile 하나에 정의했습니다. GitLab Webhook으로 특정 브랜치 푸시를 감지하고, Checkout → Build → Deploy 단계가 순차적으로 실행되도록 구성했습니다.
Trigger
Developer
git push devtest
GitLab
Webhook 송신
Jenkins Pipeline
Checkout
git clone
Build
mvn clean package
Deploy
SSH + deploy.sh
Target
Staging Server
WAR 배포 + WAS 재기동
배포 1회 평균 소요 시간
분
Before · 수동
15 ~ 20분
After · 자동화
4분
▼ 약 80% 단축
Process
구현 단계
- 01
Jenkins를 Docker 컨테이너로 띄우기
호스트 환경이 꼬이는 걸 피하려고 Jenkins를 Docker 컨테이너로 돌렸습니다. 작업·플러그인·자격증명은 볼륨으로 분리해서 재기동해도 설정이 그대로 유지되도록 구성했습니다.
- 02
GitLab Webhook 연결
GitLab 저장소의 푸시 이벤트를 Jenkins로 넘겨받고,
regexpFilterExpression으로 devtest 브랜치 푸시만 걸러서 빌드가 돌아가도록 필터링했습니다. - 03
Jenkinsfile 작성
Checkout → Build → Deploy 단계를 나눠 두어, 실패가 생기면 어느 단계에서 멈췄는지 바로 보이도록 했습니다. Deploy는 SSH로 WAR 파일을 보낸 뒤 서버측
deploy.sh를 실행해서 WAS 재기동까지 한 번에 처리합니다.Jenkinsfilegroovy// Jenkins Declarative Pipeline - GitLab Webhook 연동 자동 배포pipeline {agent anytriggers {GenericTrigger(genericVariables: [[key: 'BRANCH_NAME', value: '$.ref'],[key: 'EVENT_TYPE', value: '$.event_name']],regexpFilterExpression: '^refs/heads/devtest push$')}stages {stage('Checkout') {steps {git branch: 'devtest',credentialsId: 'gitlab-ssh-key',url: 'ssh://git@server/gitlab/goad.git'}}stage('Build') {steps {sh 'mvn clean package -P staging'}}stage('Deploy') {steps {sshPublisher(publishers: [sshPublisherDesc(configName: 'staging-server',transfers: [sshTransfer(sourceFiles: 'target/issga.war',execCommand: '/home/deploy/deploy.sh')])])}}}} - 04
GitLab 커밋에 빌드 상태 표시
빌드 결과를 GitLab 커밋 상태로 되돌려 줘서, GitLab에서 커밋을 보면 빌드 성공/실패/진행 중 여부를 바로 확인할 수 있도록 했습니다.
Outcome
결과와 배운 것
배포 시간 20분 → 4분
수동 15~20분 걸리던 작업이 자동 파이프라인으로 4분대까지 줄었습니다.
수동 작업 실수가 사라짐
명령어 오타, 환경 착각처럼 사람이 개입해서 나던 실수들이 거의 없어졌습니다.
대기 시간 없이 다음 작업으로
푸시하고 나면 파이프라인이 돌아가는 동안 개발자들은 바로 다음 작업으로 넘어갈 수 있습니다.
Freestyle보다 Pipeline이 맞았다
처음에는 Freestyle Job으로 시도했는데, 추적·재사용·확장 모두 Pipeline 쪽이 훨씬 편했습니다. 절차를 코드로 남기는 게 왜 중요한지 실감했습니다.
MORE
다른 케이스 살펴보기
바다봄
AUTH / SSO
외부 사이트용 SSO Provider 구축
OTT 등 외부 기관 사이트에서 바다봄 계정으로 로그인하도록 Provider를 직접 구현했습니다. 일회용 UUID 토큰을 DB에 저장해 다중 WAS를 지원하고, CI(개인 공통 식별자) 기반으로 양쪽 계정을 자동 매핑합니다.
자세히 보기바다봄
DEVOPS / OBSERVABILITY
SSE + Cross-WAS 실시간 로그 뷰어
WAS는 대전 IDC에 있는데, 망분리 정책상 그 서버에 붙을 수 있는 PC가 부산 사무실에만 있었습니다. 그래서 로그 한 번 보려면 사실상 부산으로 가야 하는 구조였어요. 관리자 웹 안에 SSE 기반 뷰어를 만들고, 두 개 WAS 노드 로그까지 Cross-WAS 릴레이로 한 화면에서 보이도록 구성했습니다.
자세히 보기바다봄
LEGACY MIGRATION
OTT 기술거래 시스템을 바다봄으로 이관
Oracle + MyBatis 기반의 OTT 기술거래 플랫폼을 PostgreSQL + iBATIS 환경으로 옮겼습니다. 87개 URL, 34개 JSP, 80여 개 SQL과 14개 테이블을 재작성했습니다.
자세히 보기정부광고통합지원시스템
INFRA / SESSION
Redis 기반 세션 클러스터링
JEUS Standard에서는 세션 클러스터링 기능을 못 써서, Redis를 외부 세션 저장소로 두고 우회했습니다. 덕분에 WAS 순차 재기동이 가능해졌습니다.
자세히 보기정부광고통합지원시스템
SECURITY / NETWORK
Nginx 리버스 프록시로 TLS 1.3 적용
WebtoB 공용 SSL을 건드리기 부담스러워서, 앞단에 Nginx를 세우고 거기서 TLS를 종단하도록 바꿨습니다. 기존 서비스는 영향 없이 TLS 1.3으로 올렸습니다.
자세히 보기프리랜서 · 사이드 프로젝트
CLIENT WORK / WEB
산후조리원 홈페이지 리뉴얼 제안 → 제작
아내가 입소한 조리원의 홈페이지가 오래돼 보여서 직접 UI 샘플을 만들어 제안했습니다. 192프레임 스크롤 애니메이션, 카카오맵, SEO까지 갖춘 Astro 정적 사이트를 제작해서 실제 운영 도메인으로 배포했습니다.
자세히 보기프리랜서 · 사이드 프로젝트
SIDE PROJECT / AI
AI 작명 + 이상형 월드컵으로 가족이 함께 고르는 아기 이름
기존 작명 서비스가 혼자 쓰는 구조여서, 가족이 같이 참여할 수 있는 방식을 만들었습니다. GPT-4o가 사주·오행 맞춰 이름을 추천하면, 이상형 월드컵으로 가족이 투표해서 최종 이름을 고릅니다.
자세히 보기