[Springboot] nginx 무중단 배포 환경 설정

송진영·2022년 4월 18일
1

Springboot

목록 보기
3/9

nginx 설치하는 방법은 nginx 설치법에서 확인할 수 있다.

Spring Profile 설정

프로필 확인

@RestController
@RequiredArgsConstructor
public class WebRestController {
 private final Environment env;
 @GetMapping("/profile")
 public String getProfile() {
   return Arrays.stream(env.getActiveProfiles()).findFirst().orElse("");
 }
}

WebRestController를 통해서 현재 어떤 profile을 사용 중인지 확인할 수 있다.

라이브러리 추가

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

위 라이브러리를 dependencies 안에 넣어준다.

prod-application.yml 설정

~$ sudo mkdir app
~$ cd app
~$ sudo mkdir config
~$ cd config
~$ sudo vim prod-application.yml

app 디렉터리를 만들고 안에 config 디렉터리를 만들어 주고 안에 yml 설정 파일을 만들어준다.

--- # prod1 환경
spring:
  config:
    activate:
      on-profile: prod1
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://주소:3306/스키마?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC&autoReconnect=true
    username: 아이디
    password: 비번
  jpa:
    hibernate:
      ddl-auto: update
    generate-ddl: true
    show-sql: true
    properties:
      hibernate:
        format_sql: true
    database: mysql
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
logging:
  level:
    root: info
server:
  port: 8089
---
--- #prod2 환경
spring:
  config:
    activate:
      on-profile: prod2
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://주소:3306/스키마?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC&autoReconnect=true
    username: 아이디
    password: 비번
  jpa:
    hibernate:
      ddl-auto: update
    generate-ddl: true
    show-sql: true
    properties:
      hibernate:
        format_sql: true
    database: mysql
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
logging:
  level:
    root: info
server:
  port: 8090

본인의 기존 데이터베이스를 포함한 설정 정보들을 모두 가져와주고, profile 두 개를 각각 8089, 8090포트로 나눠준다.

  • 이 경우 ec2에서 8089, 8090포트를 열어줘야 한다.

실행

~$ java -jar 본인jar이름.jar --spring.config.location=file:config/prod-application.yml --spring.profiles.active=prod1

위의 명령어를 실행하면 prod-application.yml의 prod1 profile 설정을 통해서 실행을 시켜 8089 포트로 실행이 된다

"The follwing 1 profile is active: "prod1"이 뜬다면 profile 설정은 성공이다.

Nginx 설정

nginx.conf 수정

~$ sudo vim /etc/nginx/nginx.conf


/etc/nginx/nginx.conf에 들어가 위와 같이 수정

~$ sudo service nginx reload

설정 후 nginx을 재시작 해준다.

~$ sudo vim /etc/nginx/conf.d/service-url.inc

service-url.inc을 생성하여 안에 위와 같이 적고 저장한다.
그러면 기본 설정을 prod 1인 8089 포트로 설정해준 것이고, nginx.conf에서 이 주소를 읽어와 전달해준다.

nginx 포트 전달

위의 설정을 마치면 아래와 같이 80포트로 들어오는 요청을 스프링의 8089포트로 전달해준다.

Nginx 재시동 및 전환

이번엔 쉘 스크립트를 사용해서 스프링 서버를 재시동하고 nginx가 해당 스프링 서버를 가리킬 수 있도록 한다.

재시동 쉘 스크립트 작성(deploy.sh)

~$ sudo vim deploy.sh

/home/ec2-user/app에 deploy.sh를 만들어준다.

#!/bin/bash
echo "> 현재 구동중인 profile 확인"
CURRENT_PROFILE=$(curl -s http://localhost/profile)
echo "> $CURRENT_PROFILE"
if [ $CURRENT_PROFILE == prod1 ]
then
	IDLE_PROFILE=prod2
	IDLE_PORT=8090
elif [ $CURRENT_PROFILE == prod2 ]
then
	IDLE_PROFILE=prod1
	IDLE_PORT=8089
else
	echo "> 일치하는 Profile이 없습니다. Profile: $CURRENT_PROFILE"
	echo "> prod1을 할당합니다. IDLE_PROFILE: prod1"
	IDLE_PROFILE=prod1
	IDLE_PORT=8089
fi
echo "> $IDLE_PROFILE 배포"
sudo fuser -k -n tcp $IDLE_PORT
sudo nohup java -jar /jar파일경로/core-0.0.1-SNAPSHOT.jar --spring.config.location=file:config/prod-application.yml --spring.profiles.active=$IDLE_PROFILE &
echo "> $IDLE_PROFILE 10초 후 Health check 시작"
echo "> curl -s http://localhost:$IDLE_PORT/actuator/health "
sleep 10
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
		echo "> Health check 성공"
		break
	else
		echo "> Health check의 응답을 알 수 없거나 혹은 status가 UP이 아닙니다."
		echo "> Health check: ${response}"
	fi
	if [ $retry_count -eq 10 ]
	then
		echo "> Health check 실패. "
		echo "> Nginx에 연결하지 않고 배포를 종료합니다."
		exit 1
	fi
	echo "> Health check 연결 실패. 재시도..."
	sleep 10
done
echo "> 스위칭을 시도합니다..."
sleep 10
sh /home/ec2-user/app/switch.sh

jar 파일 이름과, 마지막 줄 switch.sh 파일 위치는 본인에 맞게 바꿔야 한다.

  • 3번 라인: 현재 nginx가 가리키는 스프링의 profile을 확인한다.
  • 6~19번 라인: 현재 가리키고 있는 CURRENT_PROFILE과 IDLE_PROFILE을 구분한다.
  • 21~23번라인
    • sudo fuser -k -n tcp $IDLE_PORT: IDLE_PORT로 구동 중인 스프링 서버가 있으면 중단
    • sudo nohup java -jar core-0.0.1-SNAPSHOT.jar --spring.config.location=file:config/prod-application.yml --spring.profiles.active=$IDLE_PROFILE &: 스프링 로그는 nohup.out에 기록하며 백그라운드로 IDLE_PROFILE의 스프링 서버 가동(뒤에 &를 붙이지 않으면 다음 명령을 실행하지 않는다.)
  • 25~라인
    • 일정 시간 후 10번 동안 서버 health check - Actuator 라이브러리 사용
    • 실패하면 code 1로 스크립트 종료
    • 성공하면 반복문을 빠져나가고 전환 스크립트 실행

전환 쉘 스크립트 작성(switch.sh)

~$ sudo vim swich.sh

마찬가지로 app 디렉터리에 생성해준다.

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

if [ $CURRENT_PROFILE == prod1 ]
then
	IDLE_PORT=8090
elif [ $CURRENT_PROFILE == prod2 ]
then
	IDLE_PORT=8089
else
	echo "> 일치하는 Profile이 없습니다. Profile:$CURRENT_PROFILE"
	echo "> 8089를 할당합니다."
	IDLE_PORT=8089
fi

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

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

echo "> Nginx Reload"
sudo service nginx reload
  • 3~15번 라인: 현재 구동 중인 스프링 프로필을 확인하여 새롭게 가리킬 프로필 셋을 지정한다.
  • 22번 라인: /etc/nginx/conf.d/service-url.iinc 파일에 포트 부분을 IDLE_PORT로 바꿔준다.
  • 25번 라인: nginx가 새로 업데이트된 service-url.inc 파일의 내용을 리로드하여 재시작한다.

실행

~$ sh deploy.sh

deploy.sh를 실행시켜준다.

개행문자 오류

원인

  • 처음에 위와 같은 문제가 발생하길래 원인을 찾아보니 window 환경에서 파일을 생성하여 git에 올리고 그것을 그대로 받아와서 window와 linux 사이의 개행 문자 차이 때문에 발생한 오류였던 것 같다.

해결

ec2에서 직접 타이핑 해서 쓰면 위와 같은 오류가 발생하지 않는다.

prod1 에서 prod2로 전환되며 백그라운드로 Spring jar 파일이 잘 실행되는 것을 확인할 수 있다.

참고 사이트(만렙 개발자 키우기)

profile
못하는 건 없다. 단지 그만큼 노력을 안 할 뿐이다.

0개의 댓글