[AWS] Elastic Beanstalk으로 SpringBoot 서버 배포하기 (2024/1월 15시간의 삽질 기록 - 완 -)

Ogu·2024년 1월 17일
2

프로젝트를 진행하며 지속적으로 수동 API 명세서를 수정해 공유하기가 어렵다 보니, 서버를 배포하여 Swagger를 통해 즉각적인 협업이 가능하도록 하기로 결정했습니다. 두렵지만 하나하나 차근차근 해보겠습니다!
우선은 간단하고 쉬운 배포를 위해 설정이 간편한 Elastic Beanstalk 으로 배포하기로 결정했습니다.

IAM 역할 생성하기

우선, AWS사이트에 로그인하여 리전 설정을 서울로 해줍니다!
(살고 있는 위치에서 가까울수록 응답 속도 등이 빠르기 때문)

IAM > 역할 에서 역할 생성 을 누릅니다.

엔터티 유형으로 AWS 서비스를 선택하고, 사용 사례로 EC2 를 선택하고 다음으로 넘어갑니다.

권한 정책에서 다음 세가지를 추가합니다.

  • AWSElasticBeanstalkWebTier
  • AWSElasticBeanstalkWorkerTier
  • AWSElasticBeanstalkMulticontainerDocker

역할 이름을 aws-elasticbeanstalk-ec2-role 과 같이 설정합니다. 다른 이름을 사용한다면 EB 생성에서 설정을 위해 기억해주세요!

밑에 신뢰할 수 있는 엔터티 선택이 잘 추가되었는지 확인하고,
역할 생성을 눌러 마무리합니다.

Elastic Beanstalk 서비스 생성하기

검색창에서 Elastic Beanstalk을 검색해 해당 서비스로 들어갑니다.

애플리케이션 생성을 눌러 서비스를 생성합니다.

다음과 같이 환경 티어는 웹 서버 환경으로 변경하지 않고, 애플리케이션 이름을 설정합니다.

환경 이름과 도메인도 서비스에 맞게 간단하게 설정했습니다.

플랫폼에서 유형은 고정하고, Java, 프로젝트의 자바 버전과 Amazon Linux 2023 을 선택합니다.

사전 설정은 기본값인 단일 인스턴스(프리 티어)로 놔둡니다. 이후 다음으로 넘어갑니다.

서비스 액세스에서는

  • 서비스 역할 : 새 서비스 역할 생성 및 사용
  • EC2 인스턴스 프로파일 : aws-elasticbeanstalk-ec2-role(아까 설정한 IAM 역할)
    을 선택하고 검토 단계로 건너뛰기를 눌러 넘어갑니다.

설정 내역들을 확인하고 제출을 눌러 생성합니다.

Elastic Beanstalk에서 RDS 생성하기

이제 클라우드에 올릴 데이터베이스로 아마존 RDS서비스를 사용합니다. 이 역시 ElasticBeanstalk의 메뉴를 이용해 간편하게 구축할 수 있습니다.

해당 Elastic Beanstalk에서 구성 > 네트워킹 및 데이터베이스 > 편집을 누릅니다.

다음과 같이 엔진을 mysql로, 인스턴스 클래스는 프리티어를 지원하는 db.t2.micro

이후 RDS의 사용자이름, 암호를 설정하고 삭제 정책은 추가 비용이 발생할 수 있으므로 그대로 두었습니다. 적용을 눌러 생성합니다. (아직 테스트 dev 환경이라 해당 환경을 삭제할 때 DB까지 모두 함께 삭제하도록 설정했습니다.)

데이터베이스가 생성되었다면 엔드포인트를 복사합니다.

ElasticBeanstalk RDS 환경 속성 설정하기

다시 구성에 가서 업데이트, 모니터링 및 로깅에서 편집을 누릅니다.

가장 아래로 내려가서 다음과 같이 필요한 환경 속성을 추가합니다. 먼저 default로 있던 모든 TCP 유형의 인바운드 규칙은 삭제하고 진행합니다.

  • SPRING_DATASOURCE_URL : jdbc:mysql://rds엔드포인트:포트/DB이름
  • SPRING_DATASOURCE_USERNAME : 앞서 설정한 RDS 사용자 이름
  • SPRING_DATASOURCE_PASSWORD : RDS 비밀번호

이렇게 설정한 환경 속성 값은 애플리케이션 실행 시 스프링 부트의 환경 변수, 즉 properties.yml 파일의 설정 값의 역할을 합니다.
application.yml 에서 spring 항목의 datasource 항목들을 지웁니다.

ElasticBeanstalk 기타 환경 속성 설정하기

그리고 아래와 같이 SERVER_PORT와 active할 profile도 설정합니다!
(profile은 yml파일을 환경별(local, dev, prod 등)로 분리하였을 때만 자신의 환경에 맞게 설정합니다!
)

~~

🤔 SERVER_PORT를 5000으로 설정하는 이유
Elastic Beanstalk는 nginx를 역방향 프록시로 사용하여 애플리케이션을 포트 80의 Elastic Load Balancing 로드 밸런서에 매핑합니다. Elastic Beanstalk는 확장하거나 자체 구성으로 완전히 재정의할 수 있는 기본 nginx 구성을 제공합니다.
기본적으로 Elastic Beanstalk는 요청을 포트 5000의 애플리케이션에 전달하도록 nginx 프록시를 구성합니다. PORT 환경 속성을 기본 애플리케이션이 수신 대기하는 포트로 설정하여 기본 포트를 재정의할 수 있습니다.

🔔 주의! 현재 AWS 정책이 바뀌면서 환경 속성 변수 네이밍도 변경되었습니다.
공식 문서에는 변경된 환경 속성 네이밍들이 나오지만, 배포 성공 후 테스트 결과 아래 설정으만 했을 때 502 Bad Gateway가 떴습니다. 위의 기본적인 yml기반 설정 (SPRING_DATASOURCE_URL, SPRING_DATASOURCE_USERNAME, SPRING_DATASOURCE_PASSWORD, SERVER_PORT)만 제대로 입력해주시면 됩니다.
대체 저 아래 공식 문서의 바뀐 Elastic Beanstalk RDS 연결 환경 속성은 왜 존재하는 것일까요,,? 아래 설정만으로 성공하신 분은 댓글 남겨주세요!

~~-RDS_HOSTNAME : RDS 엔드포인트에서 뒤에 포트(:3306)를 지운 값

  • RDS_PORT : 엔드포인트 뒤의 포트: 3306
  • RDS_DB_NAME : ebdb (rds DB이름)
  • RDS_USERNAME : RDS USERNAME
  • RDS_PASSWORD : RDS PW
    elastic beanstalk에서 RDS 생성시 DB네임이 default로 ebdb로 생성되는 것 같습니다.
    ~~


따라서 다음과 같이 환경 속성을 변경합니다.

자세한 것은 공식 문서를 참고하세요!
https://docs.aws.amazon.com/ko_kr/elasticbeanstalk/latest/dg/java-rds.html

로컬에서 RDS 연결하기

로컬에서 사용하던 H2 대신 AWS의 RDS를 사용해봅시다.
RDS는 H2처럼 데이터를 콘솔에서 조회할 수 없어서, DB 툴을 사용합니다.

먼저, 구성에서 데이터베이스 영역의 엔드포인트를 눌러 데이터 베이스 관리 페이지로 이동합니다.
(저는 연결이 되지 않아 RDS로 직접 들어가서 설정하였습니다.)

그리고 우리 로컬에서 DB에 접근할 수 있도록 로컬의 ip를 허용해야 합니다. DB식별자의 링크를 눌러 이동하고, [연결&보안] 탭의 보안 그룹에 있는 VPC 보안 그룹 하이퍼링크를 클릭합니다.

해당 보안 그룹의 name을 클릭하고, 인바운드 규칙 편칩을 누릅니다.

기본값을 수정하여

  • 유형 : MYSQL/Aurora
  • 소스 : 내 IP를 선택하고 저장을 누릅니다.
    이제 로컬에서 elastic beanstalk DB에 접근할 수 있습니다.
    🎈 기존의 EC2 보안그룹이 선택되어 있는 것을 삭제하지 마세요! 기존 보안그룹의 모든 TCP를 MySQL/Aurora로 바꿔도 무방합니다.

이제 elastic beanstalk 데이터베이스에 연결할 수 있는지 확인하겠습니다. 인텔리제이에서 database navigator 플러그인을 설치해 DB를 연결합니다.

그럼 이제 메뉴바에 DB Navigator 플러그인이 추가되어 있는 것을 볼 수 있습니다. settings를 눌러 접속 설정을 하겠습니다.

왼쪽 상단의 초록색 + 버튼을 눌러 MySQL을 선태합니다. 이후 같이 Name, Description, Host(포트 제외), Port, User, Password를 입력해주세요. 위의 환경속성에서 설정한 값이랑 동일합니다.
Test Connection을 눌러 접속을 확인합니다. 잘 접속이 되었다면 Apply, OK(확인)을 누릅니다.

🤬 Error

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.

갑자기 접속이 안되는 현상이 일어났는데, 바보같이 핫스팟에서 와이파이(네트워크)로 바꿔서 다른 것으로 접속하고서는 왜 연결이 안되지? 하고있었다. IP가 바뀌었기 때문에 해당 IP도 보안 그룹에 추가해주어야 한다!!

다시 메뉴바에서 DB Browser를 열고 다음과 같이 새로운 SQL 콘솔창을 엽니다.

다음과 같이 테이블 생성 SQL문을 작성하고 실행시킵니다.
(ddl-auto를 create 또는 create-drop으로 설정했을 경우 DDL을 따로 작성하지 않아도 됩니다.)

기존에 작성한 Entity 클래스의 테이블 생성문(DDL)은 다음 아이콘을 누르면 자동으로 생성해줍니다.


이제 AWS의 RDS MySQL을 사용하므로 프로젝트를 빌드하여 배포하기 전에 해당 의존성을 추가해야 합니다! build.gradle에 mysql 의존성을 추가하고 새로고침을 누릅니다.

dependencies {
	... 생략
    implementation 'com.mysql:mysql-connector-j'
}

Elastic Beanstalk에 서비스 배포하기 (.jar)

어플리케이션 배포하기

인텔리제이의 Gradle 탭에서 Task > build > build를 눌러 빌드합니다.

빌드가 정상적으로 되었다면 build > libs 폴더에 빌드된 .jar 파일이 생기는데요, 이 파일을 기억하기 쉬운 위치에 복사합니다.

이제 우리의 Elastic Beanstalk 서비스로 돌아가서, 업로드 및 배포를 누르고 jar파일을 선택합니다.

EC2 인스턴스 포트 개방하기

다음과 같이 EC2의 인바운드 규칙 편집에서 HTTP, HTTPSAnywhereIP4로 누구든 해당 포트에 이용이 가능하게끔 0.0.0.0/0를 설정합니다.
(추후에는 프론트의 IP만 허용하도록 변경할 예정입니다.)

🎈 8080 포트를 따로 개방하지 않아도 되는 이유는, 앞서 설명드렸듯 Elastic Beanstalk는 nginx를 역방향 프록시로 사용하여 애플리케이션을 포트 80의 Elastic Load Balancing 로드 밸런서에 매핑하기 때문입니다. 또한 기본적으로 Elastic Beanstalk는 요청을 포트 5000의 애플리케이션에 전달하도록 nginx 프록시를 구성하죠!

그리고 SSH는 내 IP만 허용해서 반드시 자신만 조작이 가능하게끔 설정해아합니다.

EC2도메인에 접속하여 확인!

두근두근! ec2의 도메인에 접속해볼까요?

흑흑ㄱ 15시간의 전투 끝에 드디어 때려눕혔습니다.. ㅜㅡㅜㅠㅡㅠㅜ

PostMan으로도 API 잘 요청되네요!

정말 정신이 나가버리는 줄 알았고 너무 짜증나서 울고 멍때리고 했었는데, 여기저기 블로그와 책에서 제대로된 정보가 없어서 정말 이것저것 다 테스트해봤던 것 같습니다. (502 GateWay 뜨는게 당연한건데.. AWS에 대한 기본적인 이해가 다들 없으신 채로 책과 블로그들을 따라하다 보니 그런 것 같네요. 어떤 보안그룹에서 어떤 포트를 열어주는지 등등)
결국 제가 이겼습니다^^

여러분의 소중한 시간 꼭 지키세요!


배포 오류 보는 TIP

Elastic Beanstalk의 로그 탭에서 오른쪽 로그 요청 버튼을 눌러 마지막 100줄 또는 전체를 누르고 txt파일을 다운받아 로그를 확인합니다.
전체를 요청하면 유형이 bundle로 , 마지막 100줄을 요청하면 tail로 뜹니다.

인텔리제이에서 볼 수 있는 스프링부트 서버 가동 시 로그들은 아래 파일에서 확인할 수 있습니다. var/log/web.stdout.log

따라서 먼저 스프링부트 내 설정이나 RDS가 제대로 연동이 되었는지 해당 파일로 먼저 확인을 하시고, 스프링부트는 잘 띄워졌는데 (로그에 오류가 없는데) 502BadGateWay가 뜬다면 EC2 등의 서버쪽 오류이니 다른 곳에서 오류를 확인해보세요! (먼저 SpringBoot의 오류가 없는지 확인하고, 마지막 100줄 로그로 Error를 검색해서 하나하나 살펴봅니다!)

참고

설정 Error 관련

profile
私はゲームと日本が好きなBackend Developer志望生のOguです🐤🐤

0개의 댓글