단일의 aws ec2 인스턴스에서 무중단 배포를 해야 하는 상황이 드디어 온것이다. 시행착오를 거치면서 완성한 배포 스크립트를 공유한다. 프로젝트는 spring boot + gradle 기반의 프로젝트이고 nginx 서버를 사용하였다. 어플리케이션 사이드에서 포트 프로파일 정보와 헬스 체크에 관련한 컨트롤러를 생성하고 그 정보를 토대로 배포할때 참고한다.
@RestController
@RequiredArgsConstructor
public class ProfileController {
private final Environment env;
@GetMapping("/port-profile")
public String profile() {
List<String> profiles = Arrays.asList(env.getActiveProfiles());
List<String> realProfiles = Arrays.asList("port-1","port-2");
String defaultProfile = profiles.isEmpty() ? "port-1" : profiles.get(0);
return profiles.stream()
.filter(realProfiles::contains)
.findAny()
.orElse(defaultProfile);
}
}
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello";
}
}
application-port-1.properties
server.port=8080
application-port-2.properties
server.port=8081
/etc/nginx/conf.d/semoh-app-api-service-url.inc
set $service_url http://127.0.0.1:8080;
/etc/nginx/sites-enabled/semoh.conf
server {
listen 80;
server_name api-test.semoh.co.kr;
include /etc/nginx/conf.d/semoh-app-api-service-url.inc;
location / {
proxy_pass $service_url;
}
}
./deploy.sh $env (예: ./deploy.sh prod)
CURRENT_PORT_PROFILE=$(curl -k http://api-test.semoh.co.kr/port-profile)
echo "> spring.profiles.active = $1"
if [ -z "$1" ]; then
echo "profile을 입력하세요. (예: ./start-nostop.sh prod)"
exit 1
fi
echo "> 현재 구동중인 Port 프로필"
echo "$CURRENT_PORT_PROFILE"
if [ "$CURRENT_PORT_PROFILE" == "port-1" ]; then
CURRENT_RUNNING_PORT=8080
WILL_RUNNING_PORT=8081
WILL_RUNNING_PORT_PROFILE="port-2"
elif [ "$CURRENT_PORT_PROFILE" == "port-2" ]; then
CURRENT_RUNNING_PORT=8081
WILL_RUNNING_PORT=8080
WILL_RUNNING_PORT_PROFILE="port-1"
else
CURRENT_RUNNING_PORT=8081
WILL_RUNNING_PORT=8080
WILL_RUNNING_PORT_PROFILE="port-1"
fi
echo "> 현재 구동중인 Port $CURRENT_RUNNING_PORT"
JAR="./sangsang-noriteo-app-api/build/libs/sangsang-noriteo-app-api-0.0.1-SNAPSHOT.jar"
cd ../../
rm $JAR
./gradlew :sangsang-noriteo-app-api:test
./gradlew :sangsang-noriteo-core:clean
./gradlew :sangsang-noriteo-core:cleanQuerydslSourcesDir
./gradlew :sangsang-noriteo-app-api:bootJar
fuser -k $WILL_RUNNING_PORT/tcp
echo "> 구동 시 Port $WILL_RUNNING_PORT"
echo "> 구동 할 port profile $WILL_RUNNING_PORT_PROFILE"
nohup java -jar -Dspring.profiles.active="$1",$WILL_RUNNING_PORT_PROFILE $JAR &
echo "> Health check 시작합니다."
echo "> curl -s http://localhost:$WILL_RUNNING_PORT/hello"
sleep 3
for retry_count in {1..300}; do
response=$(curl -s http://localhost:$WILL_RUNNING_PORT/hello)
up_count=$(echo "$response" | grep -c "hello")
if [ "$up_count" -ge 1 ]; then
echo "> Health check 성공"
break![](https://velog.velcdn.com/images/sonaky47/post/60c08f31-794d-4d6a-a8bf-9f0ad26dd064/image.png)
else
echo "> Health check: ${response}"
fi
if [ "$retry_count" -eq 100 ]; then
echo "> Health check 실패. "
echo "> Nginx에 연결하지 않고 배포를 종료합니다."
exit 1
fi
echo "> Health check 연결 실패. 재시도..."
sleep 1
done
echo "> 전환할 Port: $WILL_RUNNING_PORT"
echo "> Port 전환"
echo "set \$service_url http://127.0.0.1:$WILL_RUNNING_PORT;" | sudo tee /etc/nginx/conf.d/semoh-app-api-service-url.inc
sudo service nginx reload
sleep 10
echo "> 구동중이었던 프로세스 종료"
fuser -k $CURRENT_RUNNING_PORT/tcp