우리 프로젝트에서 최종적으로 결정하고 구성한 아키텍처이다. 지금부터 이 아키텍처를 배포할 때 어떤 전략을 통해서 배포하였는지 그렇기에 어떤 점을 고려했는 지 정리해보자 한다.
아키텍처에 맞게 띄워진 DOCKER이다. 하나의 EC2안에 전부 띄웠기 때문에 이렇게 구성된 것을 확인할 수 있다.
solsol-shop/
├── Dockerfile
├── app.jar
├── .env
└── docker-compose.yml
각 마이크로서비스가 독립적인 컨테이너로 패키징되어 개별 배포가 가능하다.
# 브랜치별 자동 배포 트리거
rules:
- if: '$CI_COMMIT_BRANCH == "back/stock/main"' # 재고 서비스
- if: '$CI_COMMIT_BRANCH == "back/pay/main"' # 결제 서비스
- if: '$CI_COMMIT_BRANCH == "back/shop/main"' # 쇼핑 서비스
- if: '$CI_COMMIT_BRANCH == "back/orchestrator/main"' # 오케스트레이터
stages:
- deploy # build + deploy를 한 Job에서 처리
image: gradle:8.9.0-jdk21 # Java 21 + Gradle 8.9
script:
- cd $SERVICE_DIR
- chmod +x gradlew
- ./gradlew clean bootJar --no-daemon # 데몬 없이 깨끗한 빌드
- cp build/libs/*.jar $APP_JAR # 표준화된 JAR 이름
--no-daemon: 으로 CI 환경에서 메모리 효율성
clean bootJar: 의존성 충돌 방지
모든 서비스에서 app.jar로 통일
Docker Compose 기반 Rolling Update
# 서버에서 실행되는 배포 명령
ssh ${EC2_USER}@$EC2_HOST "
cd /home/${EC2_USER}/solsol-stock &&
docker compose build app && # 새 이미지 빌드
docker compose up -d --no-deps --force-recreate app # 무중단 교체
"
Git Push -> GitLab CI 트리거가 발동 -> Gradle 빌드 -> JAR 생성 -> SCP 업로드 -> Docker 이미지 빌드 -> 컨테이너 교체 -> 헬스체크
--no-deps : 의존 서비스 영향 없음
--force-recreate : 새 컨테이너로 완전 교체
Docker 네트워크 : 기존 연결 유지
git push origin back/stock/main
script:
- cd $SERVICE_DIR
- chmod +x gradlew
- ./gradlew clean bootJar --no-daemon
- cp build/libs/*.jar $APP+JAR
scp -o StrictHostKeyChecking=no $APP_JAR ubuntu@j13a106.p.ssafy.io:/home/ubuntu/solsol-stock/app.jar
ssh ubuntu@j13a106.p.ssafy.io "
cd /home/ubuntu/solsol-stock &&
docker compose build app &&
docker compose up -d --no-deps --force-recreate app
"
# 배포 후 자동 헬스체크
curl -f http://j13a106.p.ssafy.io/api/stock/actuator/health
사실 Rolling Update 가 무중단이라고 하였지만 완전한 무중단은 아니다.
완전한 무중단 배포인 Blue-Green 방식에 대해서 소개하고 오해가 생김을 막고자 한다.
Rolling Update는 그냥 동일한 포트에서 돌아가고 있던 컨테이너를 SIGTERM 신호를 통해 중지하고, 새 컨테이너를 즉시 시작한다.
그렇기에 다운타임이 약 2~3초 정도 생긴다. (컨테이너 교체시간)
하지만 Blue-Green 방식은 Blue(현재) 환경이 존재하는 채로 Green(새로운) 환경을 새로 배포한 후 Nignx 설정 변경으로 트래픽을 전환한다.
이렇게 전환하기에 다운타임이 0초 완전 무중단을 할 수 있다. 하지만 메모리, CPU, 포트 모두 2배가 필요하다.
무중단 배포 아키텍처(Zero Downtime Deployment)- 글로벌 서비스 운영의 필수 요소
MSA이기 때문에 전체 가용성 측면으로 Blue-Green이 필요한 이유가 크게 와닿지 않았다.
또한 SAGA 패턴을 적용해서 서비스 일시 중단 시 분산 트랜잭션의 ACID 속성을 유지시켰습니다.
운영 효율성에서도 빠른 배포 속도와, 단순한 롤백을 통해서 개발하기 훨씬 편하여 선택하지 않았다.
트래픽이 1000TPS가 나오거나, 인프라 리소스가 충분하다거나, 완전 무중단이 비즈니스 크리티컬 해질 때, 또한 DevOps 팀이 확장된다면 도입해야할 거 같다!