Published on

Cl/CD란?

Authors
  • avatar
    Name
    zkrp
    Twitter

이번에 서비스를 혼자 운영하면서 가장 번거롭게 느꼈던 부분이 바로 배포 과정의 반복 작업이었습니다. 새로운 코드를 적용할 때마다 매번 docker build --platform linux/amd64 -t ...docker push ... 명령어를 직접 입력하고, 이후 서버에 직접 접속해 도커 이미지 버전을 수정한 뒤 컨테이너를 재기동해야 했습니다. 이런 과정을 한두 번 할 때는 괜찮지만, 개발과 운영을 반복하다 보면 같은 명령을 수십 번 입력하게 되고, 사소한 실수로 인해 장애가 발생하기도 했습니다.

이렇듯 도커 빌드와 푸시, 서버 접속 및 배포 버전 조정 등 모두 수작업으로 처리하다 보니 일관성이 깨지고, 작업 효율도 떨어지며, 실수의 위험도 커졌습니다. 이런 반복적이고 오류에 취약한 작업을 자동화하면 어떻게 달라질지 궁금해졌고, 자연스럽게 CI/CD의 필요성과 그 구현 방법에 관심을 갖게 되었습니다.

이러한 계기로  CI/CD(지속적 통합/지속적 배포)에 대해 본격적으로 공부하는 김에 블로그를 작성하려합니다.

설명

우선 CI에 대해 작성하겠습니다

1. CI (Continuous Intergation)

정의

지속적인 통합

CI는 개발자가 새로운 코드 변경 사항을 일정한 주기로 공용 저장소(메인 레포지토리)에 병합하고, 그때마다 자동으로 빌드와 테스트가 실행되어 코드의 품질과 일관성이 유지되도록 돕는 개발 방식입니다.

  • 버그 수정이나 새로운 기능 개발 등 각자의 작업물이 수시로 메인 레포에 통합되고, 이 과정에서 자동화된 컴파일,테스트,품질, 보안 검증이 머신에 의해 즉각적으로 수행
  • 코드 변경이 발생할 때마다 자동으로 테스트를 수행하여 빌드 실패와 버그를 조기에 발견할 수 있도록 도움
    • A 개발자의 코드 변경으로 인해 B 개발자의 기능에 오류가 발생했다면, CI 덕분에 이를 조기에 인식하고 문제를 신속히 해결

즉 CI를 통해 다양한 테스트와 자동 검증이 일상적으로 돌아가며, 문제가 생기면 곧바로 피드백을 받을 수 있습니다

CI 에서 일반적으로 수행되는 테스트는 다음과 같습니다.

1-1) 테스트 종류

레벨무엇을 검증?특징Spring Boot에서의 대표 어노테이션·도구
단위(Unit) 테스트“한 메서드·클래스의 순수 로직- 초고속&경량- 외부 의존(Mock·Stub) 격리@ExtendWith(MockitoExtension.class)@Mock / @InjectMocks
통합(Integration) 테스트“여러 Bean·레이어가 함께 잘 동작하는지 검증”- 스프링 컨텍스트 or 실제 DB/포트 사용- 속도 ⬆, 신뢰도 ⬆@SpringBootTest (+ Testcontainers)@Transactional
성능테스트서비스가 얼마나 많은 사용자와 데이터를 원할하게 처리할 수 있는지 검증- 동시에 1000명의 사용자가 접속해도 서비스가 잘 작동하는지, 대용량 파일 업로드 시 시스템이 버티는지, 검색 결과가 기준 시간 이내에 표시되는지 등을 테스트Selenium, Playwright 등

CI/CD 환경에서는 이러한 모든 테스트가 자동으로 실행이 됩니다.만약 어느 하나라도 테스트를 통과하지 못하면 해당 코드는 실제 서비스에 반영되지 않습니다.

하지만 여기서 의문이 들었습니다. 

CI/CD 환경에서는 모든 테스트가 자동으로 실행되며, 하나라도 통과하지 못하면 해당 코드는 서비스에 반영되지 않습니다. 그런데 문득 이런 생각이 들 수 있습니다.

"굳이 CI 서버에서 또 빌드하고 테스트하지 말고, 그냥 내 PC에서 빌드 완료하고 커밋하면 끝 아닌가?"

저 역시 비슷한 고민을 했지만, CI를 도입할 수밖에 없는 본질적 이유는 아래와 같았습니다.

1-2) 로컬에서 빌드했는데도 CI에서 다시 돌리는 이유

  1. 재현성(Determinism)
    • 예: 내 PC JDK 17.0.11, 동료 PC JDK 17.0.4처럼 각자 환경이 다르면 내 컴퓨터에선 잘 되지만 서버에선 실패할 수 있습니다.
    • CI는 표준화된 환경(예: Docker 컨테이너, 고정된 OS/런타임)에서 항상 동일하게 실행하므로, 환경차로 인한 예기치 않은 오류를 예방합니다.
  2. 동시성
    • 여러 명이 같은 날 10개 PR 올리면 테스트 순서·의존성 충돌이 생길 수있습니다.
    • 중앙의 CI 서버가 이를 통제하며, 모든 변경이 함께 테스트되어 문제를 조기에 잡아낼수 있습니다.
  3. 보호장치(Guardrail)
    • Branch Protection: CI의 모든 테스트가 성공해야만 자동 머지를 허용합니다. 이를 통해 코드 품질을 강제적으로 유지할 수 있습니다.
  4. 이력과 지표
    • PR별로 테스트 기록, 코드 커버리지 등을 지속적으로 누적하고 추적할 수 있습니다
구분의미 PC**에서** 빌드 & 커밋CI 서버 환경
트리거실행 계기직접 테스트 실행 (./gradlew test)Git Push/PR 생성 시 자동 실행
환경실행 환경각자 IDE, OS, JDK, 캐시 등 제각각표준화된 컨테이너/클라우드 러너/깨끗한 OS
동시성여러 빌드 처리개별 실행, 충돌 미탐지PR간 의존성/충돌 자동 검증
결과 처리성공/실패 관리본인만 확인, 관리 어려움PR마다 PASS/FAIL 첨부, 자동 머지 차단
가시성로그와 통계개인 PC에만 결과 존재대시보드에 축적, 모두 히스토리 공유

이처럼 CI를 도입하면 누구나 언제 어디서나 동일하게 동작하는 자동화된 품질 검증 체계를 만들 수 있어 협업과 서비스 운영의 신뢰성이 크게 높아집니다.

다음은 CD에 대해 설명하겠습니다.

2. CD(Continuous Delivery & Continuous Deployment)

CD는 지속적인 서비스 제공 혹은 지속적인 배포를 뜻합니다.

즉 지속적인 배포를 통하여 실제 사용자가 사용하는 환경까지 전달할 수 있게 만드는 자동화된 프로세스입니다.

여기서 Continuous Delivery 는 검토하고나서 수동적으로 배포란 의미입니다.

  • 배포할 수 있을 정도로 검증·패키징된 아티팩트를 항상 준비해 두는 단계입니다.
    • 실제로는 테스트와 빌드, 패키징까지는 자동화하고, 최종 운영 배포 단계만 사람의 검토나 승인 후 수동으로 진행하는 방식입니다.
      → main 브랜치 머지  -> staging까지 자동 push

여기서 Continuous Deployment는 자동화를 통하여 최종 운영까지 곧바로 배포를 진행하는것을 뜻합니다.

  • 검증이 끝난 아티팩트를 실서비스(Prod)까지 자동으로 실제 배포하는 단계
  • 별도의 승인 없이 자동으로 실제 운영 서버에 배포됩니다.

CD를 사용하면 다음과 같은 장점이 있습니다.

2.1) CD의 장점

1. Lead Time 단축

  • 새로운 기능이나 버그 픽스가 개발 완료된 후, 실제 서비스(프로덕션)에 적용되기까지 걸리는 시간이 대폭 줄어듭니다.
  • 즉 "개발이 끝났는데 검토, 수동 배포 등으로 며칠을 대기하는 지연" 대신, 자동화된 CD 덕분에  몇분 내 서비스에 바로 적용할 수 있습니다.

2. 사람 실수 예방

  • 배포 과정에서 사람이 직접 쉘을 치고, 버전 입력하거나 클릭하는 수동 작업이 사라집니다.

2. 릴리즈 당 위험성 감소

  • 한번에 대량의 변경을 쌓아두고 배포하면, 문제 발생 시 범위도 커지고 ,롤백도 번거롭습니다.
  • CD는 작고 자주 배포가 가능하게 해 주므로, 문제가 발생해도 영향 범위가 적습니다.

이렇게 해서 CI/CD를 도입하면 제가 직접 겪었던 수동 배포의 번거로움과 반복 작업을 효과적으로 해소할 수 있다는 점을 알게 되었습니다.

이어지는 게시글에서는 실제 서비스에 CI/CD를 적용한 방법과 실전 경험을 공유드리겠습니다.

읽어주셔서 감사합니다!!