서버 이중화의 필요성
- 무중단 서비스 제공
- 하나의 서버에 장애가 발생해도 다른 서버로 연결이 가능함.
- 부하 분산
- 로드 밸런서를 통해 여러 서버로 부하를 분산시킬 수 있음.
로드밸런서란?
클라이언트 요청을 여러 서버로 분산시켜주는 중간 장치
주요목적
- 가용성 : 특정 서버 장애 시 다른 서버가 요청 처리.
- 확장성 : 서버 대수를 늘려 트래픽 급증에 대응.
- 성능 최적화 : 과부하를 방지해 응답 속도 유지.
무중단 배포 방식의 필요성
- 서비스 연속성 유지
- 배포 중에도 사용자 요청을 처리할 수 있어, 서비스 이용경험을 최대화 시킬 수 있음.
- 비즈니스 손실 최소화
- 짧은 다운타임도 거래 실패, 수익 손실로 이어질 수 있음.
- 안정적 롤백 및 단계적 배포
- 문제가 발견되면 신속하게 이전 버전으로 되돌릴 수 있음.
- 운영, 유지보수 편의성
- 배포 전용 시간을 따로 잡지 않아도 되어, 스케줄에 구애받지 않고 배포가 가능하다.
- 자동화/ci/cd 파이프 라인 강화
- 배포 자동화 수준이 높아지므로, 코드품질 향상으로도 이어진다.
- 반복 가능한 배포 프로세스가 정립되어, 실수로 인한 인프라 설정 오류나 누락을 예방할 수 있다.
- 고객 신뢰 확보
- 사용자 입장에서는 항상켜져 있는 안정적인 서비스가 좋은 인상을 남긴다.
무중단 배포의 방식은 몇개가있는가
1. 블루-그린(Blue-Green) 배포
- 개념:
- 운영 중인 ‘Blue’ 환경과 새로운 버전을 배포할 ‘Green’ 환경을 동일한 스펙으로 별도로 운영
- Green 환경 검증 후 로드밸런서 설정만 바꿔(트래픽 스위칭) 전환
- 장점:
- 배포 전후 환경이 완전히 분리되어 있어, 문제가 생기면 즉시 롤백(Blue로 재전환) 가능
- 테스트·검증→전환 과정이 명확
- 단점:
- 동일 사양의 리소스를 두 벌 운영해야 하므로 비용 증가
- 데이터베이스 스키마 변경 시 동기화가 까다로울 수 있음
2. 카나리(Canary) 배포
- 개념:
- 신규 버전을 소수의 사용자(예: 5~10%)에게만 먼저 배포하여 안정성 검증
- 이상 없으면 점진적으로 트래픽 비율을 늘려 전체 롤아웃
- 장점:
- 장애 확산 범위를 초기에 차단 가능
- 실사용 데이터 기반 안정성 검증
- 단점:
- 점진 배포를 위한 트래픽 조절 로직 구현 필요
- 롤아웃 기간 동안 Blue/Green보다 운영 복잡도 증가
3. 롤링(Rolling) 업데이트
- 개념:
- 서버 풀(pool)을 N개 배치했을 때, 일정 단위(예: 1대씩)로 순차 교체
- 각 교체 시점마다 로드밸런서에서 제외 후 배포→재등록
- 장점:
- 전체 서버가 동일한 환경으로 점진 전환되어 리소스 낭비 없음
- 배포 속도가 빠르고 비용 효율적
- 단점:
- 롤백 시 이미 교체된 서버 수만큼 되돌려야 하므로 복구 복잡
- 짧은 시간이라도 특정 서버만 구버전 동작 → 버전 불일치 가능성
어떻게 적용했는지
- 기존 인스턴스를 2개로 먼저 만들기 (오토 스케일링 그룹에서 min/max 를 2로 고치면 된다.)
- 이때 인스턴스 2개로 분산이 잘 되는지 로드밸런스 확인 한번 해주기.
- 그리고 min/max를 2로 고치고 0으로 고치고 왓다갓다 테스트 해보기. 이때 0으로 고칠때 적용이 안되면 일시 중지된 프로세스(ReplaceUnhealthy, HealthCheck, Terminate) 이렇게 넣어보고, 그래도 안되면 다시 해당 프로세스 뺀 다음에 0으로 고치고 적용해보기. 약간 반영이 느릴 수 있음.
- 오토스케일 그룹을 하나 더 만들어서 인스턴스를 2개 더 추가해야함
- 이때 그러면 총 인스턴스가 4개가 되어있는 상태.
- 즉 오토스케일링 그룹이 2개이고 각각 2개씩 인스턴스를 가진 상황임.
- 이렇게 해야하는 이유가 타겟그룹을 통해 왓다갓다 하면서 가중치를 부여하기 위함.
- 기존 타겟그룹의 설정을 참고하여 green용으로 하나 더 만들기.
- 기존 타겟 그룹에서 green이라는 이름을 붙여서 하나 더만들기.
- 타겟 그룹은 로드밸런서 타기 전에 가중치 0/1 을 주게 되면서 그린 타겟과 블루 타겟을 왓다갓다 하는 용도임.
- 기존 로드밸런서에 새로 생성한 타겟그룹을 붙이기.
- 리스너 편집을 통해 대상그룹을 하나 더 추가한다.
- 아래 사진을 참고

위 작업을 마치면 아래 사진처럼 보인다.

추가적으로 code deploy에 들어가서 해당 설정에 오토스케일링 그룹을 추가해주어야함.


배포스크립트 설명
Step 1: CodeDeploy로 배포 시작
text- name: Deploy with CodeDeploy
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: |
deployment_id=$(aws deploy create-deployment \\
--application-name ${{ env.APPLICATION_NAME }} \\
--deployment-group-name ${{ env.DEPLOYMENT_GROUP_NAME }} \\
--file-exists-behavior OVERWRITE \\
--s3-location bucket=${{ env.S3_BUCKET_NAME }},bundleType=zip,key=${{ env.ZIP_FILE_NAME }} \\
--query 'deploymentId' --output text)
echo "DEPLOYMENT_ID=$deployment_id" >> $GITHUB_ENV
- CodeDeploy를 통해 S3에 업로드한 zip 파일로 배포를 시작
- 생성된 deployment_id를 환경변수로 저장
Step 2: 배포 완료 대기
text- name: Wait for deployment to complete
run: |
aws deploy wait deployment-successful --deployment-id ${{ env.DEPLOYMENT_ID }}
- CodeDeploy 배포가 성공적으로 완료될 때까지 대기합니다.
Step 3: 현재 Prod/Stage TG/ASG 결정
text- name: Determine current Prod and Stage TG/ASG
run: |
PROD_TG=$(aws elbv2 describe-listeners \\
--listener-arn ${{ env.LISTENER_ARN }} \\
--region ${{ env.AWS_REGION }} \\
--query 'Listeners[0].DefaultActions[0].ForwardConfig.TargetGroups[?Weight==`1`].TargetGroupArn' \\
--output text)
if [ "$PROD_TG" = "${{ env.BLUE_TG_ARN }}" ]; then
PROD_ASG="${{ env.BLUE_ASG_NAME }}"
STAGE_TG="${{ env.GREEN_TG_ARN }}"
STAGE_ASG="${{ env.GREEN_ASG_NAME }}"
else
PROD_ASG="${{ env.GREEN_ASG_NAME }}"
STAGE_TG="${{ env.BLUE_TG_ARN }}"
STAGE_ASG="${{ env.BLUE_ASG_NAME }}"
fi
echo "PROD_TG=$PROD_TG" >> $GITHUB_ENV
echo "PROD_ASG=$PROD_ASG" >> $GITHUB_ENV
echo "STAGE_TG=$STAGE_TG" >> $GITHUB_ENV
echo "STAGE_ASG=$STAGE_ASG" >> $GITHUB_ENV
- 현재 ELB 리스너가 트래픽을 보내고 있는 Target Group(Prod)을 조회
- Blue/Green 방식에 따라 Prod/Stage의 TG, ASG를 결정
- 결과를 환경변수로 저장
Step 4: Stage ASG 인스턴스 2대로 스케일업
text- name: Scale Stage ASG to 2 for HA
run: |
aws autoscaling update-auto-scaling-group \\
--auto-scaling-group-name $STAGE_ASG \\
--min-size 2 --max-size 2 --desired-capacity 2
- Stage(새 버전) ASG의 인스턴스 수를 2대로 늘려 고가용성(HA) 확보
Step 5: Stage TG 인스턴스 헬스체크 대기
text- name: Wait for Stage TG instances to be healthy
run: |
aws elbv2 wait target-in-service \\
--target-group-arn $STAGE_TG \\
--region ${{ env.AWS_REGION }}
- Stage Target Group에 연결된 인스턴스들이 정상(Healthy) 상태가 될 때까지 대기
Step 6: 트래픽을 Stage TG로 스위칭
text- name: Switch traffic to Stage TG
run: |
aws elbv2 modify-listener \\
--listener-arn ${{ env.LISTENER_ARN }} \\
--default-actions '[{"Type":"forward","ForwardConfig":{"TargetGroups":[{"TargetGroupArn":"'"$STAGE_TG"'","Weight":1},{"TargetGroupArn":"'"$PROD_TG"'","Weight":0}]}}]'
- ELB 리스너의 트래픽을 Stage TG(새 버전)로 전환
Step 7: 이전 Prod ASG 인스턴스 0대로 스케일다운
text- name: Scale down old Prod ASG to zero
if: always()
run: |
echo "Scaling down old Prod ASG ($PROD_ASG) to zero to save cost"
aws autoscaling update-auto-scaling-group \\
--auto-scaling-group-name $PROD_ASG \\
--min-size 0 --max-size 0 --desired-capacity 0 \\
--region ${{ env.AWS_REGION }}
- 이전 Prod ASG의 인스턴스 수를 0으로 줄여 비용 절감
Step 8: Stage 인스턴스로 새 AMI 생성 및 Launch Template 업데이트
text- name: Create AMI from one Stage instance and update Launch Template
run: |
IMAGE_NAME="ami-dev-app-$(date -u +%Y%m%d%H%M%S)"
INSTANCE_ID=$(aws elbv2 describe-target-health \\
--target-group-arn $STAGE_TG \\
--query 'TargetHealthDescriptions[0].Target.Id' \\
--output text)
new_ami_id=$(aws ec2 create-image \\
--instance-id $INSTANCE_ID \\
--name $IMAGE_NAME \\
--no-reboot \\
--query 'ImageId' --output text)
echo "New AMI ID: $new_ami_id"
USER_DATA=$(base64 -w0 < scripts/user-data.sh)
cat > template-data.json <<EOF
{
"ImageId": "$new_ami_id",
"UserData": "$USER_DATA"
}
EOF
aws ec2 create-launch-template-version \\
--launch-template-id ${{ env.LAUNCH_TEMPLATE_ID }} \\
--version-description "Auto-updated $(date -u)" \\
--source-version '$Latest' \\
--launch-template-data file://template-data.json \\
--query 'LaunchTemplateVersion.VersionNumber' --output text > ver.txt
NEW_VER=$(cat ver.txt)
aws ec2 modify-launch-template \\
--launch-template-id ${{ env.LAUNCH_TEMPLATE_ID }} \\
--default-version $NEW_VER
- Stage(새 버전) 인스턴스 중 하나로부터 AMI 생성
- user-data.sh 스크립트를 base64 인코딩하여 Launch Template에 포함
- 기존 Launch Template에서 새로운 버전을 생성(새 AMI 사용)
- 새 버전을 기본 버전으로 지정
'프로젝트 > 서버관리' 카테고리의 다른 글
| AWS shield 도입 (0) | 2025.02.24 |
|---|---|
| ssm 서버에 로컬 환경에서 데이터 베이스 연동(mac) (0) | 2024.12.23 |
| ec2에서 이미지 pull 시 깃허브액션을 활용하여 자동화 하기. (0) | 2024.11.02 |
| 도커 허브에서 도커 이미지 pull 받은 이후 우분투 서버에서 실행시키기 (0) | 2024.11.01 |
| 도커 파일로 이미지 생성해서 도커에 올리기 (0) | 2024.10.31 |