이 글은 '스프링부트와 AWS로 혼자 구현하는 웹 서비스 - 이동욱(jojoldu)'을 공부하며 작성한 글로 생략된 내용은 책을 구매해서 확인하는 것을 권장합니다.
참고 소스코드 깃허브 https://github.com/jojoldu/freelec-springboot2-webservice
http://www.yes24.com/Product/Goods/83849117
스프링 부트와 AWS로 혼자 구현하는 웹 서비스 - YES24
가장 빠르고 쉽게 웹 서비스의 모든 과정을 경험한다. 경험이 실력이 되는 순간!이 책은 제목 그대로 스프링 부트와 AWS로 웹 서비스를 구현한다. JPA와 JUnit 테스트, 그레이들, 머스테치, 스프링
www.yes24.com
이 책의 10장에 해당하는 무중단 배포 구현 과정을 정리한 글이다.
9장까지 진행된 프로젝트는 배포시 일시적으로 페이지가 중단되는 문제가 있다. 많은 서비스를 할수록 배포시간이 길어지기 때문에 중단없이 배포하도록 할 필요가 있다.
무중단 배포
- 서비스를 정지하지 않고 배포하는 것
이 프로젝트에서는 엔진엑스(Nginx)를 이용한 무중단 배포를 진행한다.
Nginx : 웹 서버, 리버스 프록시, 캐싱, 로드 밸런싱, 미디어 스트리밍을 위한 오픈소스 소프트웨어
*리버스 프록시: Nginx가 외부의 요청을 받아 백엔드 서버로 요청을 전달하는 행위
실제 요청에 대한 처리는 뒷단의 웹 애플리케이션 서버들이 처리한다.
Nginx 쓰는 이유
- 가장 저렴하고 쉽다.
- 기존에 쓰던 EC2에 그대로 적용 -> 배포를 위해 AWS EC2 인스턴스가 하나 더 있을 필요가 없음.
- AWS와 같은 클라우드 인프라가 반드시 구축되어 있을 필요가 없다. (개인 서버나 사내 서버에서 동일한 방식으로 구축 가능)
하나의 EC2 혹은 리눅스 서버에 엔진엑스 1대와 스프링 부트 Jar 2대를 사용하는 구조이다.
- 엔진엑스는 80(http), 443(https) 포트를 할당한다.
- 스프링 부트 1은 8081 포트를 실행한다.
- 스프링 부트 2는 8082 포트를 실행한다.
Nginx를 사용한 무중단 배포 과정을 정리하면 아래와 같은 순서로 진행된다.
1. 사용자는 서비스 주소로 접속(80 혹은 443)
2. 엔진엑스는 사용자의 요청을 받아 현재 연결된 스프링 부트1로 요청을 전달한다. 이때, 신규 배포가 필요하면 엔진엑스와 연결되지 않은 스프링부트2를 배포한다.
3. 배포 후 스프링부트 2가 정상적으로 구동 중이라면 nginx reload명령어로 8081 대신 8082를 바라보도록 한다.
nginx reload는 0.1초이내에 완료가능
무중단 배포 전체 구조
스프링부트와 AWS로 혼자 구현하는 웹 서비스 p373 그림
이미지 출처: https://highjune.dev/aws/awsseries9/
엔진엑스 설치와 스프링 부트 연동
1. EC2에 Nginx 설치
sudo amazon-linux-extras install nginx1 # Nginx 설치
nginx -v # nginx 버전 확인
sudo service nginx start # Nginx 실행
책에는 nginx 설치 명령어로 sudo yum install nginx로 나와있는데, 아마존 리눅스2 AMI로 했다면 위에 있는 명령어로 설치해야 한다. 책에서 사용한 아마존 리눅스1은 지금은 aws에 없다.
2. 보안그룹 추가
엔진엑스의 포트번호를 보안 그룹에 추가한다.
AWS -> EC2 -> 왼쪽 보안그룹 -> 해당 인스턴스 -> 인바운드 규칙 편집 -> 80번 포트 추가
소스를 Anywhere - IPv4와 Anywhere - IPv6로 각각 지정하고 80번 포트로 규칙을 추가한다.
3. 리다이렉션 주소 추가
8080이 아닌 80포트로 이제 주소가 변경되므로 구글과 네이버 로그인에도 변경된 주소를 등록해준다.
3-1. 구글 로그인 리다이렉션 주소 추가
구글클라우드 플랫폼 (https://console.cloud.google.com) -> 왼쪽 API 서비스 -> 사용자 인증 정보 -> OAuth 2.0 클라이언트 ID 이름 클릭
기존에 등록된 리다이렉션 주소에 8080 부분을 제외한 주소를 추가 등록한다.
3-2. 네이버 로그인 리다이렉션 주소 추가
네이버 Developer https://developers.naver.com/apps/#/register?api=nvlogin -> 내 어플리케이션 -> 원하는 어플리케이션명 클릭 -> API 설정
기존에 등록된 리다이렉션 주소에어 8080 부분을 제외한 주소를 추가 등록한다.
주소를 추가하고 EC2 도메인으로 8080포트없이 접속하면 엔진엑스 페이지로 접속된다.
4. 엔진엑스와 스프링 부트 연동
이제 엔진엑스가 현재 실행중인 스프링 부크 프로젝트를 바라볼 수 있도록 프록시 설정을 해줘야 한다.
EC2에 접속해서 Nginx 설정 파일을 수정한다.
sudo vim /etc/nginx/nginx.conf
책에서는 저 파일로 들어가서 location / 부분에 추가하라고 되어있는데, 파일에 들어가보니 찾는 location / 부분이 없어서 location / { ... }를 server { ... }안에 새로 작성해주었다.
- proxy_pass: 엔진엑스로 요청이 오면 http://localhost:8080으로 전달
- proxy_set_header XXX: 실제 요청 데이터를 header의 각 항목에 할당한다. $이후에 오는 부분이 요청자의 IP $전에 오는 부분이 요청자의 IP를 저장할 곳
설정 파일을 수정했으니 엔진엑스를 재시작해준다.
sudo service nginx restart
이거 restart로 꼭 해주어야 한다. 재시작을 해야 적용되기 때문에 start로 하면 프록시 적용이 되지 않는다.
8080포트 없이 EC2 도메인으로 접속
무중단 배포 스크립트 만들기
무중단 배포 스크립트 작성 전 배포시에 8081을 쓸지, 8082를 쓸지 판단하는 기준이 되는 API 추가
1. ProfileController를 만들어 profile API 작성 (web 폴더 안에)
@RequiredArgsConstructor
@RestController
public class ProfileController {
private final Environment env;
@GetMapping("/profile")
public String profile() {
//현재 실행중인 ActiveProfile을 모두 가져온다. 즉, real, oauth, real-db 등이 활성화되어있다면 모두 담겨있다.
List<String> profiles = Arrays.asList(env.getActiveProfiles());
List<String> realProfiles = Arrays.asList("real", "real1", "real2");
//real, real1, real2는 모두 배포에 사용될 profile이라 이 중에 하나라도 있으면 그 값을 반환한다.
String defaultProfile = profiles.isEmpty()? "default" : profiles.get(0);
return profiles.stream()
.filter(realProfiles::contains)
.findAny()
.orElse(defaultProfile);
}
}
현재 실행중인 ActiveProfile을 가져와 배포에 사용할 profile(real, real1, real2)이 하나라도 있다면 그 값을 반환한다.
지금 하는 무중단 배포에서는 real1과 real2만 사용하지만 step2를 다시 사용할 수도 있으니 real을 남겨둔다.
1-1. 위 코드 작성을 테스트하기 위한 ProfileControllerUnitTest 작성
ProfileController는 스프링 환경이 필요하지 않기 때문에 @SpringBootTest를 안 붙여도 테스트가 가능하다.
생성자 주입 방식으로 주입된 properties 별로 테스트 코드 작성
public class ProfileControllerUnitTest {
@Test
public void real_profile이_조회된다() {
//given
String expectedProfile = "real";
MockEnvironment env = new MockEnvironment();
env.addActiveProfile(expectedProfile);
env.addActiveProfile("oauth");
env.addActiveProfile("real-db");
ProfileController controller = new ProfileController(env);
//when
String profile = controller.profile();
//then
assertThat(profile).isEqualTo(expectedProfile);
}
@Test
public void real_profile이_없으면_첫_번째가_조회된다() {
//given
String expectedProfile = "oauth";
MockEnvironment env = new MockEnvironment();
env.addActiveProfile(expectedProfile);
env.addActiveProfile("real-db");
ProfileController controller = new ProfileController(env);
//when
String profile = controller.profile();
//then
assertThat(profile).isEqualTo(expectedProfile);
}
@Test
public void active_profile이_없으면_default가_조회된다() {
//given
String expectedProfile = "default";
MockEnvironment env = new MockEnvironment();
ProfileController controller = new ProfileController(env);
//when
String profile = controller.profile();
//then
assertThat(profile).isEqualTo(expectedProfile);
}
}
1-2. /profile이 인증 없이도 호출될 수 있도록 SecurityConfig클래스 수정
permitAll 마지막에 "/profile"을 추가한다.
1-3.SecurityConfig 설정 테스트 코드 추가
이 코드는 스프링 시큐리티 설정을 불러오기 때문에 스프링 환경이 필요하다. @SpringBootTest를 사용해서 작성한다.
책에는 @RunWith(SpringRunner.class)를 쓰고 있으나 Junit5이 되면서 @ExtendWith(SpringExtension.class)으로 변경되었다. @ExtendWith는 테스트 진행시 JUnit에 내장된 실행자말고 SpringExtension라는 스프링 실행자 사용한다.
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.beans.factory.annotation.Autowired;
import static org.assertj.core.api.Assertions.assertThat;
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ProfileControllerTest {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Test
public void profile은_인증없이_호출된다() throws Exception{
String expected = "default";
ResponseEntity<String> response = restTemplate.getForEntity("/profile", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).isEqualTo(expected);
}
}
파일을 main에다 만들어서 test로 끌어와서 refactor했더니 test 실행 버튼 > 모양이 생기지 않았다. 파일을 지우고 test 파일에 만들어서 같은 내용을 작성했더니 버튼이 생겼다.
처음 알았는데, test 파일은 test 폴더에서 만들어야 테스트 버튼이 나오는 것 같다.
1-4. 깃허브로 푸시하고 /profile로 접속해서 인증없이도 잘 접속되는지 확인
바로 접속하면 배포중이라 nginx 에러 페이지가 뜰 수도 있다. 잠시 후 다시 접속하면
2. real1, real2 profile 생성
현재 EC2 환경에서 실행되는 profile은 Travis CI 배포 자동화를 위한 real 뿐이다.
그래서 무중단 배포를 위한 profile(real1, real2)를 src/main/resources 아래에 추가해줘야 한다.
application-real1.properties
server.port=8081
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.session.store-type=jdbc
application-real2.properties
server.port=8082
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.session.store-type=jdbc
real profile과 달리 8081, 8082로 포트를 지정했다.
그리고 책(2.1.7)과 다른 스프링부트 버전(2.4.1)을 사용하고 있기 때문에, 옵션이 변화해서 spring.profiles.include를 사용하면 운영 환경(real)에서 인식이 되지 않는다고 한다.
참고
- 저자블로그 글 (https://jojoldu.tistory.com/539)
- application.properties 설정 파일 분리 글 (https://sedangdang.tistory.com/262)
프로필에서 설정한 것을 지우고 application.properties에 profile group을 모두 등록한다.
# Profile Group
spring.profiles.group.local=oauth
spring.profiles.group.real=real, real-db, oauth
spring.profiles.group.real1=real1, real-db, oauth
spring.profiles.group.real2=real2, real-db, oauth
깃허브에 푸시해준다.
3. 엔진엑스 설정 수정
3-1. /etc/nginx/conf.d/에 service-url.inc 생성
배포때마다 프록시 설정이 교체될 수 있도록 설정해주어야 한다.
엔진엑스 설정파일이 모여있는 곳에 service-url.inc 생성한다.
sudo vim /etc/nginx/conf.d/service-url.inc
#파일 열고 아래 코드 작성
set $service_url http://127.0.0.1:8080;
i를 누르고 편집모드로 들어가 작성후 esc누르고 :wq!로 저장한다.
3-2. 엔진엑스 설정 파일 수정 (nignx.conf)
위에서 만든 파일을 엔진엑스가 사용할 수 있도록 nginx.conf 파일을 수정한다.
sudo vim /etc/nginx/nginx.conf
잘못되었을 때, 이전 상태로 접속해보려고 원래 있던 incluse 부분을 주석 처리했는데, 삭제해도 된다.
바꾼 설정을 적용하기 위해 엔진엑스 재시작을 한다.
sudo service nginx restart
재시작하고 EC2 도메인으로 접속하니 nignx로 접속할 수 없다고 에러가 발생했다.
nginx 파일에는 오타가 없는 거 같아 이전에 작성한 파일을 점검하기 위해 인텔리제이를 봤다.
real1, real2 profile 생성하고 생성한 파일 2개와 application.properties를 푸시를 했다고 생각했는데, application--real1.properties와 application--real2.properties가 푸시가 안되어있었다. 즉, 푸시할 때, 파일을 다 보내지 않았다.
아마 application.properties에 등록한 profile group을 사용할 그룹이 없어서 안되지 않았나 싶다!
푸시하고 접속해보니 잘된다.
4. 배포 스크립트들 작성
4-1. step2와 중복되지 않게 EC2에 step3 디렉토리 생성 및 appspec.yml 수정
mkdir ~/app/step3 && mkdir ~/app/step3/zip
step3 디렉토리는 무중단 배포에 사용할 디렉토리이다. 배포시 이 디렉토리를 사용하도록 appspec.yml도 step3로 배포되도록 수정한다.
4-2. 배포 스크립트들 작성
무중단 배포에 필요한 스크립트들은 총 5개다.
- stop.sh : 기존 엔진엑스에 연결되어 있지 않은 상태로 실행중이던 스프링 부트 종료
- start.sh : 배포할 신규 버전 스프링 부트 프로젝트를 stop.sh로 종료한 'profile'로 실행
- health.sh : 'start.sh'로 실행 시킨 프로젝트가 정상적으로 실행되었는지 체크
- switch.sh : 엔진엑스가 바라보는 스프링 부트를 최신 버전으로 변경
- profile.sh : 앞선 4개의 스크립트 파일에서 공용으로 사용할 'profile'과 포트 체크 로
appspec.yml에 위 스크립트들을 사용하도록 hooks 부분을 수정해준다.
hooks:
AfterInstall:
- location: stop.sh # 엔진엑스와 연결되어 있지않은 스프링 부트 종료
timeout: 60
runas: ec2-user
ApplicationStart:
- location: start.sh # 엔진엑스와 연결되어 있지 않은 Port로 새 버전의 스프링 부트 시작
timeout: 60
runas: ec2-user
ValidateService:
- location: health.sh # 새 스프링 부트가 정상적으로 실행되었는지 체트
timeout: 60
runas: ec2-user
Jar 파일이 복사된 후부터 차례로 위 스크립트들이 실행된다.
scripts 디렉토리에 스크립트들 작성
아직 깃허브에 푸시하기 전이라 빨간색으로 표시되었다. 인텔리제이에서는 .gitignore에 등록 안된 파일인데 푸시가 안되어있으면 빨간색으로 나온다.
profile.sh
#!/usr/bin/env bash
# 쉬고 있는 profile 찾기: real1이 사용 중이면 real2가 쉬고 있고, real2가 실행 중이면 real1이 쉬고 있음
function find_idle_profile()
{
# 현재 엔진엑스가 바라보고 있는 스프링부트가 정상적으로 수행 중인지 확인
RESPONSE_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost/profile)
if [ ${RESPONSE_CODE} -ge 400 ] # 400보다 크면 -> 40x, 50x 에러 포함
then
CURRENT_PROFILE=real2
else
CURRENT_PROFILE=$(curl -s http://localhost/profile)
fi
if [ ${CURRENT_PROFILE} == real1 ]
# 엔진엑스와 연결되어 있지 않은 profile
then
IDLE_PROFILE=real2
else
IDLE_PROFILE=real1
fi
# bash라는 스크립트는 값을 반환하는 기능x -> 제일 마지막 줄에 echo로 결과 출력, 클라이언트가 그 값을 잡아서 사용
echo "${IDLE_PROFILE}"
}
# 쉬고 있는 profile의 port 찾기
function find_idle_port()
{
IDLE_PROFILE=$(find_idle_profile)
if [ ${IDLE_PROFILE} == real1 ]
then
echo "8081"
else
echo "8082"
fi
}
- $(curl -s -o /dev/null -w "%{http_code}" http://localhost/profile)
- 현재 엔진엑스가 바라보고 있는 스프링부트가 정상적으로 수행 중인지 확인, 응답값을 HttpStatus로 받는다.
- 정상이면 200, 오류가 발생하면 400~503 사이로 발생 -> 400이상은 모두 예외로 간주 -> real2를 현재 profile로 사용
- IDLE_PROFILE : 엔진엑스와 연결되어 있지 않은 profile로 스프링 부트 프로젝트를 이 profile로 연결하기 위해 반환
- echo "${IDLE_PROFILE}" : bash라는 스크립트는 값을 반환하는 기능x -> 제일 미지막 줄(echo는 중간에 사용x)에 echo로 결과 출력, 클라이언트에서 이 값을 잡아서 사용 $(find_idle_profile)
stop.sh
#!/usr/bin/env bash
ABSPATH=$(readlink -f $0)
ABSDIR=$(dirname $ABSPATH) # 현재 stop.sh가 속해있는 경로를 찾는다
source ${ABSDIR}/profile.sh # 자바로 보면 import 구문에 해당, 이 코드로 profile.sh의 여러 function 사용 가능
IDLE_PORT=$(find_idle_port)
echo "> $IDLE_PORT 에서 구동중인 어플리케이션 pid 확인"
IDLE_PID=$(lsof -ti tcp:${IDLE_PORT})
if [ -z ${IDLE_PORT} ]
then
echo "> 현재 구동중인 어플리케이션이 없으므로 종료하지 않습니다."
else
echo "> kill -15 $IDLE_PID" # Nginx에 연결되어 있지는 않지만 현재 실행 중인 jar Kill
kill 15 ${IDLE_PID}
sleep 5
fi
start.sh
#!/usr/bin/env bash
ABSPATH=$(readlink -f $0)
ABSDIR=$(dirname $ABSPATH)
source ${ABSDIR}/profile.sh
REPOSITORY=/home/ec2-user/app/step3
PROJECT_NAME=springboot-web-practise
echo "> Build 파일 복사"
echo "cp $REPOSITORY/zip/*.jar $REPOSITORY/"
cp $REPOSITORY/zip/*.jar $REPOSITORY/
echo "> 새 어플리케이션 배포"
JAR_NAME=$(ls -tr $REPOSITORY/*.jar | tail -n 1)
echo "> JAR Name: $JAR_NAME"
echo "> $JAR_NAME 에 실행권한 추가"
chmod +x $JAR_NAME
echo "> $JAR_NAME 실행"
IDLE_PROFILE=$(find_idle_profile)
echo "> $JAR_NAME 를 profile=$IDLE_PROFILE 로 실행합니다. "
nohup java -jar \
-Dspring.config.location=classpath:/application.properties,classpath:/application-$IDLE_PROFILE.properties,
/home/ec2-user/app/application-oauth.properties,/home/ec2-user/app/application-real-db.properties \
-Dspring.profiles.active=$IDLE_PROFILE \
$JAR_NAME > $REPOSITORY/nohup.out 2>&1 &
step2의 deploy.sh와 유사한 스크립트
차이점은 IDLE_PROFILE을 통해 properties 파일을 가져오고(application-$IDLE_PROFILE.properties), active profile을 지정하는 것(-Dspring.profiles.active=$IDLE_PROFILE)
여기서도 IDLE_PROFILE를 사용한다. -> profile.sh을 가져와야 한다.
health.sh
#!/usr/bin/env bash
# 엔진엑스와 연결되지 않은 포트로 스프링 부트(=start.sh로 실행시킨 프로젝트)가 잘 실행되었는지 체크
ABSPATH=$(readlink -f $0)
ABSDIR=$(dirname $ABSPATH)
source ${ABSDIR}/profile.sh
source ${ABSDIR}/switch.sh
IDLE_PORT=$(find_idle_port)
echo "> Health Check Start!"
echo "> IDLE_PORT: $IDLE_PORT"
echo "> curl -s http://localhost:$IDLE_PORT/profile "
sleep 10
for RETRY_COUNT in {1..10}
do
RESPONSE=$(curl -s http://localhost:${IDLE_PORT}/profile)
UP_COUNT=$(echo ${RESPONSE} | grep 'real' | wc -l)
if [ ${UP_COUNT} -ge 1 ]
then # $up_count >= 1 ("real" 문자열이 있는지 검증)
echo "> Health check 성공"
switch_proxy
break
else
echo "> Health check의 응답을 알 수 없거나 혹은 실행 상태가 아닙니다."
echo "> Health check: ${RESPONSE}"
fi
if [ ${RETRY_COUNT} -eq 10 ]
then
echo "> Health check 실패. "
echo "> 엔진엑스에 연결하지 않고 배포를 종료합니다."
exit 1
fi
echo "> Health check 연결 실패. 재시도..."
sleep 10
done
엔진엑스와 연결되지 않은 포트로 스프링 부트(start.sh가 실행 시킨 프로젝트)가 잘 떴는지 확인한다.
확인하고나서 프록시 설정을 변경해줘야 하기 때문! 프록시 설정 변경은 switch.sh에서 진행한다.
switch.sh
프록시 설정 변경을 통해 엔진엑스가 바라보는 스프링 부트를 최신 버전으로 변경
#!/usr/bin/env bash
ABSPATH=$(readlink -f $0)
ABSDIR=$(dirname $ABSPATH)
source ${ABSDIR}/profile.sh
function switch_proxy() {
IDLE_PORT=$(find_idle_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" #엔진엑스 설정을 다시 불러온다. restart와는 다름.
sudo service nginx reload
}
- echo "set \$service_url http://127.0.0.1:${IDLE_PORT};"
- 하나의 문장을 만들어 파이프라인(|)으로 넘겨주기 위해 echo 사용
- 엔진엑스가 변경해야할 프록시 주소를 생성
- 쌍따옴표(")를 사용한다. (사용하지 않으면 $service_url을 그대로 인식하지 못하고 변수를 찾음)
- sudo tee /etc/nginx/conf.d/service-url.inc : 위에서 넘겨준 문장을 service-url.inc에 덮어쓴다.
- sudo service nginx reload: 엔진엑스 설정을 다시 불러온다.
- restart는 잠시 끊기지만 reload는 끊김없이 불러온다. 다만 중요할 설정을 반영하려면 restart를 해주어야 한다. 여기서는 외부의 설정 파일인 service-url을 다시 불러오는 거기 때문에 reload로 가능
무중단 배포 테스트
1. 자동으로 버전 값이 변경되도록 build.gradle 수정
잦은 배포로 Jar 파일명이 겹칠 수도 있다. 이를 대비해서 자동으로 버전 값이 변경되도록 해준다.
빌드할 때마다 시간이 버전에 추가되도록 변경
이제 깃허브로 푸시한다.
2. 배포 진행시 CodeDeploy 로그로 잘 진행되는지 확인
cd /opt/codedeploy-agent/deployment-root/deployment-logs
sudo vi codedeploy-agent-deployments.log
책에 나온대로 tail -f로 해도 된다.
버전값에 빌드 시간을 포함한 파일명으로 저장되고 있는 것을 알 수 있다.
그런데 start.sh 다음에 health.sh가 실행되어야 하는데, 로그가 제대로 나오지 않았다.
오류1
health.sh 실행과정이 아예 진행되지 않았다...
그 이유는 깃허브에 health.sh를 비워둔채 푸시했기 때문이었다..글로 작성하면서 하고있는데, 글에 health.sh를 주석을 달아서 작성하고 그걸 가져와서 쓴다는게 깜빡하고 빈채로 푸시한 상황!
어쩐지 오류가 났으면 과정 중에 출력이 나와야 하는데 아무것도 나오지 않았었다 아무것도 없으니 안 나오는게 맞다.
파일을 푸시할 때, 제대로 작성했는지 점검하자!!
오류2
다시 푸시했더니 이번엔 travis ci가 실패했다.
Version 2 of the Ruby SDK will enter maintenance mode as of November 20, 2020. To continue receiving service updates and new features, please upgrade to Version 3. More information can be found here: https://aws.amazon.com/blogs/developer/deprecation-schedule-for-aws-sdk-for-ruby-v2/
원인을 찾기위해 로그를 보니 Health check의 응답을 알 수 없거나 혹은 실행 상태가 아닙니다.가 나온다.
8080 서버를 띄우고 profile을 가져오지 못하는 것 같았다.
찾아보다 이 이슈 글(https://github.com/jojoldu/freelec-springboot2-webservice/issues/232)을 보고 start.sh에 잘못된 부분이 있는지 확인했다.
start.sh에 Dspring 부분을 한 줄로 작성해야 하는데 줄바꿈을 하는 바람에 properties 파일들을 제대로 못 읽은 것 같다.
수정 후 다시 배포
switch.sh까지 실행완료됐다. 배포 성공
profile을 확인해보면 real -> real1로 바뀌었다.
스프링부트 로그를 확인하려면 아래 명령어를 입력하면 된다.
vim ~/app/step3/nohup.out
3. 한번더 배포하고 real2로 배포되는지 확인
스프링 부트로 시작하는 웹서비스 Ver.2 -> 스프링 부트로 시작하는 웹서비스 완성!으로 바꿔주고 배포
배포중인 상태에서 새로고침을 해도 접속이 끊기지 않는다.
배포가 완료되면
바꾼 내용이 적용된다! 이어서 profile을 확인하면 real2로 되어있다.
2번 배포를 진행한 후 자바 애플리케이션 실행 여부를 확인해보면
ps -ef | grep java
보면 책과 달리 step2 애플리케이션도 실행되고 있다. kill하지 않았기때문에 실행되고 있는게 맞다.
step2와 step3의 포트를 다르게 해놓았기 때문에 step2로 인해 step3가 문제가 생기지는 않는다. 종료하려면 kill 명령어를 사용하면 된다.
참고(https://github.com/jojoldu/freelec-springboot2-webservice/issues/196)글을 보니 저자분께서 step3가 안되면 step2를 참고해서 수정할 수도 있기에 강제 종료하는 부분을 책에는 포함하지 않으셨다고 한다.
오늘부로 스프링부트와 aws로 혼자 구현하는 웹서비스 책을 다했다! 11장은 1인 개발시 도움이 될 도구와 조언 부분이기에 따로 글로 작성하진 않을 예정이다.
'스프링부트와 AWS로 혼자 구현하는 웹서비스' 카테고리의 다른 글
Travis CI 배포 자동화 - Travis CI와 AWS S3, CodeDeploy 연동 (0) | 2023.04.13 |
---|---|
Travis CI 배포 자동화 - Travis CI와 프로젝트, Travis CI와 AWS S3 연동 (0) | 2023.04.06 |
EC2 서버에 프로젝트 배포하기 - 스프링부트 프로젝트로 RDS 접근 및 EC2에서 소셜 로그인 (0) | 2023.03.29 |
EC2 서버에 프로젝트 배포하기 - EC2에 프로젝트 Clone 및 배포 스크립트 작성(외부 Security 파일 등록) (0) | 2023.03.27 |
AWS에 데이터베이스 환경 구축 - 내 PC에서 RDS 접속과 RDS와 EC2의 연동 확인 (0) | 2023.03.15 |
댓글