# CI/CD

### Jenkins Pipeline 으로 배포 시간을 1시간에서 20분으로 줄인 경험.

대만 LostArk 오픈을 준비하면서 배포 대상 서버 수가 크게 늘어난 적이 있었다.

프론트 서버 10대, 백엔드 서버 10대로 총 20대를 운영해야 했고, 기존 방식으로는 배포 시간이 너무 오래 걸리기 시작했다.

처음에는 "여러 서버를 동시에 배포하면 더 빠르지 않을까?" 라고 생각했지만 실제로는 반대였다.

Jenkins 에서 여러 서버 빌드 작업을 한 번에 몰아서 실행하면 Jenkins 서버 CPU 가 98% 까지 치솟았고, Grafana 알림이 올 정도로 부하가 커졌다. 심한 경우 Jenkins 자체가 멈추기도 했다.

즉, 배포 대상 서버 수는 늘었는데 **배포를 관리하는 Jenkins 가 병목이 되는 구조** 였던 것이다.&#x20;

이 문제를 해결하기 위해 Jenkins 의 **Pipeline 기능을 이용해 배포 단계를 재구성** 했고, 그 결과 전체 배포 시간을 크게 줄일 수 있었다.&#x20;

***

### 문제 상황

서버 수가 적을 때는 기존 방식으로도 어떻게든 운영이 가능했다.

하지만 프론트 10대, 백엔드 10대로 규모가 커지면서 문제가 드러났다.

기존 배포 방식에서는 여러 서버에 대한 빌드와 배포 작업을 한 번에 처리하려고 했고, 이 과정에서 Jenkins 서버 리소스 사용량이 급격히 올라갔다.

특히 모든 작업을 동시에 몰아 처리하려고 하면 Jenkins CPU 가 거의 포화 상태가 되었고, 결과적으로

* Jenkins 서버가 불안정해지고
* 배포 자체가 실패하거나 지연되고
* 예상과 달리 전체 소요 시간도 더 길어졌다.

즉, 단순히 병렬 개수를 늘리는 것이 정답이 아니었다.<br>

***

### 왜 느려졌는가

처음엔 단순히 "서버가 많아져서 오래 걸린다"는 문제처럼 보였다.

하지만 실제로는 **배포 대상 서버 수보다 Jenkins 의 처리 방식** 이 더 큰 문제였다.

핵심 원인은 다음과 같았다.

* 빌드와 배포가 한 번에 몰리면서 Jenkins 자원을 과도하게 사용했다.
* 모든 서버를 무작정 동시에 처리하면서 Jenkins CPU 가 병목이 되었다.
* 병렬 처리 수는 늘었지만, Jenkins 가 버티지 못해 오히려 전체 시간이 길어졌다.&#x20;

결국 문제의 본질은&#x20;

**"배포 대상 서버 수 증가"** 자체가 아니라 **"Jenkins 가 감당할 수 없는 방식으로 작업을 몰아넣은 구조"** 였다.

***

### 개선 방향

이 문제를 해결하면서 중요하게 본 건 두 가지였다.

**1. 빌드와 배포 단계를 분리할 것**

**2. 병렬 처리는 하되 Jenkins 가 감당 가능한 단위로 나눌 것**

그래서 Jenkins Pipeline 을 사용해 전체 흐름을 재구성했다.

빌드는 먼저 한 번에 정리하고, 배포는 서버들을 적절한 묶음으로 나눠 병렬 처리하는 방향으로 바꿨다.

핵심은 "최대한 많이 동시에 돌리는 것" 이 아니라,&#x20;

**Jenkins 가 멈추지 않으면서 전체 완료 시간을 줄이는 구조** 를 만드는 것이었다.

***

### 실제 Pipeline 구조

구조는 크게 두 단계였다.

#### 1. 전체 빌드 단계

먼저 공통 빌드 작업을 수행했다.

이 단계에서는 배포에 필요한 산출물을 준비하는 역할을 했다.

#### 2. 서버 배포 단계

배포 서버를 한 번에 20대로 던지지 않고,

적절한 단위로 나눠서 병렬 처리 했다.

예를 들어 1 \~ 10, 11 \~ 20 처럼 그룹을 나누고, 이 그룹 단위 배포를 병렬로 처리하는 방식으로 구성했다.

코드 형태로는 아래와 같은 구조였다.

```groovy
pipeline {
    agent any
    options {
        timeout(time: 3, unit: 'HOURS')
    }

    stages {
        stage('전체빌드') {
            steps {
                build '<빌드용 프로젝트>'
            }
        }

        stage('서버 배포') {
            parallel {
                stage('pipeline_deploy(1~10)') {
                    steps {
                        build 'PIPELINE_DEPLOY(1~10)'
                    }
                }
                stage('pipeline_deploy(11~20)') {
                    steps {
                        build 'PIPELINE_DEPLOY(11~20)'
                    }
                }
            }
        }
    }
}
```

여기서 중요한 건 문법 자체보다도, **서버를 어떻게 나누고 어떤 순서로 병렬화할지 설계한 점** 이었다.

***

### 결과&#x20;

이 구조를 적용한 이우 전체 서버 배포 완료 시간을 크게 줄일 수 있었다.

특히 Jenkins 서버가 CPU 과부하로 멈추는 문제를 줄이면서, 결과적으로 전체 배포 시간도 단축할 수 있었다.

이 경험을 통해 느낀 건 단순했다.

* &#x20;병렬 처리는 많을수록 좋은 게 아니다.
* 배포 속도는 대상 서버 수보다 **중앙 오케스트레이션 서버의 병목** 에 더 크게 좌우될 수 있다.
* CI/CD 에서는 자동화 자체보다도 **병렬 처리 범위와 단계 분리 설계** 가 중요하다.

***

### 배운점

이 작업을 하면서 얻은 교훈은 세 가지였다.

첫째, **무작정 동시에 돌리는 것은 최적화가 아니다.**

둘째, Jenkins 도 결국 하나의 서버이기 때문에 CI/CD 설계에서 병목이 될 수 있다.

셋째, 배포 최적화는 단순 자동화보다 **단계 분리와 병렬 처리 전략** 이 더 중요하다.

결국 이 경험은 Jenkins pipeline 을 써봤다는 경험이라기보다, **배포 규모가 커진 환경에서 Jenkis 병목을 줄이고 전체 배포 구조를 개선한 경험** 이었다.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://wjddustkd45.gitbook.io/organizeme/company-org/ci-cd.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
