본문 바로가기
팀 프로젝트/최종 프로젝트

배포(3) 무중단 배포: 롤링 vs 블루-그린(https 배포완료)

by pon9 2025. 2. 16.

무중단 배포란 말 그대로 새 버전과 새 기능을 추가할 때 서비스 중단 없이 매끄럽게 업데이트되게끔 하는 걸 의미한다.

Rolling, Blue-Green, Canary, Shadow 이렇게 총 4개의 전략을 찾아볼 수 있었고,

그림자는 고려사항이 너무 많고, 카나리와 블루-그린은 유사해서 오늘은 롤링과 블루/그린에 대해 알아보고, 내 서비스에 알맞은 무중단 배포 방식을 고르고 적용해보자

 

Rolling

전체 인스턴스를 한꺼번에 바꾸는 게 아니라, 조금씩 순차적으로 새로운 버전으로 교체하는 방식이다.

일부 인스턴스만 업데이트되므로 전체 서비스가 중단되지 않는다. 

 

업데이트 도중에 문제가 발생하면, 문제 있는 인스턴스만 롤백 가능하고 별도의 환경을 준비할 필요 없이 현재 인프라에서 순차적으로 배포 가능하다는 장점이 있다.

 

단점으로는 신버전 배포 중에 구버전과 신버전이 같이 운영돼서, 버전 간 호환성 문제나 예상치 못한 이슈가 생길 수 있다.

또한 업데이트 중에 각 인스턴스의 상태를 꼼꼼히 모니터링해야 해서 관리가 까다로울 수 있다.

일부 서버는 신버전, 일부는 구버전이라 성능이나 응답 속도에 차이가 날 가능성도 있고,

트래픽 분배나 세션 관리에서 신경써야 할 부분들이 있다.

 

 

Blue-Green

구버전은 블루,신 버전은 그린으로 생각하면 된다. 현재 운영중인 블루에 구버전이 돌고 있을 때, 신버전은 그린에 배포된다.

신버전이 충분히 검증되면 트래픽을 한꺼번에 그린으로 전환해서 배포를 완료한다.

 

신버전을 그린에서 모든 테스트를 마치고 트래픽을 전환하므로, 예기치 못한 문제가 발생할 확률이 낮다.

문제가 생기면 트래픽을 다시 블루로 빠르게 돌릴 수 있다.

롤링과 다르게 신버전이 완벽히 준비된 환경에서 운용되므로, 모든 사용자에게 동일한 응답속도와 성능을 제공할 수 있다.

배포 전 별도의 환경(그린)에서 최적화와 부하 테스트를 진행할 수 있어서 실제 트래픽에 들어가기 전에 성능 문제를 발견할 수 있다.

 

하지만 두 개의 환경을 동시에 운영해야 하므로 인프라 비용이 많이 들 수 있다.

사용하지 않는 환경(그린)이 항상 대기 상태에 있으므로 리소스가 효율적으로 사용되지 않을 수 있다.

 

 

우리 프로젝트에는? 롤링!

롤링으로 하자! 규모가 작은 서비스이기도 하고, api가 크게 달라진다거나 하는 호환성 이슈는 없지 않을까?

블루-그린은 두 환경을 동시에 유지해야 해서 초기 인프라 설정 비용이 만만찮을 것이다.

포트 두 개로 사용한다면 배포 도중 서버가 터질 거고, 인스턴스가 두개라면 ... 감당하기 힘들듯.

 

그리고 롤링은 모니터링이 중요한 방법이니 그만큼 경험도 많이 쌓을 수 있을 것 같다!

 

1. ec2 인스턴스를 조금씩 업데이트 하면서, 로드밸런서(ALB)가 트래픽을 정상 인스턴스로만 보내게 설정하자

2. 오토스케일링 그룹(ASG)을 활용해 배포 중에도 항상 일정 개수의 인스턴스가 서비스 가능하도록 유지하자

3. 각종 모니터링, 최적화 툴을 이용해 서비스를 안정적으로 유지해보자

 

 

ASG와 ALB란?

ASG(Auto Scaling Group)은 ec2 인스턴스를 자동으로 관리하는 aws 기능이다.

트래픽 증가, 배포 시 인스턴스 교체 등 특정 조건에 따라 인스턴스를 자동으로 추가하거나 제거할 수 있다

롤링 업데이트를 하려면 ASG가 필수다

 

ALB(Application Load Balancer)는 어플리케이션 계층의 로드밸런서다. 여러 개의 asg에 속한 ec2인스턴스로 들어오는 트래픽을 자동으로 분배해준다.

특정 인스턴스가 다운되면 다른 정상 인스턴스로 트래픽을 보내기 때문에 무중단 배포가 가능하다

ASG와 ALB를 사용한 롤링 업데이트 아키텍처 다이어그램을 그려보면 대략 이런 느낌이다.

ASG가 unhealty한 인스턴스를 자동으로 새 인스턴스로 교체하여 재구성하고, 이것이 ASG의 자동 복구 프로세스이다.

업데이트 시에도 마찬가지로 순차적으로 구버전 인스턴스를 종료하고 새 버전으로 바꾼다

 

ALB가 healty한 인스턴스만 선택해서 트래픽을 보내주기 때문에, 헬스체크 통과 여부가 트래픽 분배를 결정하는 기준이 된다.

헬스체크는 actuator의존성을 추가해서 /actuator/health로 요청을 보내면 200응답에 추가로 json {status:UP}을 서버에서 반환한다.

//healthcheck
implementation 'org.springframework.boot:spring-boot-starter-actuator'

 

 

얼떨결에 https 배포했다

현재시간 새벽2시 배포완료 도메인까지 샀다 ..

 

ALB와 AGS 설정하는 글 작성하다가 생긴 흐름: 스샷 여러 장 찍어 올리다가 너무 길어져서 포기함

ALB를 하려면 ASG가 필요하구나

-> 롤링 업데이트를 하려면 시작 템플릿을 지정해줘야되는구나, 쉘스크립트나 써야지

-> 어라 도메인? 살수있어? 이참에 사야지

-> 크롬에서 자꾸 막히네 https 열어야겠다

-> 끝남

...

https://velog.io/@cyseok123/AWS-EC2-HTTPS-%EB%A1%9C%EB%93%9C%EB%B2%A8%EB%9F%B0%EC%84%9C

 

[AWS] EC2 인스턴스에 HTTPS 및 로드밸런서 적용하기

Certificate Manager 검색AWS Certificate Manager(ACM)

velog.io

이 글이 많은 도움이 되었다..

요번에 aws맡으면서 느낀 건 이런 인프라적인 부분은 ai보다 구글링이 훨씬 도움된다.

아무튼 https 배포는 저 글 보면서 천천히 따라했고, www를 빼먹어서 추가하지 않은 채로 하다가 몇시간 삽질했다

인프라쪽 삽질은 해도 별로 화가 안나는게 하면 할수록 아는게 늘어서 좋다

 

 

롤링 업데이트 세팅

롤링 업데이트를 하려면 asg 설정에서 '시작 템플릿' 을 구성해줘야한다.

시작 템플릿이란 asg에서 비정상 인스턴스를 종료하거나, 어플 버전이 업데이트가 되면 조건(사용자가 지정한 최소-최대 용량에 따라) 새로 인스턴스를 생성하게 되는데 이 때 이 시작 템플릿을 사용한다.

시작 템플릿은 수정될 때 마다 버전이 업데이트 되는 구조다.

버튼을 누르면 여러가지 설정들이 나오는데, 인스턴스 설정은 평소 생성할 때와 같고 맨 아래쪽 '고급 세부 정보' 탭을 열면 다시 맨 아래에

사용자 데이터라고 쉘 스크립트를 적어주는 칸이 있다. 나의 경우 ami를 우분투로 설정했기 때문에 리눅스 쉘스크립트를 작성해줬다.

내가 리눅스 명령어를 잘 몰랐다면.. 어우 끔찍해

(그러나 맥북 숙련도 이슈로 무식하게 복사붙여넣기를 했다..)

 

우분투 24LTS면 docker-ce가 안 되고 docker.io로 설치해야 한다

#!/bin/bash
#패키지 목록 업데이트 & 필수 패키지 설치
sudo apt update -y
sudo apt install -y ca-certificates curl gnupg lsb-release

#도커 설치
sudo mkdir -m 0755 -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo tee /etc/apt/keyrings/docker.asc > /dev/null
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update -y
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

#도커 자동실행 설정
sudo systemctl start docker
sudo systemctl enable docker

#sudo 도커 권한 부여
sudo usermod -aG docker ubuntu

#도커컴포즈 설치
DOCKER_COMPOSE_VERSION=$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
sudo curl -L "https://github.com/docker/compose/releases/download/v${DOCKER_COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

#도커 로그인
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin

#cheerha 디렉토리 생성
mkdir -p ~/cheer-ha

#환경변수 파일 생성
echo "$ENV_FILE" > ~/cheer-ha/.env

#도커컴포즈 파일 생성
cat <<EOF > /home/ubuntu/cheer-ha/docker-compose-release.yml
--컴포즈 파일 내용--
EOF

#컨테이너 실행
docker-compose -f ~/cheer-ha/docker-compose-release.yml down
docker pull lcyoun9/cheer-ha:latest
docker-compose -f ~/cheer-ha/docker-compose-release.yml up -d --force-recreate

그런데 허브에서 이미지를 가져올 때, 항상 최신 이미지만 가져와야 하는데 자꾸 예전 이미지를 가져와서 방법을 좀 찾아야한다.

 

github actions cd.yml 설정도 기존과 많이 다르다. 기존에는 deploy시 단순히 도커 허브에서 이미지를 받아 컨테이너를 실행했다면,

steps:
  - name: Configure AWS credentials
    uses: aws-actions/configure-aws-credentials@v2
    with:
      aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }}
      aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }}
      aws-region: ap-northeast-2

  - name: Trigger ASG Rolling Update
    run: |
      aws autoscaling start-instance-refresh --auto-scaling-group-name cheerha-asg

aws에 직접 로그인해서 현재 오토스케일링 그룹에 있는 인스턴스를 가져와서 접속하는 방식이다.

이때 aws에 접근하기 위해 iam 생성이 필요하며, ec2의 경우 ec2 full access 권한을 주면 된다.

 

이제 딱 이정도만(?) 하면 주기적으로 모니터링만 하면 되고.. 배포가 끝이 보인다!

얼른 다 하고 모니터링 주기적으로 해주면서 팀원들 개발 고도화를 도와야겠다.