본문 바로가기
2021 웹개발 101

[spring boot] 백엔드 어플리케이션을 AWS의 elastic beanstalk으로 배포

by Senna 2021. 12. 29.

책을 따라서 실습하다가.. 책 내용이랑 다르게 해야하는 상황이 와서..

구글링을 총동원해서 겨우 배포 성공했다. 하루 종일 걸렸다..

기념으로 기록해본다.

 

0. 준비

실행환경..?

- Windows 10

- spring boot (Gradle, jar, java11)

미리 확인

- python 설치 확인 (cmd에서 python --version)

- aws cli v2 설치 (구글링 후 .msi 파일 다운, 설치)

 

1. aws cli 설정

AWS 콘솔에서 IAM-액세스 관리-사용자

[사용자 추가] 눌러서,

사용자이름: cli-user,

액세스유형: 프로그래밍 방식 액세스... 로 설정하고 [다음: 권한] 누름.

권한설정: 기존 정책 직접 연결-AdministratorAccess 선택 후 [다음:태그], [다음: 검토], [사용자 만들기]

 

이 다음에 표시되는 화면에서 액세스키ID, 비밀 액세스 키를 복사.

 

 

+

cmd에서

$ aws configure
AWS Access Key ID [None]: <액세스키 ID>
AWS Secret Access Key [None]: <비밀 액세스키>
Default region name [None]: us-west-2
Default output format [None]: json

 

region name은 다른것도 가능..

한국 사용자가 많을 경우에는 ap-northeast-2를 쓰면 됨

+

이후에 pip로 ebcli 설치

pip install awsebcli --upgrade -user

 

+

환경변수(시스템 변수)

Path에 %USERPROFILE%/AppData/Roaming/Python/Python39/Scripts 추가.

+

마지막으로 cmd 재시작, 설치 확인

$ eb --version
EB CLI 3.19.2 (Python 3.9.0)

 

 

 

2. 환경 초기화

 

cmd에서 백엔드 프로젝트 폴더로 이동한다.

이후 eb init 입력

$eb init TodoApplication-backend

Select a default region
1) us-east-1 : US East (N. Virginia)
2) us-west-1 : US West (N. California)
3) us-west-2 : US West (Oregon)
4) eu-west-1 : EU (Ireland)
5) eu-central-1 : EU (Frankfurt)
6) ap-south-1 : Asia Pacific (Mumbai)
7) ap-southeast-1 : Asia Pacific (Singapore)
8) ap-southeast-2 : Asia Pacific (Sydney)
9) ap-northeast-1 : Asia Pacific (Tokyo)
10) ap-northeast-2 : Asia Pacific (Seoul)
11) sa-east-1 : South America (Sao Paulo)
12) cn-north-1 : China (Beijing)
13) cn-northwest-1 : China (Ningxia)
14) us-east-2 : US East (Ohio)
15) ca-central-1 : Canada (Central)
16) eu-west-2 : EU (London)
17) eu-west-3 : EU (Paris)
18) eu-north-1 : EU (Stockholm)
19) eu-south-1 : EU (Milano)
20) ap-east-1 : Asia Pacific (Hong Kong)
21) me-south-1 : Middle East (Bahrain)
22) af-south-1 : Africa (Cape Town)
(default is 3): 3

Application TodoApplication-backend has been created.
Select a platform.
1) .NET Core on Linux
2) .NET on Windows Server
3) Docker
4) GlassFish
5) Go
6) Java
7) Node.js
8) PHP
9) Packer
10) Python
11) Ruby
12) Tomcat
(make a selection): 6

Select a platform branch.
1) Corretto 11 running on 64bit Amazon Linux 2
2) Corretto 8 running on 64bit Amazon Linux 2
3) Java 8 running on 64bit Amazon Linux (Deprecated)
4) Java 7 running on 64bit Amazon Linux (Deprecated)
(default is 1): 1

Alert: You chose a deprecated platform branch. It might not be supported in the future.

Cannot setup CodeCommit because there is no Source Control setup, continuing with initialization
Do you want to set up SSH for your instances?
(Y/n): n

이제 .elasticbeanstalk 이라는 폴더가 생겼다.

 

 

3. 백엔드 어플리케이션 설정

 

application.properties 파일 수정

# application.properties 파일 내용

server.port: 5000

책이랑 다르게 엘라스틱 빈스톡의 플랫폼을 [Corretto 11 running on amazon linux 2] 로 선택했다.

(Java 8 running on 64bit amazon linux 옵션은 deprecataed 경고가 뜨기 때문...)

그래서 포트가 어떻게 되나... 여러번 시도 했었다.

근데 다른거 없었다. 포트 그냥 5000 쓰면 된다.

 

+

gadle.build의 dependencies에도 하나 추가한다.

# build.gradle 의 dependencies에 추가

runtimeOnly 'mysql:mysql-connector-java'

runtimeOnly 'com.h2database:h2'가 있어도 그 아랫줄에 새로 끼워 넣으면 됨.

 

+

그리고 새 클래스 작성

package com.example.demo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HealthCheck {
	
	@GetMapping("/")
	public String healthCheck() {
		return "The service is up and running...";
	}

}

AWS 로드밸런서는 기본 경로인 "/"에 HTTP 요청을 보내서 어플리케이션이 동작하는지 확인한다.

일라스틱 빈스톡은 이를 기반으로 어플리케이션이 실행중인 상태인지, 주의가 필요한 상태인지 확인해준다.

또 이 상태를 AWS 콘솔 화면에 표시해준다.

이를 위해서 "/"에 간단한 API를 만들어주면 좋다.

 

+

이제 spring boot 프로젝트를 build한다.

# cmd로 프로젝트 폴더까지 이동한 후

$ gradle clean build

Welcome to Gradle 7.3!

Here are the highlights of this release:
 - Easily declare new test suites in Java projects
 - Support for Java 17
 - Support for Scala 3

For more details see https://docs.gradle.org/7.3/release-notes.html

Starting a Gradle Daemon (subsequent builds will be faster)

> Task :test
2021-12-28 11:59:50.262  INFO 4408 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2021-12-28 11:59:50.272  INFO 4408 --- [ionShutdownHook] .SchemaDropperImpl$DelayedDropActionImpl : HHH000477: Starting delayed evictData of schema as part of SessionFactory shut-down'
2021-12-28 11:59:50.289  INFO 4408 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2021-12-28 11:59:50.314  INFO 4408 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.

BUILD SUCCESSFUL in 1m 11s
7 actionable tasks: 7 executed

그러면 build/libs 경로에 jar 파일이 생긴다.

버전 이름은 gradle.build 파일에서 설정할 수 있다.

 

+

.elasticbeanstalk/config.yml 에 deploy 부분 추가

# .elasticbeanstalk/config.yml 파일 내용

branch-defaults:
  default:
    environment: PROD-TODO-BACKEND
# 추가 시작
deploy:
  artifact: build/libs/demo-0.0.3.jar
# 추가 끝
global:
  application_name: TodoApplication-backend
  branch: null
  default_ec2_keyname: null
  default_platform: Corretto 11 running on 64bit Amazon Linux 2
  default_region: us-west-2
  include_git_submodules: true
  instance_profile: null
  platform_name: null
  platform_version: null
  profile: null
  repository: null
  sc: null
  workspace_type: Application

 

+

eb create 로 환경 생성 

# cmd에서 프로젝트 폴더로 이동한 후

$ eb create --database --elb-type application --instance-type t2.micro

Enter Environment Name
(default is TodoApplication-backend-dev): PROD-TODO-BACKEND
Enter DNS CNAME prefix
(default is PROD-TODO-BACKEND22):

Would you like to enable Spot Fleet requests for this environment? (y/N): N

Enter an RDS DB username (default is "ebroot"):
Enter an RDS DB master password: <비밀번호 입력>
Retype password to confirm: <비밀번호 입력>
Uploading: [##################################################] 100% Done...
Environment details for: PROD-TODO-BACKEND
  Application name: TodoApplication-backend
  Region: us-west-2
  Deployed Version: app-211228_143259
  Environment ID: e-m32zspxdmx
  Platform: arn:aws:elasticbeanstalk:us-west-2::platform/Corretto 11 running on 64bit Amazon Linux 2/3.2.9
  Tier: WebServer-Standard-1.0
  CNAME: PROD-TODO-BACKEND22.us-west-2.elasticbeanstalk.com
  Updated: 2021-12-28 05:33:32.287000+00:00
Printing Status:
2021-12-28 05:33:30    INFO    createEnvironment is starting.
2021-12-28 05:33:32    INFO    Using elasticbeanstalk-us-west-2-490191556309 as Amazon S3 storage bucket for environment data.
2021-12-28 05:33:53    INFO    Created target group named: arn:aws:elasticloadbalancing:us-west-2:490191556309:targetgroup/awseb-AWSEB-DZM8O8EKV3XS/e5c4b46318194e1d
2021-12-28 05:33:53    INFO    Created security group named: sg-0ce0bec80d01e332c
2021-12-28 05:34:09    INFO    Created security group named: awseb-e-m32zspxdmx-stack-AWSEBSecurityGroup-STVZ3AC9TCPA
2021-12-28 05:34:09    INFO    Created Auto Scaling launch configuration named: awseb-e-m32zspxdmx-stack-AWSEBAutoScalingLaunchConfiguration-1N9SNDTFZLLM5
2021-12-28 05:34:09    INFO    Created RDS database security group named: awseb-e-m32zspxdmx-stack-awsebrdsdbsecuritygroup-1vo76ck4ah7r0
2021-12-28 05:34:24    INFO    Creating RDS database named: aa17sko6ijnmpkt. This may take a few minutes.
2021-12-28 05:36:29    INFO    Created load balancer named: arn:aws:elasticloadbalancing:us-west-2:490191556309:loadbalancer/app/awseb-AWSEB-18IATENQI5FEY/208b51a89b8a681f
2021-12-28 05:36:44    INFO    Created Load Balancer listener named: arn:aws:elasticloadbalancing:us-west-2:490191556309:listener/app/awseb-AWSEB-18IATENQI5FEY/208b51a89b8a681f/9e890169d65e24ce
2021-12-28 05:42:51    INFO    Created RDS database named: aa17sko6ijnmpkt
2021-12-28 05:43:54    INFO    Created Auto Scaling group named: awseb-e-m32zspxdmx-stack-AWSEBAutoScalingGroup-1J2JGBKYPBVNS
2021-12-28 05:43:54    INFO    Waiting for EC2 instances to launch. This may take a few minutes.
2021-12-28 05:43:54    INFO    Created Auto Scaling group policy named: arn:aws:autoscaling:us-west-2:490191556309:scalingPolicy:c3bc20fd-e70e-45ea-bc76-b5c8ec638995:autoScalingGroupName/awseb-e-m32zspxdmx-stack-AWSEBAutoScalingGroup-1J2JGBKYPBVNS:policyName/awseb-e-m32zspxdmx-stack-AWSEBAutoScalingScaleUpPolicy-GI0BN5M0F3WR
2021-12-28 05:43:54    INFO    Created Auto Scaling group policy named: arn:aws:autoscaling:us-west-2:490191556309:scalingPolicy:8937a9a1-0781-4876-94f5-e21743b04e39:autoScalingGroupName/awseb-e-m32zspxdmx-stack-AWSEBAutoScalingGroup-1J2JGBKYPBVNS:policyName/awseb-e-m32zspxdmx-stack-AWSEBAutoScalingScaleDownPolicy-15LV9A4LA8XNU
2021-12-28 05:44:09    INFO    Created CloudWatch alarm named: awseb-e-m32zspxdmx-stack-AWSEBCloudwatchAlarmLow-1RTKL2U1BUJJU
2021-12-28 05:44:09    INFO    Created CloudWatch alarm named: awseb-e-m32zspxdmx-stack-AWSEBCloudwatchAlarmHigh-5BZ9YSG55UY3
2021-12-28 05:44:15    INFO    Instance deployment successfully detected a JAR file in your source bundle.
2021-12-28 05:44:15    INFO    Instance deployment successfully generated a 'Procfile'.
2021-12-28 05:44:18    INFO    Instance deployment completed successfully.
2021-12-28 05:44:51    INFO    Application available at PROD-TODO-BACKEND22.us-west-2.elasticbeanstalk.com.
2021-12-28 05:44:51    INFO    Successfully launched environment: PROD-TODO-BACKEND

배포 완료..!

 

 

5. 배포 상태 확인

AWS 콘솔 - Elastic Beanstalk - 환경에서 배포 상태 확인.

+

URL로 접속해서 위에서 작성한 HealthCheck 클래스 내용이 잘 나오는지 확인.

 

 

5. RDS DB 연결 설정

 

elastic beanstalk-구성에서 연결된 데이터베이스의 엔드포인트 클릭.

 

해당 DB 상세에서 VPC 보안그룹 눌러서 이동

 

보안그룹 - 인바운드 규칙 - 인바운드 규칙 편집

 

규칙 추가 - 유형:MYSQL/Aurora, 소스: Anywhere - 저장

 

 

+

이후에 백엔드 어플리케이션으로 돌아와서 설정 추가

# application.properties 파일 내용

server.port: 5000

spring.jpa.database=mysql
spring.jpa.show-sql=true
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.hibernate.ddl-auto=update

spring.datasource.url=jdbc:mysql://<엔드포인트 링크>:3306/<db이름>
spring.datasource.username=<rds 사용자>
spring.datasource.password=<rds 사용자 비번>

- rds 사용자/비번은 eb create에서 썼던 정보를 갖다 써도 된다..

- db이름은 보통 'ebdb'로 생성되는 듯.. 아니면 aws 콘솔 - rds - 구성에서 확인 가능

 

+

cmd에서 다시 build하고 재배포하기

$ gradlew clean build

> Task :test
2021-12-28 20:33:12.849  INFO 14328 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2021-12-28 20:33:12.854  INFO 14328 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2021-12-28 20:33:14.082  INFO 14328 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.

BUILD SUCCESSFUL in 39s
8 actionable tasks: 8 executed
$ eb deploy

Uploading: [##################################################] 100% Done...
2021-12-28 11:33:53    INFO    Environment update is starting.
2021-12-28 11:33:58    INFO    Deploying new version to instance(s).
2021-12-28 11:34:03    INFO    Instance deployment successfully detected a JAR file in your source bundle.
2021-12-28 11:34:04    INFO    Instance deployment successfully generated a 'Procfile'.
2021-12-28 11:34:07    INFO    Instance deployment completed successfully.
2021-12-28 11:34:12    INFO    New application version was deployed to running EC2 instances.
2021-12-28 11:34:12    INFO    Environment update completed successfully.

 

 

 

 

6. 작동 확인

 

url로 접속

+

POSTMAN으로 API 응답 확인

+

DB에 적용 잘 되었는지 확인해봤다.

작동.. 잘된다.

 

 

..

끝!


하루 종일 헤맸다...

해결 과정을 정리해보자면..

 

1.

처음엔 책에서 하라는데로 Java 8 running on linux로 배포를 했는데..

플랫폼 deprecated가 떠서 종료하고 다시 init 했다.

디폴트로 되어있던 Corretto 11 running on Amazon linux 2를 골랐다.

 

2.

그 후엔 계속에서 502 Bad Gateway가 떴다. 로그를 확인했더니 아래와 같았다.

connect() failed (111: Connection refused) while connecting to upstream

6시간은 헤맸다. 계속 수정-빌드-배포를 반복했다. 열번 넘게 재배포 했는데 해결 못했다.....

연결 timeout 시간도 수정해보고.. application-prod.yaml에서 포트도 바꿔보고.. setenv PORT=5000 이런것도 써보고..

근데..? 아무튼 안됨.. ㅎㅎ..

...

..

밥먹고 천천히 다시 해보기로 결정 ㅠㅠ

 

3.

application-prod.yaml, application-dev.yaml으로 나눠서 작성했던걸 다 삭제하고,

setenv했던 SPRING_PROFILES_ACTIVE=prod변수도 삭제했다. 

 

4.

application.properties를 다시 만들고, 단순하게 'server.port=5000'만 넣어서 재배포했더니

웬걸? 너무 잘되는거다.. 일단 포트가 문제가 아니었다는걸 알았다.

 

5.

이 다음은 rds db의 connection을 확인하려했다.

책에서는 ${rds.username} 이런 식으로 변수를 썼는데..

application.properties로 바꾸고 나서는 이 부분에서 자꾸 에러가 났기 때문이다.

Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to open JDBC Connection for DDL execution

여차저차 알아보다가 [rds-인바운드규칙]을 설정하고 났더니 db 접속도 잘 되고 gradlew build도 잘 되었다.

aws에 재배포하고 접속했더니 성공이었다..! ㅠㅠ 

여기까지 대략 9시간 걸림 (기절)

 

6. 요약

- 책이랑 다르게 설정하고 재배포

- 502 Bad Gateway를 돌파하려고 애 썼다. 이유를 추정하기 너무 어려웠다.

- 0으로 돌아가서, 조금씩 살 붙여가며 build했더니 뭐가 문제인지 조금씩 보였다 ㅠ

 

해결과정 끝...

 

502 Bad Gateway는 정말 이유가 너무너무 다양해서

구글링 해서 보이는 문서마다 전부 다 해결 방법이 달랐다.ㅠㅠ

(너무 막막해서 쓰러져 울고싶었다..)

잘 해결 되어서 다행이다..

 

 

이제 프론트 배포하고 CORS 대비하고 해야하는데 힘이 다 빠졋다 ㄱ-

화이팅..