JUINTINATION
AWS 엘라스틱빈스톡과 RDS(MariaDB) 연동하기 본문
이 글은.. 삽질을 아주아주 많이하고나서 작성하는 글이다. (혹시라도 제 글을 읽으면서 따라할 분이 계시다면 이 글을 꼭 전부 다 읽고 나서 실행하세요..!) 아무튼 이번엔 엘라스틱빈스톡과 RDS(DB)를 연동해 볼 것이다. 먼저 이전에 만들었던 엘라스틱빈스톡을 종료해야 한다.
기존의 엘라스틱빈스톡 종료
이미 종료를 누른 상태라서 활성화가 되지 않아있지만, 아무튼 이전에 만들었던 환경에서 작업 버튼을 눌러 환경 종료를 누른다.
이후 애플리케이션 탭으로 넘어가 위와 같이 애플리케이션 삭제를 진행한다.
위의 과정이 끝나면 EC2의 인스턴스 탭으로 들어가보면 인스턴스 상태가 종료됨으로 바뀐 것을 확인할 수 있다. 몇 시간이 지나면 해당 인스턴스는 아예 사라지게 된다.
이후 보안 그룹에서 지금까지 삽질 및 연구로 만들어진 여러 보안 그룹을 default를 제외하고 모두 삭제한다. 엘라스틱빈스톡이 정상적으로 종료되고 보안 그룹에 연결된 인스턴스가 없을 때 보안 그룹이 정상적으로 삭제될 것이다.
새로운 엘라스틱빈스톡 환경 구축
자세한 내용은 예전에 작성했던 AWS 엘라스틱빈스톡 생성하기를 참고하면 좋을 것 같다.
애플리케이션 이름은 aws-v4-beanstalk으로 지정했다.
플랫폼은 Java에 Corretto 11 running on 64bit Amazon Linux 2로 설정했다.
서비스 액세스 구성은 위와 같이 기존 서비스 역할 사용으로 진행했다.
이 화면은 건들지 않고 다음 버튼을 눌렀다. 여기서 데이터베이스를 생성하게 되면 아래에서 생성할 RDS의 최소 용량인 20기가에 추가적인 데이터베이스 용량이 할당되므로, 20기가를 넘으면 과금이 되는 정책으로 인해 과금이 될 것이다. 알고 싶지 않았다.
다음 화면에서 쭉 내리면 위와 같이 인스턴스 유형을 선택하는 칸이 있는데 삽질을 계속하다가 코딩애플님의 유튜브 영상 하나를 보게 되었고, 이전에 건너뛰기로 만들었던 환경은 유료인 인스턴스 유형인 것 같다는 생각이 들었다.
그래서 유튜브 내용을 참고하여 위와 같이 t2.micro 하나로 수정했다.
앞선 페이지에서 다음 버튼을 누르면 이렇게 환경 속성을 확인할 수 있는데, 이건 나중에 수정할 것이다.
이렇게 엘라스틱빈스톡을 다시 생성하는 과정은 끝났지만, 이론적인 내용은 다 제쳐두더라도 RDS 생성 및 접속을 위해서는 추가적인 설정이 더 필요하다.
엘라스틱빈스톡 환경의 구성 탭으로 돌아가보면 아래의 업데이트, 모니터링 및 로깅 부분에서 편집 버튼을 누른다.
이후 위와 같이 RDS_HOSTNAME, RDS_DB_NAME, RDS_PORT, RDS_USERNAME, RDS_PASSWORD를 추가해야 한다. 이때 IP주소는 RDS를 생성한 이후에 수정할 것이며, 위와 같이 설정을 해두면 프로젝트에 데이터베이스의 정보를 적어두지 않기 때문에 노출이 되지 않는다는 점이 장점이다.
RDS 생성 및 접속
rds를 검색한 뒤 클릭한다.
이 화면에서 데이터베이스 생성 버튼을 누른다. 여기서부터는 책에 내용이 (또) 없어서 거의 대부분은 다른 블로그들을 참고하면서 프리스타일로 진행했다.
위와 같이 표준 생성, MariaDB를 선택한다.
엔진 버전은 따로 수정하지 않고, 템플릿은 프리 티어를 선택했다.
설정에서 DB 인스턴스 식별자는 aws-v4-rds, 자격 증명 설정에서 사용자 이름을 metacoding, 암호는 metacoding1234로 설정한다.
인스턴스 구성은 따로 건들지 않았다.
스토리지 또한 따로 건들지 않았는데, 아래에 보이는 스토리지 자동 조정은 단순 학습이 목적이기 때문에 체크를 해제해줬다.
연결 부분 또한 처음에 건들지 않았다. 하지만 이후의 실습을 위해 퍼블릭 액세스는 예로 선택했어야 했다.. 퍼블릭 액세스를 허용해 줘야 외부에서 누구나 접근이 가능한 상태가 되며, 로컬 컴퓨터에서만 외부 접근이 가능하도록 설정할 것이다.
아래의 VPC 보안그룹은 default를 빼고, 위에서 생성된 엘라스틱빈스톡 인스턴스의 보안 그룹을 선택해야 한다. 그리고 추가 구성을 열어 데이터베이스 포트는 3306으로 설정했다.
이 부분도 따로 건드린 부분이 없다.
아래의 추가 구성을 열고 마찬가지로 단순 학습이 목적이기 때문에 자동 백업은 비활성화시켰다.
위의 부분도 따로 건든 부분이 없다.
위의 설정이 끝났다면 데이터베이스 생성 버튼을 누르면 된다.
생성이 완료됐다면 위와 같이 데이터베이스 탭에서 aws-v4-rds를 볼 수 있을 것이다.
해당 데이터베이스로 들어가면 연결 및 보안에서 엔드포인트를 확인할 수 있다. 이때 보이는 엔드포인트는 나중에 쓰이므로 따로 복사를 해두는 것이 좋다.
밑으로 쭉 내려 보안 그룹을 클릭한다.
여기서 또 보안 그룹 ID를 클릭한다.
여기서 인바운드 규칙을 수정해야 한다. 현재 해당 보안 그룹은 EC2와 RDS가 같이 사용하고 있는데, 보안 그룹 탭에서 RDS의 3306 포트를 열어줘야 한다.
위와 같이 인바운드 규칙을 편집해야 하는데, 이때 3306 포트는 내 ip에만 열어줘서 내 로컬 컴퓨터에서만 접근이 가능하게 해야 하며, 또한 EC2가 RDS에 연결이 가능해야 하기 때문에 EC2에게도 3306 포트를 열어줘야 한다.
RDS 생성 및 접속
이 책에서는 윈도우 환경에서 RDS에 접속하기 위해 HeidiSQL을 설치해줘야 한다고 하는데, 나는 지금 Mac 환경이기 때문에 다음의 과정을 진행했다.
먼저 VSC 익스텐션에서 SQLTools MySQL/MariaDB/TiDB 플러그인을 설치해준다.
이후 Command + Shift + P
를 눌러 SQLTools Management: Add New Connection
을 선택한다.
이후 위와 같은 화면이 뜨면 MariaDB를 선택하고 넘어간다.
이후 위와 같이 세팅을 진행한다.
- Connection name: aws-v4-mariadb
- Server Address: RDS 엔드 포인트
- Database: mysql
- Username: metacoding
- Password: metacoding1234
이후 TEST CONNECTION 버튼으로 테스트를 진행해본 뒤 문제가 없다면 SAVE CONNECTION 버튼을 눌러 다음으로 넘어간다.
이 화면이 뜨면 CONNECT NOW 버튼을 눌러 넘어간다.
이후 이 화면이 뜬다면 위와 아래의 쿼리문을 실행한다.
-- 데이터베이스 생성
CREATE DATABASE metadb;
-- 데이터베이스 선택
USE metadb;
-- 데이터베이스 문자 인코딩 세팅
ALTER DATABASE metadb CHARACTER SET = 'utf8mb4' COLLATE = 'utf8mb4_general_ci';
-- 데이터베이스 문자 인코딩 세팅 확인
SHOW VARIABLES LIKE 'c%';
-- 테이블 생성
CREATE TABLE Book (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(255),
content VARCHAR(255),
author VARCHAR(255)
);
-- 테이블 잘 생성되었는지 확인 및 검증
SELECT * FROM Book;
오른쪽 화면과 같이 No data가 뜬다면 정상적으로 테이블이 생성된 것이다.
추가적으로 TablePlus로도 위와 같이 세팅하여 테스트해볼 수 있다.
마찬가지로 아까 쿼리문으로 만든 Book 테이블이 정상적으로 생성된 것을 볼 수 있다.
위의 과정까지 모두 마쳤다면, 다시 엘라스틱빈스톡의 환경 -> 구성 -> 업데이트, 모니터링 및 로깅 부분에서 편집 버튼을 눌러서 아까 ip주소로 넘겨 지나갔던 RDS_HOSTNAME을 RDS의 엔드포인트로 변경한 후 적용 버튼을 누른다.
배포 및 테스트
위와 같이 프로젝트를 클론한 뒤 application.yml의 active profile이 prod인지 확인한다. dev일 때의 테스트 등은 실제로 진행하긴 했지만 일단 넘어가도록 하겠다.
이후 gradlew에 실행 권한을 부여한 뒤 빌드하여 build/libs 디렉터리에 jar 파일을 만든다.
위와 같이 엘라스틱 빈스톡에 배포한다. 자세한 내용은 이전에 작성한 글을 참고하면 된다.
이후 {엘라스틱빈스톡 인스턴스의 IPv4 주소}/api/book 으로 이동하면 지금은 아무런 데이터가 없기 때문에 위와 같이 빈 리스트가 나올 것이다.
프로젝트 내부 구조
그렇다면 이 프로젝트는 어떻게 RDS에 접근하는 것일까? 그 해답은 yml 설정 파일들에 있다.
application.yml
spring:
profiles:
active:
- prod
개발 중에는 active 상태를 dev로 설정해두면 application-dev.yml 파일의 설정을 사용하고, prod로 설정해두면 아래의 application-dev.yml 파일의 설정을 사용한다. application-dev.yml 파일의 내용은 h2 관련 내용으로 지금은 정리할 필요가 없을 것 같아서 넘어가겠다.
application-prod.yml
server:
port: 5000
servlet:
encoding:
charset: utf-8
spring:
datasource:
url: jdbc:mariadb://${rds.hostname}:${rds.port}/${rds.db.name}
driver-class-name: org.mariadb.jdbc.Driver
username: ${rds.username}
password: ${rds.password}
jpa:
open-in-view: true
hibernate:
ddl-auto: none
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
logging:
level:
'[org.springframework.boot.web]': INFO
여기서 datasource 부분에 주목할 필요가 있는데, 엘라스틱빈스톡을 생성할 때 환경 속성을 설정했던 것을 기억할 것이다. 환경 속성에 RDS_USERNAME: metacoding과 같은 모양으로 변수를 만들었었는데, 이 변수가 환경 변수로서 애플리케이션에 전달되는 것이다. 즉, 해당 변수를 우분투에서 환경 변수를 사용할 때와 ${ } 모양이 동일하게 ${RDS_USERNAME}로 사용할 수 있다.
OS는 환경 변수를 만들 때 .을 인식하지 못하고 _만 인식하지만, 스프링이 애플리케이션을 실행할 때 .을 _로 바꿔 OS에게 이해시켜준다. 또한 스프링이 소문자도 대문자로 변환해주기 때문에 ${rds.username}으로도 사용이 가능하다.
그래서 위와 같이 url와 username, password를 엘라스틱빈스톡을 생성할 때 설정한 환경 속성을 활용하여 나의 데이터베이스의 주소 및 포트, 이름 등의 정보를 직접 적지 않아서 보안에 도움이 되는 것이다.
Postman을 활용한 CRUD 테스트
먼저 프로젝트의 컨트롤러 부분을 확인해봐야 한다.
package site.metacoding.awsv4.web;
import java.util.List;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import lombok.RequiredArgsConstructor;
import site.metacoding.awsv4.service.BookService;
import site.metacoding.awsv4.web.dto.BookRespDto;
import site.metacoding.awsv4.web.dto.BookSaveReqDto;
@RequiredArgsConstructor
@RestController
public class BookApiController {
private final BookService bookService;
@GetMapping("/")
public String home() {
return "<h1>aws-v4</h1>";
}
@PostMapping("/api/book")
public ResponseEntity<?> bookSave(@RequestBody BookSaveReqDto reqDto) {
BookRespDto respDto = bookService.책등록(reqDto);
return new ResponseEntity<>(respDto, HttpStatus.CREATED);
}
@GetMapping("/api/book")
public ResponseEntity<?> bookList() {
List<BookRespDto> respDtos = bookService.책목록보기();
return new ResponseEntity<>(respDtos, HttpStatus.OK);
}
}
GetMapping과 PostMapping 모두 /api/book으로 되어있다. 서비스 부분의 자세한 로직은 다음 시간에 살펴보도록 하겠다. 아무튼 GET 방식으로 /api/book으로 접속하게 되면 책의 목록을 볼 수 있고, POST 방식으로 /api/book으로 BookSaveReqDto을 같이 보내면 책이 등록되는 것 같으니 BookSaveReqDto를 살펴보겠다.
package site.metacoding.awsv4.web.dto;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import site.metacoding.awsv4.domain.Book;
@NoArgsConstructor
@Getter
public class BookSaveReqDto {
private String title;
private String content;
private String author;
@Builder
public BookSaveReqDto(String title, String content, String author) {
this.title = title;
this.content = content;
this.author = author;
}
public Book toEntity() {
return Book.builder()
.title(title)
.content(content)
.author(author)
.build();
}
}
이 DTO의 필드를 보면 title, content, author가 있으며, 모두 String 타입이다. 이에 맞춰 POST 요청을 보내면 될 것이다.
먼저 GET 요청을 해당 도메인으로 전송하게 되면 똑같이 빈 리스트가 나오는 것을 확인할 수 있다.
이후 POST 요청으로 Body에 위와 같이 JSON을 작성하여 해당 도메인으로 전송하면 정상적으로 값을 확인할 수 있게 된다.
다시 기존의 도메인으로 접속하게 되면 빈 리스트가 아닌 아까 추가한 데이터가 포함된 리스트를 볼 수 있다.
결론
위에서 잠깐 언급했듯이.. 책의 내용과 달리 바뀐 부분이 많아서 삽질을 매우 매우 많이 했던 작업이었다. 카페에서 멘탈이 나갈 뻔했지만 이런 간단한 것도 내 힘으로 못 찾으면 앞으로 더 어려운 일은 어떻게 할까 싶은 마음에 정신줄을 붙잡고 끝까지 했던 것 같다. 아무튼 앞으로도 이 경험을 교훈 삼아 막힌 일을 내 힘으로 해결할 수 있는 사람이 되어야겠다.
또한 이 부분을 시작하기 전에 "RDS도 EC2같은 서버라고 했는데, RDS를 생성하면 인스턴스가 하나 더 생성되면서 과금 이슈에 문제가 되려나?" 라는 나의 작은 궁금증은 인스턴스가 새롭게 생기지 않았기 때문에 아닌걸로 해결됐다! 이틀간의 삽질 끗!
'Amazon Web Services' 카테고리의 다른 글
GitHub Actions를 활용한 CI/CD 배포 (0) | 2024.07.19 |
---|---|
CI/CD(지속적 통합/지속적 배포)란? (1) | 2024.07.19 |
AWS 엘라스틱빈스톡 내부 구성 직접 확인하기 (0) | 2024.07.16 |
AWS 엘라스틱빈스톡 프로젝트 배포 (1) | 2024.07.16 |
AWS 엘라스틱빈스톡 생성하기 (0) | 2024.07.12 |