IT/AWS

[AWS] EC2 Nginx 무중단 배포

어린이개발자 2024. 12. 5. 22:01

회사에서 운영하는 서비스에서 수정사항 반영 시 매번 EC2 인스턴스를 중단이 필요했고, 이때 서비스를 제공할 수 없기에 이를 해결하기 위하여 Nginx 를 활용한 무중단 배포 도입을 결정했다.
 
1. 아키텍처

 
2. 방법
- Spring Boot 애플리케이션을 기존 1개에서 2개로 추가 변경
- Nginx 관련 설정 파일(ex. nginx.conf 등) 수정하여 리버스 프록시 역할을 하도록 셋팅
- 배포 시 사용할 폴더 및 파일(ex. deploy.sh 등) 추가하여 해당 쉘 스크립트를 실행하면 배포가 진행되도록 셋팅
 
3. 상세
- 3.1. Nginx 관련 설정 파일 수정
  - /etc/nginx 폴더에 nginx.conf 파일
  - include /etc/nginx/sites-enabled/*; 로 작성된 부분이 있는데, 이는 해당 부분을 가져와 적용한다는 의미
  - /etc/nginx/sites-enabled/default 파일 수정

server {
	    ...생략...
        underscores_in_headers on; // 해당 옵션을 설정해야 header 에 "_" 가 포함된 key를 사용 가능
		...생략...
		server_name XXX; // 수정 (EC2 인스턴스의 DNS 주소 입력)
		
		location / {
				include /etc/nginx/conf.d/service-url.inc; // 추가
                proxy_pass $service_url; // 추가
                proxy_set_header X-Real-IP $remote_addr; // 추가
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; // 추가
                proxy_set_header Host $http_host; // 추가

                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                #try_files $uri $uri/ =404; // 비활성화
		}
}

 
 
  - /etc/nginx/conf.d/service-url.inc 파일 생성 후 내용 추가

set $service_url http://127.0.0.1:8081;

 
- 3.2. 배포 시 사용할 폴더 및 파일 추가
  - 폴더 
    - /home/ubuntu/bogus/nonstop
    - /home/ubuntu/bogus/nonstop/api-server/build/libs
    - /home/ubuntu/bogus/nonstop/jar
  - 파일
    - /home/ubuntu/bogus/nonstop/deploy.sh
    - /home/ubuntu/bogus/nonstop/switch.sh
 
- 3.3. 배포 시 사용할 스크립트 파일 작성
  - /home/ubuntu/bogus/nonstop/deploy.sh

#!/bin/bash
BASE_PATH=/home/ubuntu/bogus
BUILD_PATH=$(ls $BASE_PATH/build/libs/*.jar)

JAR_NAME=$(basename $BUILD_PATH)
echo "> build 파일명: $JAR_NAME"

echo "> build 파일 복사"
DEPLOY_PATH=$BASE_PATH/nonstop/jar/
rm $DEPLOY_PATH$JAR_NAME
cp $BUILD_PATH $DEPLOY_PATH

echo "> 현재 구동 중인 Profile 확인"
CURRENT_PROFILE=$(curl -s http://localhost/profile)
echo "> $CURRENT_PROFILE"

# 쉬고 있는 set 찾기: production 이 사용중이면 production-2 가 쉬고 있고, 반대면 production 이 쉬고 있음
if [ $CURRENT_PROFILE == production ]
then
        IDLE_PROFILE=production-2
        IDLE_PORT=8082
elif [ $CURRENT_PROFILE == production-2 ]
then
        IDLE_PROFILE=production
        IDLE_PORT=8081
else
        echo "> 일치하는 Profile 이 없습니다. Profile: $CURRENT_PROFILE"
        echo "> production 을 할당합니다. IDLE_PROFILE: production"
        IDLE_PROFILE=production
        IDLE_PORT=8081
fi

echo "> application.jar 교체"
IDLE_APPLICATION=$IDLE_PROFILE-api-server.jar
echo "> IDLE_APPLICATION: $IDLE_APPLICATION"
IDLE_APPLICATION_PATH=$DEPLOY_PATH$IDLE_APPLICATION
echo "> IDLE_PORT: $IDLE_PORT"

ln -Tfs $DEPLOY_PATH$JAR_NAME $IDLE_APPLICATION_PATH

echo "> $IDLE_PROFILE 에서 구동중인 애플리케이션 pid 확인"
IDLE_PID=$(sudo lsof -t -i :$IDLE_PORT)

if [ -z $IDLE_PID ]
then
        echo "> 현재 구동중인 애플리케이션이 없으므로 종료하지 않습니다."
else
        echo "> kill -15 $IDLE_PID"
        kill -15 $IDLE_PID
        sleep 5
fi

echo "> $IDLE_PROFILE 배포"
nohup java -jar -Dspring.profiles.active=$IDLE_PROFILE $IDLE_APPLICATION_PATH &

echo "> $IDLE_PROFILE 10초 후 Health check 시작"
echo "> curl -s http://localhost:$IDLE_PORT/"
sleep 10

for retry_count in {1..10}
do
        response=$(curl -s http://localhost:$IDLE_PORT/)
        echo "> response : $response"
        up_count=$(echo $response | grep 'success' | wc -l)

        if [ $up_count -ge 1 ]
        then
                echo "> Health check 성공"
                break
        else
                echo "> Health check 의 응답을 알 수 없습니다."
                echo "> Health check: ${response}"
        fi

        if [ $retry_count -eq 10 ]
        then
                echo "> Health check 실패"
                echo "> Ngnix 에 연결하지 않고 배포를 종료합니다."
                exit 1
        fi

        echo "> Health check 연결 실패. 재시도..."
        sleep 10
done

echo "> 스위칭"
sleep 10
/home/ubuntu/bogus/nonstop/switch.sh

 
  - /home/ubuntu/api-server/nonstop/switch.sh

#!/bin/bash
echo "> 현재 구동중인 Port 확인"
CURRENT_PROFILE=$(curl -s http://localhost/profile)

# 쉬고 있는 set 찾기: production 이 사용중이면 production-2 가 쉬고 있고, 반대면 production 이 쉬고 있음
if [ $CURRENT_PROFILE == production ]
then
        IDLE_PORT=8082
elif [ $CURRENT_PROFILE == production-2 ]
then
        IDLE_PORT=8081
else
        echo "> 일치하는 Profile 이 없습니다. Profile: $CURRENT_PROFILE"
        echo "> 8081을 할당합니다."
        IDLE_PORT=8081
fi

echo "> 전환할 Port: $IDLE_PORT"
echo "> Port 전환"
echo "set \$service_url http://127.0.0.1:${IDLE_PORT};" |sudo tee /etc/nginx/conf.d/service-url.inc

PROXY_PROFILE=$(curl -s http://localhost/profile)
echo "> Nginx Current Proxy Profile: $PROXY_PROFILE"

echo "> Nginx Reload"
sudo service nginx reload

 
- 3.4. 스크립트 파일 실행
  - /home/ubuntu/bogus/nonstop/deploy.sh
    - 참고) deploy.sh 파일을 실행 과정에서 switch.sh 파일 실행
 
4. 참고
https://jojoldu.tistory.com/267

'IT > AWS' 카테고리의 다른 글

[AWS] DynamoDB 연동기  (1) 2024.11.29
[AWS] ECS Fargate 도입기  (0) 2024.11.27