스프링 부트와 AWS로 혼자 구현하는 웹서비스 후기 (2/2)

김설영·2022년 8월 7일
0

약 2주간의 여정이 끝이났다.

스프링 시큐리티까지는 버전 간 차이가 크지 않아 진도에 영향이 크지 않았지만,

본격적으로 AWS를 시작하면서부터 버전 간 차이로 인해 많이 막히기 시작했다.

해결하느라 애도 많이 먹었었다. 애먹었던 부분을 복기할 겸, 정리도 할 겸, 후기 2편에서는 주요 차이점에 대해 작성해보고자 한다.

주요 차이점에 대해..


1. Amazon Linux Server

  • 책에서 사용한 리눅스 서버 : Amazon Linux 1 AMI
  • 내가 사용한 리눅스 서버 : Amazon Linux 2 AMI

책에서는 Linux 1이 커뮤니티가 잘되어있으니 Linux 1 사용을 권장하고 있다. 하지만, 해당 서버는 아마존 내에서 더이상 지원하지 않는 듯 했다. 기본이 Linux 2로 되어있었고, 나는 Linux 2를 사용하였다.

Linux Server 에 따른 변경 사항

Java 설치

  • 책 : Java8
  • 나 : Java11

자바 버전과 Amazon Linux 버전에 따라, EC2 서버 내에 설치하는 방법도 달랐다.
아래의 블로그 글을 참고하면 좋다.
AWS EC2에 JDK 11 설치하기

Host 이름 변경

Linux 1 -> Linux 2로 변경됨에 따라, Host 이름을 변경하는 방식이 약간 달라졌다. 아래의 블로그 글을 참고하면 좋다.
[aws] Linux2 OS 기본 설정 - hostname 확인 및 변경

모르면 ???를 띄울 수 있는 내용

  • reboot 명령어로 EC2 서버를 재시작 한 후, 바로 접속할 수 없다. 우리의 컴퓨터가 재부팅에 시간이 걸리듯, EC2 서버도 똑같다. 나는 reboot을 하고 바로 접속을 시도하여, Operation Timeout 등의 메세지를 수도없이 띄웠다. 그 땐, 내가 잘못한게 무엇인줄 몰랐다. 너무 급한 성격이 문제였음..ㅋㅋ

2. RDS

RDS에서는 별 다른 차이점을 발견하지 못했다.


3. CI tool

  • 책 : Travis CI
  • 나 : GitHub Action

Travis CI가 지금은 유료화가 되었다. 그래서 오픈 소스 CI tool이 필요했고, 나는 GitHub Action을 선택했다. 아래의 글을 참고하면 GitHub Action을 적용하기 좋다.
Travis CI 대신 GitHub Action 적용하기


4. 배포 오류 발생 - 접속이 안되는 문제

Spring boot 2.5.0 이상에서, gradle을 사용하여 빌드를 할 경우 jar 파일이 2개가 생성된다. -> 해당 내용은 이 블로그를 참고하세요

  • 앱 이름.jar : bootJar Task로 생성된 것
    • 해당 파일은 해당 프로젝트에 필요한 모든 의존성이 같이 추가되어 있음.
    • MANIFEST.MF 파일이 정상적인 상태로 나옴(Main method 위치 기재)
  • 앱 이름-plain.jar : build Task로 생성된 것
    • 해당 파일은 의존성을 제외하고 오직 프로젝트에 있는 자원들만 Jar파일로 만든 것.
    • MANIFEST.MF 파일에 Main method의 위치가 기재되지 않은 채로 나옴

이 문제가, deploy.shJAR_NAME=$(ls -tr $REPOSITORY/*.jar | tail -n 1) 부분에서 심각한 문제를 발생시켰고, 아래와 같은 오류를 발생시킨다.

no main manifest attribute, in /home/ec2-user/app/step2/RestApiPractice-1.0.1-SNAPSHOT-plain.jar

이유는 다음과 같다.
JAR_NAME=$(ls -tr $REPOSITORY/*.jar | tail -n 1) 로직이 의존성이 전부 추가된 앱이름.jar파일을 잡지 않고 앱이름-plain.jar파일을 잡게 되면, Main 메소드의 위치를 잡지 못해 앱을 실행조차 하지 못하기 때문이다.

이는 아래 방식중 하나로 해결하면 된다.

build.gradle에 다음의 내용을 추가

jar {
	enabled = false
}
  • 위 내용을 추가해준 후 배포를 하게되면 앱이름-plain.jar가 생성되지 않는다.
  • EC2 console에서 rm {파일 이름}으로 앱이름-plain.jar를 삭제한다.
  • 그 후 배포를 하게되면 문제 없이 작동이 된다.

또는

deploy.sh 파일에서 plain이 붙은 파일을 실행 대상에서 제외

as-is

JAR_NAME=$(ls -tr $REPOSITORY/*.jar | tail -n 1) 

to-be

JAR_NAME=$(ls -tr $REPOSITORY/*.jar | grep -v "plain" | tail -n 1) 

위 내용은 아래의 글을 참고했다.

[Linux] nohup 세션이 끊겨도 계속 실행되도록 해보자
리눅스 표준 입출력 리다이렉션
[LINUX] 📚 /dev/null 과 2>&1 완벽 이해하기 (리다이렉션 기호 조합 정리)
[LINUX] 📚 입출력 재지정 & 파이프 명령어 💯 정리


5. CodeDeploy 설치 방식 변경

  • 기존
aws s3 cp s3://aws-codedeploy-ap-northeast-2/latest/install .--region ap-northeast-2
  • 변경 : 아래의 명령어를 순차적으로 실행
sudo yum update

sudo yum install ruby

sudo yum install wget

wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install

chmod +x ./install

sudo ./install auto

출처 : Amazon Linux 또는 RHEL용 CodeDeploy 에이전트 설치


6. 구동 중인 프로세스가 종료되지 않는 문제 - PID를 못 찾음

deploy.sh에 구동 중인 프로세스를 종료시켜주는 로직을 위해, PID를 찾는 로직을 넣어주었다.

# 변경 전 (문제 발생 로직)
CURRENT_PID=$(pgrep -fl RestApiPractice | grep jar | awk '{print $1}')

위의 로직은 문제가 하나 있었다. 전혀 PID를 탐색해내지 못한다는 점이었다.

  • CodeDeploy의 로그 상에는 "현재 구동 중인 애플리케이션이 없어서 종료하지 않음"으로 표기되어있고
  • Spring Boot의 로그 상에는 "8080이 이미 사용중이라 시작이 되지 않음"으로 표기되어 있었다.

PID를 왜 못찾을까? 싶어서 아래의 코드를 EC2 console에 입력 해보았다.

pgrep -fl RestApiPractice | grep jar
  • 책에 작성된 로직을 그대로 입력했을 뿐인데, PID가 검색되지 않는 것을 확인할 수 있었다.

나와 같은 경우가 존재할 것 같아서, 서치를 한 결과 아래의 두 게시글에서 해결책을 찾을 수 있었다.
깃허브 이슈 586
Spring Boot 프로젝트 ERROR : port 8080 is already in use 해결 방법

### 변경 후
CURRENT_PID=$(pgrep -fl RestApiPractice | grep java | awk '{print $1}')
  • grep으로 잡아내는 부분을 java로 변경하면 된다.

7. Nginx 설치

Amazon Linux 버전이 1에서 2로 넘어오면서, Nginx 설치 방법에도 약간의 변화가 생겼다.
Amazon Linux 2에 nginx 설치

# 변경 전
sudo yum install nginx

# 변경 후
sudo amazon-linux-extras install nginx1

그리고, Nginx 실행 결과도 약간의 변화가 생겼다.

# 변경 전
Starting nginx: [ OK ]

# 변경 후
Redirecting to /bin/systemctl start nginx.service

8. Spring Boot Profile 설정 방식

이 부분은 나도 공부가 더 필요하다. 앞으로 더 알아봐야 할 부분이지만, 나는 아래와 같은 방식으로 해결했다.
향로님께서는 profile을 group으로 설정하는 방식을 이용하셨는데, 나는 아무리 해도 진행이 되지 않았다. real 자체를 인식하지 못함.

그래서 결국 아래와 같이 real.properties, real1.properties, real2.properties에 모두 spring.profiles.include={자기자신},real-db,oauth를 때려박아줌으로써 해결했다.

물론 위와 같은 방식이 근본적인 해결일까.. 싶은 생각은 있다. 아직 반도 해결 못한 기분이다. 일단은, 나만의 프로젝트로 다시 한번 스스로 해보면서 공부하는 게 좋겠다 싶어 넘어간 부분이다.


차이점을 해결하느라 좀 많은 시간을 썼었다. 하지만, 많은 공부가 되었기 때문에 뜻깊었던 시간이라고 생각한다.
어차피 모든 tool은 업데이트되며, 계속 바뀌어간다. 그런 부분을 대처하는 학습을 조금이나마 미리 해볼 수 있었던 것 같다.

그래도,
책 덕분에, 수월하게 AWS를 사용해 볼 수 있었고 무중단 배포까지 손쉽게 경험해볼 수 있었던 것은 사실이다.
이제 이 지식들을 나의 것으로 만들기 위해 프로젝트를 몇 가지 구상해봐야겠다.

일단 복습부터 하고...

profile
블로그 이동하였습니당! -> https://kimsy8979.tistory.com/

0개의 댓글