이번 개인 과제 중 AWS를 실습하는 부분이 있는데, 요구사항은 다음과 같다. 먼저 EC2와 RDS를 구축하고 연결하는 과정을 기록해보려고 한다.✍🏻
✔️ EC2
- EC2 인스턴스에서 어플리케이션을 실행한다.
- 탄력적 IP를 설정해 외부에서도 접속할 수 있도록 한다.
- 서버 접속 및 Live 상태를 확인할 수 있는 health check API를 만든다.
✔️ RDS
- RDS 데이터베이스를 구축한다.
- EC2에서 실행되는 어플리케이션에 연결한다.
✔️ S3
- S3 버킷을 생성한다.
- 유저의 프로필 이미지 업로드 및 관리 API를 구현한다.
인텔리제이에서 프로젝트를 빌드해보자! EC2 인스턴스는 이미 만들어놨다는 가정 하에 진행하겠다.
1) Gradle 탭에서 Task - build
에서 왼쪽에 톱니바퀴 모양이 있는 build를 두 번 클릭한다.
2) BUILD SUCCESSFUL
메시지가 뜨고 빌드가 정상적으로 수행되었다면 프로젝트에서 build - libs
에 생긴 파일을 확인한다.
여기서 expert-0.0.1-SNAPSHOT.jar
파일을 EC2로 보내야 한다.
🤔 .jar
파일이 뭐길래...?
⚠️ 빌드 과정에서 발생한 오류
Error creating bean with name 'jwtAuthenticationFilter' defined in file ...
오류JwtAuthenticationFilter
클래스가 JwtUtil
을 주입받으려고 했는데 스프링 컨테이너에 JwtUtil
빈이 등록되어 있지 않아 발생한 오류이다.JwtUtil
을 Mock으로 주입해 해결했다.@WithMockUser
을 추가해 테스트용으로 가짜 인증 객체(SecurityContext)에 넣어 해결했다.1) 로컬에서 .jar
파일을 EC2로 보낸다. 로컬에서 다음 명령어를 입력한다.
나는 window라서 wsl에서 입력했다.
scp -i key.pem build/libs/expert-0.0.1-SNAPSHOT.jar ubuntu@EC2_IP:/home/ubuntu/
혹시 key.pem
과 빌드된 파일이 다른 곳에 있다면 각 경로를 입력해줘야 한다. 나는 각자 다른 곳에 있어서 다음과 같이 경로를 하나하나 입력했다. 만약 잘 전송됐다면 왼쪽에 파일명이 뜨고 오른쪽에 100% 라고 뜰 것이다.
2) EC2에 접속한다.
key.pem
이 있는 폴더에서 다음과 같이 입력한다.
ssh -i key.pem ubuntu@EC2_IP
이렇게 Welcome to Ubuntu~라는 글자가 나오면 정상적으로 접속된 것이다.
3) EC2에서 Spring boot 서버를 백그라운드로 실행한다.
우선 ls
명령어를 통해 실제로 EC2에 .jar
파일이 있는지 확인한다. 파일이 제대로 있다면 다음 명령어를 입력한다.
nohup java -jar expert-0.0.1-SNAPSHOT.jar &
nohup
: no hang up의 줄임말로, 터미널 연결이 끊겨도 프로세스가 죽지 않고 계속 실행된다. 로그는 기본적으로 nohup.out
파일에 저장된다.java -jar expert-0.0.1-SNAPSHOT.jar
: java 명령어로 .jar
파일을 실행한다. Tomcat이 내장되어있어 8080
포트에서 바로 실행된다.&
: 해당 명령어를 백그라운드로 실행한다. 터미널에서 바로 다음 명령어를 입력할 수 있고, 실행된 프로세스는 PID를 부여받아 별도로 동작한다.서버가 잘 실행된다면 다음과 같이 뜰 것이다.
[1]
: 백그라운드 작업 번호16824
: 실행된 프로세스의 PID (Process ID)nohup: ignoring input and appending output to 'nohup.out'
: 터미널 입력을 무시하고 모든 출력(로그)을 nohup.out 파일에 저장하겠다는 의미⚠️ 배포 과정에서 발생한 오류
application.properties
에서 DB 설정을 주석 처리한후 다시 빌드했다.ps -ef | grep java
명령어를 이용해 PID를 확인 후, kill -9 [PID]
명령어로 기존 프로세스를 종료한 후, 다시 서버를 실행한다.8080
포트가 열려 있는지 확인한다. 만약 열려있지 않다면 다음과 같이 Inbound rules에 8080
포트를 추가한다.nohup java -jar expert-0.0.1-SNAPSHOT.jar &
명령어 오류 : nohup: failed to run command 'java': No such file or directory
라는 오류 메세지가 나타났다. EC2 인스턴스에 Java가 설치되어 있지 않아서 발생한 오류이다. 다음과 같은 명령어를 입력해 Java를 설치 후 다시 시도한다.sudo apt update
sudo apt install openjdk-17-jdk -y
EC2 대시보드에서 Network & Security - Elastic IPs
를 클릭한다.
Allocate Elastic IP address
클릭하고 Amazon에서 제공하는 IP를 선택 후 Allocate 한다.
생성된 Elastic IP를 선택하고 Actions - Associate Elastic IP address
를 누른다.
연결할 인스턴스를 선택 후 Associate 한다.
이제 Public IP 대신 Elastic IP를 사용하면 된다. Elastic IP를 사용하면 인스턴스를 재시작해도 IP가 변하지 않고, Route53이나 외부 DNS에서 연결을 쉽게 할 수 있다. 그런데 연결이 안 된 EIP는 비용이 발생한다고 하니 꼭 인스턴스 연결 상태를 확인하자!
RDS 인스턴스를 생성 했다면, EC2와 RDS를 연결해야 한다.
기존에 EC2가 속한 보안그룹을 RDS에 추가한다. 나는 launch-wizard-2 라는 이름의 보안 그룹을 EC2에 적용했으므로 RDS에도 같은 것을 적용했다.
그리고 RDS 보안 그룹 Inbound rules에 MySQL/Aurora 포트(TCP 3306)를 추가했다. RDS 인스턴스는 AWS 내에서 격리되어 있기 때문에 외부에서 바로 접근할 수 없다. 따라서 RDS의 보안 그룹에서 MySQL/Aurora 포트(3306)를 허용해야, EC2 인스턴스의 보안 그룹 또는 특정 IP가 RDS와 연결될 수 있다.
application.properties
에 다음과 같이 RDS 연결 정보를 작성했다.
spring.datasource.url=jdbc:mysql://<엔드포인트>:<포트>/<DB명>
spring.datasource.username=admin
spring.datasource.password=비밀번호
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url
: RDS 엔드포인트 + 포트 + DB명spring.datasource.username
: RDS 사용자명spring.datasource.password
: RDS 비밀번호driver-class-name
; MySQL 사용 시 추가참고로 RDS 엔드포인트는 RDS 내 데이터베이스에 들어가면 나와있다.
이제 위에서 EC2로 배포할 때 했던 과정을 다시 해주면 된다.
.jar
파일 전송health check를 위해 다음 의존성을 추가한다.
implementation 'org.springframework.boot:spring-boot-starter-actuator'
다음은 application.properties
에 추가하는 설정으로, RDS 연결 확인을 위해 필요하다.
management.endpoint.health.show-details=always
management.health.db.enabled=true
management.endpoint.health.show-details=always
when-authorized
로, 권한이 없으면 status: "UP"
만 보여준다.management.health.db.enabled=true
health check로 확인해보면 다음과 같이 tjqjdmlDB가 정상적으로 돌아가고 있는 것을 알 수 있다.
위 결과에서 기본 경로가 /actuator/health
가 아니라 그냥 /health
인데, 아래 설정을 추가하면 /actuator
없이 루트 경로로 health check가 가능하다.
management.endpoints.web.base-path=/