키즈노트 CI/CD 파이프라인 진화기(2)
키즈노트 CI/CD 파이프라인 진화기: 없던 것을 만들고, 만든 것을 통합하기까지
Part 2 — 첫 번째 삽: Frontend Pipeline 만들기
1. 왜 Frontend를 먼저 선택했는가
네 개 플랫폼 중 Jenkins와 연결된 곳은 Frontend가 유일했다. iOS, Android, 그리고 Backend도 Jenkins 연동이 없었던 상황에서 Frontend만이 그나마 Freestyle Job이라는 형태로 CI/CD의 틀을 갖추고 있었다.
그런데 “유일하게 Jenkins가 있다”는 사실이 오히려 문제의 규모를 더 잘 보여주고 있었다.
Freestyle Job의 수가 20~30개에 달했다. 빌드 환경별(dev, staging, cbt, prod), 파트너사 관련 프로젝트별로 잡이 쪼개져 있었고, 각각의 잡이 독립적으로 Jenkins UI 안에 설정되어 있었다. Frontend 파트장님께서 Jenkins에 대한 이해가 있어서 여기까지 구성해두긴 했지만, 잡 수가 늘어날수록 관리 부담도 함께 늘고 있었다.
이런 상황에서 Frontend를 가장 먼저 선택한 이유는 세 가지였다.
첫째, 이미 Jenkins 기반이라 전환 리스크가 낮았다. 새로운 도구를 도입하는 게 아니라 기존 구조를 개선하는 작업이었기 때문에 팀의 저항도 상대적으로 적었다.
둘째, 파라미터 기반 빌드 구조가 이미 준비되어 있었다. 당시 Freestyle Job에는 choice parameter, active choices parameter 타입의 파라미터들이 설정되어 있었고, Execute shell로 빌드 및 배포 커맨드를 날리는 방식이었다. 파이프라인으로 옮기기 위한 기초 작업이 사실상 되어 있던 셈이었다.
셋째, 성공 사례를 먼저 만들 수 있었다. Frontend가 잘 되면 이후 iOS, Android, Backend 팀을 설득하는 데 실제 사례로 활용할 수 있었다. 첫 번째 삽을 어디에 꽂느냐가 이후 전체 흐름을 결정하는 일이기도 했다.
2. Freestyle → Scripted Pipeline 전환
Freestyle Job의 한계
※ 실제 키즈노트 화면이 아닌, 동일한 구조로 재현한 예시 화면입니다.
Freestyle Job은 Jenkins UI 안에 설정이 박혀 있다. 빌드 스크립트, 파라미터, 배포 커맨드가 모두 화면 안에 존재하기 때문에 몇 가지 구조적인 문제가 따라온다.
- 형상 관리 불가 — 누가 언제 어떤 설정을 바꿨는지 이력이 남지 않는다
- 코드 리뷰 불가 — 변경 사항을 검토할 방법이 없다
- 휴먼 에러 — UI에서 직접 수정하다 보면 실수가 생기고, 잡 수가 많을수록 빈도가 높아진다
- 복제의 악순환 — 새 잡이 필요하면 기존 잡을 복사하고 일부만 수정하는 방식이 반복된다
20~30개의 잡을 이런 방식으로 관리하고 있었으니, 하나를 고치면 나머지도 찾아서 고쳐야 했다. 레거시가 쌓이는 구조였다.
Scripted Pipeline을 선택한 이유
Declarative Pipeline이 아닌 Scripted Pipeline을 선택한 데는 이유가 있었다.
당시 Frontend 배포는 단순히 소스를 빌드하는 수준이 아니었다. 프로젝트별로 빌드 방식이 조금씩 달랐고, 환경(dev, staging, cbt, prod)에 따라 처리해야 하는 로직도 살짝식 달랐다. 여기에 배포 과정 중 Slack 알림, 프로젝트별 에외 처리 등 다양한 분기 로직이 있었다.
Scripted Pipeline은 Groovy 코드로 작성되기 때문에 조건문, 반복문, 함수 정의 등을 자유롭게 사용할 수 있었다. 환경별 분기와 프로젝트별 처리 로직을 하나의 스크립트 안에 담기에 적합했고, 이후 여러 프로젝트에 공통으로 적용될 기능들을 코드로 재사용하기에도 유리했다.
무엇보다 코드로 파이프라인을 작성하고 Git으로 관리한다는 방향성이었다. Jenkins UI 안에 설정을 남기는 대신 Git으로 형상 관리하고 변경 이력을 추적할 수 있는 구조를 만들고 싶었다. 당시에는 Shared Library까지 고려한 것은 아니었지만, 결과적으로 Scripted Pipeline을 선택한 것이 이후 Shared Library 도입과 Git 기반 관리 체계로 확장되는 기반이 되었다.
전환 과정
전환은 두 단계로 진행했다.
1단계 — 1:1 변환
Freestyle Job에 설정된 내용을 그대로 Scripted Pipeline 코드로 옮기는 작업이었다. 기능을 바꾸는 게 아니라 형태만 바꾸는 단계였다. 잡 수가 많다 보니 변환 과정에서 휴먼 에러가 종종 발생했고, 이것이 나중에 Git 레포 관리를 시작하는 계기가 되기도 했다.
2단계 — 정리 및 통합
변환이 완료된 후, 하나씩 배포 테스트를 진행하면서 불필요한 부분을 걷어냈다. 그리고 환경별로 쪼개져 있던 잡들을 비교해 동일한 프로젝트끼리 하나로 합치는 작업을 했다.
당시 개발과 운영 Jenkins가 분리되어 있었기 때문에:
dev+staging→ 하나의 잡으로 통합cbt+prod→ 하나의 잡으로 통합
cbt는 Closed Beta Test의 약자로, 운영 배포 직전 내부 검증 환경이었다.
20~30개였던 잡이 프로젝트 단위로 정리되면서 수가 의미 있게 줄었다.
3. Frontend Pipeline 구조
※ 실제 키즈노트 화면이 아닌, 동일한 구조로 재현한 예시 화면입니다.
빌드 및 배포 흐름은 다음과 같이 구성했다.
1
Git Pull → 서버 환경변수 설정 → Build → Deploy
Git Pull 단계에서 Jenkins 에이전트 노드가 Git 레포를 pull해 소스를 가져온다. 파라미터로 브랜치와 프로젝트를 선택할 수 있도록 했다.
서버 환경변수 설정 단계에서는 타겟 서버에서 사용할 환경 변수들을 설정하는 과정이 진행되도록 하였다.
Build 단계에서는 워크스페이스에서 빌드를 진행한다. 환경별 분기는 파라미터로 받은 ENV 값을 빌드 커맨드에 직접 넘기는 방식으로 처리했다. Freestyle에서는 환경마다 잡을 따로 만들어야 했지만, Pipeline에서는 하나의 스크립트 안에서 파라미터로 환경을 선택할 수 있게 됐다. 이것이 Freestyle 대비 가장 핵심적인 변화였다.
Deploy 단계에서는 빌드 결과로 생성된 아티팩트를 scp로 타겟 서버에 전송하고 서비스를 재구동하는 방식으로 진행했다.
4. Slack 알림 연동
파이프라인 작업을 하면서 특히 공을 들인 부분이 Slack 알림이었다.
키즈노트는 팀 간 소통을 Slack으로 하고 있었다. 배포를 진행한 개발자 본인만 결과를 아는 게 아니라, 관련 담당자들이 배포 사실과 결과를 실시간으로 확인할 수 있어야 했다. QA팀, 기획팀, 다른 개발 파트에서도 “지금 배포가 됐구나”를 알 수 있어야 협업이 매끄러워지는 구조였다.
Slack 커스텀 앱을 생성하고 Jenkins에 연결했다. Slack Block Kit을 활용해 단순 텍스트가 아닌 구조화된 메시지로 빌드 과정과 결과를 프로젝트 채널에 전송하도록 했다.
※ 위 화면들은 실제 키즈노트 화면이 아닌, 동일한 구조로 재현한 예시 화면입니다.
이 구조는 이후 iOS, Android, Backend 파이프라인에도 동일하게 적용되면서 전사 배포 알림의 표준이 되었다.
5. Git 레포 관리 시작
Freestyle에서 Pipeline으로 변환하는 과정에서 잡 수가 많다 보니 혼선이 자주 생겼다. 어떤 잡은 변환이 완료됐고 어떤 잡은 아직 진행 중인지, 검증된 스크립트와 아직 테스트 중인 스크립트가 뒤섞이는 상황이 발생했다.
이를 해결하기 위해 파이프라인 스크립트 전용 Git 레포를 별도로 생성했다. 검증이 완료된 스크립트만 레포에 올리는 원칙을 세우고, 디렉터리 구조는 플랫폼과 프로젝트 단위로 나눴다.
아래와 같은 방식으로 구성하였다.
1
2
3
4
5
6
7
8
9
10
pipeline-scripts/
├── frontend/
│ ├── kidsnote-web/
│ │ ├── xxx-dev
│ │ └── xxx-prod
│ ├── classnote-web/
│ └── familynote-web/
├── backend/
├── ios/
└── android/
당시에는 형상 관리 목적이었다. Jenkins 잡이 이 레포에서 직접 스크립트를 가져오는 방식은 아니었다. 잡 설정 안에 스크립트가 복사되어 있는 형태였고, 레포는 “검증된 버전을 보관하는 곳” 역할을 했다.
하지만 이 결정이 나중에 얼마나 중요한 선택이었는지는 시간이 지나면서 드러났다. 스크립트가 Git에 있다는 사실 자체가 이후 Shared Library 도입과 각 잡이 레포 소스를 직접 참조하는 방식으로의 전환을 가능하게 한 기반이 되었다.
처음부터 GitOps를 목표로 설계한 건 아니었다. 하지만 “코드로 관리한다”는 원칙 하나가 방향을 만들었다.
당시에는 단순히 파이프라인 스크립트를 백업하기 위한 저장소라고 생각했다. 하지만 결과적으로 이 저장소는 이후 Shared Library, Git 기반 Job 관리, 코드 리뷰 문화의 출발점이 되었다. 지금 돌아보면 Frontend Pipeline 자체보다도 이 저장소를 만든 결정이 더 큰 전환점이었던 것 같다.
6. 팀 간 협업
프론트엔드 파트장과의 작업
협업은 주로 Frontend 파트장을 통해 이루어졌다. 입사 초기였고 DevOps 경력도 많지 않았던 시점이라, 팀의 개발 상황과 성향을 어떻게 파악하고 소통을 해야 하는지에 파트장의 역할이 컸다.
다행히 Frontend 팀은 새로운 기술에 거부감이 없었다. 오히려 새로운 방식을 시도하고 개선을 만들어가는 걸 즐기는 성향이었다. 파트장이 방향을 제시하면, 그 방향에 맞게 파이프라인 스크립트를 설계하고 구축하는 방식으로 진행했다.
하루에도 여러 번 소통하면서 테스트 결과를 서로 공유하고 스크립트를 다듬어갔다. 막히는 부분이 생기면 같이 붙어서 해결했고, 배포 테스트가 성공할 때마다 다음 단계로 넘어갔다.
이 과정이 이후 진행될 iOS, Android, Backend 파이프라인 작업의 선례가 되었다. 기술적인 패턴뿐만 아니라, “어떻게 팀과 소통하면서 파이프라인을 만들어가는가”에 대한 방식도 여기서 처음 만들어졌다.
작업이 마무리된 후
Frontend 파이프라인 작업이 마무리됐을 때 팀의 반응은 긍정적이었다. 20~30개였던 잡이 정리되고, 파라미터 하나로 환경을 선택해 배포할 수 있게 되면서 반복 작업이 줄었다. Slack 알림이 붙으면서 배포 사실을 팀 전체가 실시간으로 공유할 수 있게 됐다.
Frontend 파트로부터 배포 관련해서 신뢰를 얻을 수 있었고, 다른 파트에서도 “이제 우리 차례는 언제인가”라는 기대가 조금씩 생기기 시작했다.
다음 글에서는 Jenkins 연동 자체가 없었던 iOS와 Android, 즉 없던 것을 처음부터 만드는 과정을 다룬다. Mac Mini를 Jenkins Slave로 연결하는 것부터 시작해서, 플랫폼마다 전혀 다른 빌드 환경을 어떻게 파이프라인으로 담아냈는지를 이야기할 것이다.
본 시리즈는 총 6부로 구성됩니다.
| 파트 | 제목 |
|---|---|
| Part 1 | 시작 전야: 플랫폼마다 달랐던 배포 풍경 |
| Part 2 | 첫 번째 삽: Frontend Pipeline 만들기 ← 현재 글 |
| Part 3 | Mobile로의 확장: iOS와 Android Pipeline 구축 |
| Part 4 | 마지막 퍼즐: Backend Pipeline 구축 |
| Part 5 | 중복을 코드로: Shared Library와 Git 기반 전환 |
| Part 6 | 회고: 없던 것을 만들고 통합하기까지 |





