도입 배경

기존 프로젝트에서는 마감 기한에 쫓기거나, 코드 구현 자체에 집중해야 하는 상황이 많아 CI/CD 도입을 미루어 왔습니다. 또한 대부분 1인 개발 환경이었기 때문에, 파일질라를 활용한 수동 배포 방식으로도 큰 불편 없이 작업을 진행할 수 있었습니다.

그러나 점핑배틀 외주 프로젝트에서 SSE(Server-Sent Events)를 적용하는 과정에서 문제가 발생했습니다. 로컬 환경에서는 정상적으로 동작하던 기능이 AWS 환경에서는 성능 저하 및 병목 현상이 발생하였고, 이를 해결하기 위해 빈번한 코드 수정과 배포를 반복해야 했습니다.

이 과정에서 수동 배포 방식은 작업 효율을 크게 저하시켰고, 로컬과 서버 환경 간의 반복적인 동기화 과정 역시 비효율적이라는 것을 체감하게 되었습니다.

이에 따라 배포 과정을 자동화하고, 코드 변경 사항을 보다 안정적으로 반영하기 위해 CI/CD 파이프라인 도입을 결정하게 되었습니다.

또한 기존에 사용해보았던 zappa의 경우, 배포 자동화 측면에서는 편리했지만 배포 시간이 길고 AWS Lambda 환경에 종속된다는 한계가 있었습니다. 이번 프로젝트는 EC2 환경에서의 유연한 운영이 필요했기 때문에, 특정 플랫폼에 종속되지 않으면서도 빠르고 안정적인 배포가 가능한 CI/CD 방식을 선택하게 되었습니다.

설계

Spring 기반 애플리케이션은 Flask에 비해 상대적으로 높은 메모리 사용량과 초기 구동 비용이 발생하기 때문에, 제한된 EC2 환경에서 안정적으로 운영하기 위한 구조를 먼저 고민하였습니다.

특히 단일 서버에 모든 구성 요소를 함께 배치할 경우, 트래픽 증가나 부하 상황에서 애플리케이션과 데이터베이스가 서로 영향을 주며 성능 저하가 발생할 수 있다고 판단했습니다.

이에 따라 애플리케이션 서버와 데이터베이스 서버를 분리하여 각각의 역할을 독립적으로 운영하는 구조를 선택하였습니다. 이를 통해 서버 간 리소스 간섭을 줄이고, 향후 확장성과 안정성을 확보하고자 하였습니다.

또한 배포 환경의 일관성을 유지하고, EC2 환경에서도 동일한 실행 환경을 보장하기 위해 Docker를 도입하였습니다. 이를 통해 개발 환경과 운영 환경 간의 차이를 최소화하고, 컨테이너 단위로 서비스를 관리할 수 있도록 설계하였습니다.

CI/CD 도구 선정 및 코드 작성

본 프로젝트는 개인 사이드 프로젝트이지만, CI/CD 환경을 실제로 구축하고 운영하는 경험을 얻는 것을 목표로 하였습니다. 이에 따라 별도의 서버 구축과 관리가 필요한 Jenkins 대신, 레포지토리와의 높은 통합성과 간편한 설정이 가능한 GitHub Actions를 선택하였습니다.

GitHub Actions를 활용함으로써 코드 변경 시 자동으로 빌드 및 배포가 이루어지는 파이프라인을 구성할 수 있었고, 별도의 인프라 관리 없이도 CI/CD 환경을 구축할 수 있었습니다.

또한 안정적인 배포를 위해 브랜치 전략을 함께 설계하였습니다.

브랜치 전략

초기에는 devmaster 브랜치만을 활용하였으나, 테스트 과정에서 개발 중인 기능과 안정적으로 동작하는 코드가 혼재되면서 배포 기준이 모호해지는 문제가 발생했습니다.

이에 따라 중간 검증 단계를 명확히 하기 위해 stage 브랜치를 추가하였으며, 다음과 같은 흐름으로 브랜치를 운영하였습니다.

  • dev: 기능 개발 및 테스트
  • stage: 통합 테스트 및 배포 전 검증
  • master: 안정적인 운영 코드

개발된 기능은 dev에서 테스트 후 stage로 병합하여 전체 흐름을 검증하고, 최종적으로 안정성이 확보된 경우에만 master로 배포하는 구조를 채택하였습니다.

이를 통해 기능 단위의 개발 상태를 명확하게 구분할 수 있었으며, 배포 안정성을 높이고 코드 관리의 가시성을 개선할 수 있었습니다.

결과

CI/CD 파이프라인 도입 이후, 수동 배포에 비해 배포 시간이 단축되었고 코드 변경 사항을 보다 빠르게 반영할 수 있게 되었습니다.

또한 반복적인 배포 과정에서 발생하던 실수를 줄이고, 개발과 배포를 분리함으로써 보다 안정적인 운영 환경을 구축할 수 있었습니다.

댓글남기기