| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
| 29 | 30 | 31 |
- SpringBoot
- 정규식
- 자바문법
- Eclipse
- 스프링부트
- js
- 문자열
- html
- CSS
- 인텔리제이
- HashMap
- list
- junit
- javascript
- Java
- Array
- 배열
- ArrayList
- java테스트
- 자바스크립트
- 단위테스트
- Visual Studio Code
- 자바
- input
- IntelliJ
- 테스트자동화
- string
- junit5
- math
- vscode
- Today
- Total
어제 오늘 내일
[Spring Boot] "배포 중에도 멈추지 않는 서버" 무중단 배포 스크립트 작성하기 (Blue/Green) 본문
[Spring Boot] "배포 중에도 멈추지 않는 서버" 무중단 배포 스크립트 작성하기 (Blue/Green)
hi.anna 2026. 3. 19. 01:14
지난 시간 Nginx 설정을 통해 80번 포트로 들어온 요청을 8080번으로 넘기는 것까지 성공했습니다.
하지만 배포할 때마다 서버를 껐다 켜야 하는 문제는 여전합니다.
오늘은 서버를 2개(8081, 8082) 운영하면서, Nginx가 바라보는 방향만 살짝 바꿔주는 무중단 배포의 마법을 부려보겠습니다.
1. 블루/그린(Blue/Green) 배포란?
구 개념은 아주 간단합니다.
- Blue (기존): 현재 서비스 중인 서버 (예: 8081 포트)
- Green (신규): 새로 배포할 서버 (예: 8082 포트)
새로운 버전(Green)을 8082포트에 몰래 띄우고, 다 떴는지 확인(Health Check)한 다음, Nginx에게 "이제 8082를 바라봐!"라고 명령하는 방식입니다. 그리고 마지막에 기존 서버(Blue)를 끕니다.
2. 준비: 포트 2개 만들기 ( 활용)
스프링 부트 설정 파일(application.yml)을 복사해서 포트만 다른 2개의 프로필을 만듭니다.
server:
port: 8081
server:
port: 8082
이제 실행할 때 -Dspring.profiles.active=set1이라고 주면 8081로 뜨고, set2라고 주면 8082로 뜨겠죠?
3. Nginx 설정 변경 ()
Nginx가 동적으로 포트를 바꿀 수 있도록, 포트 정보만 담고 있는 별도 파일을 하나 만듭니다.
1. 포트 설정 파일 생성
sudo vim /etc/nginx/conf.d/service-url.inc
내용은 딱 한 줄입니다.
set $service_url http://127.0.0.1:8081;
2. 메인 설정 파일 수정 ()
sudo vim /etc/nginx/sites-available/default
기존의 proxy_pass 부분을 아래와 같이 변수로 교체합니다.
server {
# ... (생략)
include /etc/nginx/conf.d/service-url.inc; # ★ 방금 만든 파일 포함
location / {
proxy_pass $service_url; # ★ 변수로 변경
# ... (헤더 설정 등)
}
}
재시작: sudo service nginx restart
4. 대망의 배포 스크립트 ()
이제 이 모든 과정을 자동으로 해줄 쉘 스크립트를 작성합니다. 프로젝트 루트 경로에 만드세요.
#!/bin/bash
echo "> 현재 구동 중인 포트 확인"
CURRENT_PID=$(pgrep -f java)
if [ -z $CURRENT_PID ]; then
echo "> 현재 구동 중인 애플리케이션이 없으므로 종료하지 않습니다."
else
echo "> 현재 구동 중인 애플리케이션 pid: $CURRENT_PID"
fi
# 1. 현재 어떤 포트가 돌고 있는지 확인
# (8081이 돌고 있으면 -> 8082를 배포해야 함)
CURRENT_PROFILE=$(curl -s http://localhost/profile)
if [ "$CURRENT_PROFILE" == "set1" ]; then
IDLE_PROFILE=set2
IDLE_PORT=8082
elif [ "$CURRENT_PROFILE" == "set2" ]; then
IDLE_PROFILE=set1
IDLE_PORT=8081
else
echo "> 일치하는 Profile이 없습니다. Profile: $CURRENT_PROFILE"
echo "> set1을 할당합니다. IDLE_PROFILE: set1"
IDLE_PROFILE=set1
IDLE_PORT=8081
fi
echo "> $IDLE_PROFILE 배포 (Port: $IDLE_PORT)"
nohup java -jar -Dspring.profiles.active=$IDLE_PROFILE build/libs/*.jar > nohup.out 2>&1 &
echo "> $IDLE_PROFILE 10초 후 Health Check 시작"
sleep 10
# 2. Health Check (새 서버가 제대로 떴는지 확인)
for RETRY_COUNT in {1..10}
do
RESPONSE=$(curl -s http://localhost:$IDLE_PORT/actuator/health)
UP_COUNT=$(echo $RESPONSE | grep 'UP' | wc -l)
if [ $UP_COUNT -ge 1 ]; then # "UP" 문자열이 있으면 성공
echo "> Health Check 성공"
break
else
echo "> Health Check의 응답을 알 수 없거나 실행 상태가 아닙니다."
echo "> Health Check: ${RESPONSE}"
fi
if [ $RETRY_COUNT -eq 10 ]; then
echo "> Health Check 실패. 배포를 중단합니다."
exit 1
fi
echo "> Health Check 연결 실패. 재시도..."
sleep 10
done
# 3. Nginx 스위칭 (포트 변경)
echo "> 스위칭 (Port: $IDLE_PORT)"
echo "set \$service_url http://127.0.0.1:${IDLE_PORT};" | sudo tee /etc/nginx/conf.d/service-url.inc
echo "> Nginx Reload"
sudo service nginx reload
# 4. 기존 서버 종료
if [ -n "$CURRENT_PID" ]; then
echo "> 기존 애플리케이션 종료 pid: $CURRENT_PID"
kill -15 $CURRENT_PID
sleep 5
fi
주의: 이 스크립트가 작동하려면 Controller에 현재 프로필을 반환하는
/profileAPI와, 상태를 확인하는/actuator/health가 있어야 합니다. (Spring Actuator 라이브러리 추가 필요!)
5. GitHub Actions와 연동하기
이제 GitHub Actions의 deploy 단계에서 마지막에 이 스크립트만 실행해 주면 됩니다.
- name: Execute Server
uses: appleboy/ssh-action@master
with:
# ... (접속 정보)
script: |
chmod +x ./deploy.sh
./deploy.sh
마치며
오늘의 결론입니다.
- Nginx의
include기능을 이용해 포트를 동적으로 바꾼다. - 쉘 스크립트로
현재 포트 확인 -> 새 포트 실행 -> 헬스 체크 -> Nginx 스위칭 -> 기존 포트 종료순서를 자동화한다. - 사용자는 단 0.1초의 끊김도 없이 새로운 서비스를 이용하게 된다.
이제 여러분의 서비스는 365일 24시간 멈추지 않는 무중단 서비스가 되었습니다.
다음 포스팅에서는 "자물쇠(SSL)가 없으면 사용자가 불안해해요!" 무료 SSL 인증서(Let's Encrypt) 발급받고 HTTPS 적용하기에 대해 알아보겠습니다.
