이번 글에서는 초기 스타트업에서 서버 인프라 설계 및 배포 자동화 했던 경험을 정리하고, 개선 방향을 다룰 예정이다.
우선 간단히 프로젝트 환경에 대해서 소개하자면, 프로젝트 초기에 도커 (+ 도커 컴포즈)를 활용하여 모든 컴포넌트 (Nginx, FE, BE, DB) 가 하나의 인스턴스에서 구동되도록 했다. 비용적으로는 여러 스타트업 지원 사업으로 여러 인스턴스를 확보할 수 있었지만(NCP, AWS 등), 가장 간단한 구조
에서 의도한 기능이 동작하는 지 확인하기 위해 우선 위와 같은 환경을 구성하게 됐다.
인스턴스는 크게 3 가지 그룹으로 구분해서 CI Server (Jenkins, Docker Registry), 테스트 서버, 그리고 배포 서버로 구성 했다. Dev
, Prod
인스턴스는 완전히 동일한 환경으로 구성 해서 초기에 Dev
인스턴스에서 테스트를 진행 한 뒤 Prod
에서 배포를 진행하는 식으로 활용했다.
위 과정에서 핵심으로 생각 했던 부분은, 가장 간단한 구조와 개발 환경의 유사성이었다. 서버 인프라 구축과 배포 자동화 등 경험이 거의 전무 했던 입장에서 Fail Point
를 최대한 줄이는 것이 가장 주요 하다고 판단 했었고 지금 생각해도 다른 팀에서 공개한 서비스 인프라 따라하려고 처음부터 무리 했으면 오히려 시작도 못했을 것이라고 생각한다.
로컬 개발 환경에서 Dev
인스턴스 서버로 배포되는 과정을 확인해보자. 아래 과정은 Jenkins Server 를 통해 자동화되어 있다.
(백엔드 기준) 로컬 개발 환경에서 기능 구현이 끝난 뒤 새로 구현한 기능과 이전 개발 내역을 모두 테스트를 한 뒤 모든 테스트가 통과되면 (혹은 일정 기준 이상 충족) dev
브랜치로 PR
을 생성한 뒤 머지가 되면 webhook
을 통해 Jenkins Server 내 pipeline
이 시작시킨다.
pipeline
내 작업을 순차적으로 수행하는데, 가장 먼저 업데이트된 소스 코드 내역을 불러온 뒤 빌드 테스트, 테스트를 순차적으로 진행하고 모든 태스크가 완료 되면 도커 컴포즈 빌드를 진행한다. 도커 컴포즈 빌드를 통해 생성된 이미지들은 private docker registry
로 push
한다.
그 이후 빌드 스크립트를 실제 서비스를 배포할 서버에 ssh
를 통해 전송한 뒤 해당 파일을 실행시킨다. 그리고 마지막으로 빌드 스크립트에서 docker registry
로 부터 도커 이미지를 pull
받은 뒤 docker-compose up -d
를 통해서 서비스를 구동한다.
Testcontainers is a Java 8 library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.
[ 그림 4 ] 에서 ② 과정에서 BE Test
는 TestContainer
를 통해 수행하도록 했는데, 실제 배포 환경이 MySQL
컨테이너를 띄워서 서비스하는 형식이다 보니 배포 환경의 복제 형태인 개발서버에 배포 하는 과정에서도 동일한 환경을 구성하기 위해 로컬 DB, In-Memory DB 등을 사용하지 않고 도커 컨테이너 기반의 DB 방식을 사용했다.
반면, 로컬 개발 환경에서는 애플리케이션 내 테스트 항목이 많아 짐에 따라 In-Memory DB 인 H2를 사용해서 효율성을 높였다. 로컬 테스트 이후, CI 과정에서 수행하는 테스트까지 통과한 뒤에 개발서버에 반영되는 구조라서 로컬 환경에서 위와 같은 선택을 하게 됐다.
TestContainer
의 특징과 DB 초기화 및 시드 데이터 운영 등 활용 시 필요한 설정에 대해서는 별도의 토픽으로 다룰 예정이다.
개선 방향을 잡기 위해서는 객관적인 근거가 필요하다고 생각하는데, MVP 베타 런칭 후 10일 간 접속량을 봤을 때 당장 우선적으로 Nginx 로드 밸런싱 + WAS 스케일 업 또는 DB 고가용성 등의 성능을 끌어올리는 것 보다는 앞으로 많은 유입을 대비해 수평적 규모 확장
에 용이한 구조로 변경하는 것이 필요하다고 생각했다.
[ 그림 1 ] 에서 Nginx 서버 (프록시 서버)와 FE, BE + DB 이렇게 세 개로 우선 분리한 뒤 그 이후에 성능을 끌어 올리기 위해 Nginx 로드 밸런싱 + Spring WAS 스케일 업
그리고 DB Replication
등을 고려하고 있다.
백엔드 자체적으로는 정적 분석
툴을 활용하여 코드 커버리지 등 객관적인 지표 값을 근거를 활용한 코드 관리 및 배포 과정에서 정적 분석 결과 기준에 부합하지 않은 경우 PR 머지가 안 되도록 함으로써 보다 안정적인 배포 자동화 과정을 구축 할 예정이다.