AWS RDS와 Bastion Host로 데이터베이스 환경 구축하기
클라우드 애플리케이션 배포의 첫 단계는 안정적인 데이터베이스 환경을 구축하는 것입니다.
이번 실습에서는 그 첫번째 단계로 AWS의 RDS와 Bastion Host를 사용하여 데이터베이스 환경을 안전하고 효율적으로 설정하는 방법을 배웠습니다. AWS RDS는 관리형 데이터베이스 서비스로, 복잡한 설정 없이 쉽게 데이터베이스를 운영할 수 있으며, Bastion Host는 외부와 내부 네트워크 간의 안전한 접근을 제공합니다.
0. 데이터베이스 환경 구축 비교: RDS vs Bastion Host
1) Amazon RDS (Amazon Relational Database Service)
Amazon RDS는 AWS에서 제공하는 관리형 관계형 데이터베이스 서비스다. 이를 사용하면 AWS 관리 콘솔, AWS CLI, 또는 CloudFormation을 활용하여 데이터베이스를 쉽게 구축하고 관리할 수 있다.
장점
데이터베이스의 배포, 백업, 확장, 패치 적용 등 반복적인 관리 작업의 부담을 줄여준다는 장점이 있다.
단점
그러나, RDS에는 데이터베이스가 설치된 운영 체제(OS)에 직접 접근할 수 없다는 제약이 있다.
이로 인해 OS 수준의 작업이나 특정 설정 변경은 불가능하다.
이러한 제약을 보완하기 위해 Bastion Host를 사용하여 데이터베이스 관리 환경을 구성하는 경우가 있다.
2) Bastion Host란?
Bastion Host는 내부 네트워크로의 접근을 중계하는 보안성이 높은 서버다.
외부 인터넷에서 내부 네트워크로 접근하는 유일한 통로 역할을 하며, 모든 인바운드 트래픽은 Bastion Host를 통과해야만 내부 네트워크로 들어갈 수 있다. 이를 통해 보안을 강화하고 외부와의 연결을 엄격히 제어할 수 있다.
AWS에서 Bastion Host 구축
AWS에서는 EC2(Elastic Compute Cloud)를 사용하여 Bastion Host를 구축할 수 있다.
EC2를 Bastion Host로 설정하면 SSH나 RDP를 통해 내부 네트워크의 다른 리소스에 안전하게 접근할 수 있다.
Bastion Host는 보안 강화를 위해 최소 권한 원칙을 적용하며, 주기적인 보안 패치와 접근 로그 관리가 중요하다.
Bastion Host 구조를 쉽게 이해할 수 있는 구조도로는 다음 그림을 참고하면 좋을 것 같다.
이번 수업에서는 이러한 Bastion Host를 설정하고, 이를 통해 RDS와 같은 내부 리소스를 관리하는 실습을 진행했다.
1. CloudFormation 스택 생성
1) VPC 생성 & EKS 클러스터 생성
CloudFormation을 이용하여 VPC를 생성한다.
아래 글에서 eks-work-base 라는 이름의 스택을 먼저 생성하고, eksctl 명령어로 EKS 클러스터를 생성해야 한다.
1, 2번까지만 진행하고 다시 여기로 돌아오면 된다!
1. VPC 생성: eks-work-base
2. 생성한 VPC 안에 eksctl 명령어로 EKS 클러스터 생성
[AWS] EKS 클러스터 구축 방법 및 실습
실습 전 준비 과정[AWS] IAM 사용자 생성 및 액세스 키 발급 방법[AWS] EKS 구축을 위한 도구 설치: AWS CLI, eksctl, kubectlEKS 클러스터 구축하기Amazon EKS(Elastic Kubernetes Service)를 활용해 쿠버네티스 클러스
ynslee627.tistory.com
3) RDS 환경 구성
앞에서 만든 VPC 안에 CloudFormation을 통해 RDS 환경을 구성한다.
AWS 관리 콘솔에서 CloudFormation 페이지를 열어 [스택 생성]
- [기존 템플릿 선택] – [템플릿 파일 업로드]를 선택하고 [파일 선택] 버튼을 클릭하여 rds_ope_cfn.yaml을 선택한 후 [다음] 버튼 클릭
스택이름과 파라미터 설정
- 스택 이름 설정: eks-work-rds
업로드한 CloudFormation 템플릿에는 많은 파라미터가 정의되어 있지만, 초깃값이 설정되어 있지 않기 때문에 추가로 항목을 입력해야 한다.
- EksWorkVPC: eks-work-VPC 선택
- OpeServeRouteTable: CloudFormation → eks-work-base 스택 → 출력 탭 → RouteTable값 입력
나머지 옵션들은 그대로 두고 생성한다.
2. Bastion Host에서 데이터베이스 환경 구축하기
앞에서 CloudFormation으로 VPC 안에 만든 데이터베이스를 활용해보도록 하겠다.
1) 세션 관리자를 이용해서 배스천 호스트 접속
세션 관리자(Session Manager)는 EC2 인스턴스 콘솔로 접속할 수 있는 서비스이며 AWS Systems Manager 기능의 하나로 제공한다.
기존에 만들어진 Worker Node를 이용해서 RDS를 사용한다.
AWS 관리 콘솔에서는 [서비스] -> [관리 및 거버넌스] -> [Systems Manager]
Session Manager 서비스에서 [세션 시작]을 눌러서 동일한 VPC 내의 인스턴스를 선택한다.
세션 시작을 누르면 다음과 같은 화면을 볼 수 있다.
2) 필요한 도구 설치: git, postgresql
다음 명령어를 입력하여 git과 postgresql을 설치한다.
- git
- postgresql
sudo yum install -y git
sudo amazon-linux-extras install -y postgresql11
3) DB 접속을 위한 정보 확인
postgresql에 접속하기 위해 필요한 정보를 확인해야 한다.
데이터베이스 엔드포인트 주소와 관리자 비밀번호를 확인한다.
- 데이터베이스 엔드포인트: CloudFormation에서 eks-work-rds 스택을 선택한 후 출력 탭을 선택해서 RDSEndpoint 확인
- 이 엔드포인트는 VPC 내에서만 접속 가능하다. (RDS를 만들 때 퍼블릭 IP를 사용하지 않는다.)
- 관리자(eksdbadmin) 비밀번호: Secrets Manager에서 확인
- CloudFormation으로 데이터베이스 RDS 인스턴스를 구축한 경우에는 AWS Secrets Manager가 RDS 관리자 비밀번호를 생성해 데이터베이스에 등록하는데, AWS Secrets Manager로 생성한 비밀번호는 보안 암호에서 확인한다.
- 사용자 비밀번호: Secrets Manager에서 유저(mywork) 비밀번호도 확인한다.
4) EC2 세션에서 데이터베이스 연결
사용자 생성
- 관리자 이름: eksdbadmin
- 접속 URL: 관리자 보안 암호값의 <host>
- 사용자 이름: mywork
createuser -d -U 관리자이름 -P -h 접속URL 사용자이름
비밀번호를 3번 입력하는데 첫 2개의 비밀번호는 사용자의 비밀번호이고 다음 1개는 관리자의 비밀번호
데이터베이스 생성
createdb -U <사용자 – mywork> -h <RDS 엔드포인트 주소> -E UTF8 <데이터베이스이름 – myworkdb>
앞 명령을 실행하면 비밀번호를 입력하라는 프롬프트가 표시되므로 앞에서 등록한 사용자의 비밀번호를 입력한다.
5) 데이터베이스 작업
데이터베이스에 접속
- 사용자: mywork
- RDS 엔드포인트 주소: 관리자 보안 암호값의 <host>
- 데이터베이스 이름: 관리자 보안 암호값의 <dbname>
psql -U <사용자> -h <RDS 엔드포인트 주소> <데이터베이스>
사용자(mywork)의 비밀번호 입력
샘플 데이터 생성 방법 1️⃣ : 직접 SQL문 입력
데이터베이스에 접속했으니, 직접 SQL문을 입력하여 샘플 데이터를 생성한다.
테이블 생성
CREATE TABLE region
(
region_id SERIAL PRIMARY KEY,
region_name VARCHAR(100) NOT NULL,
creation_timestamp TIMESTAMP NOT NULL
);
CREATE TABLE location
(
location_id BIGSERIAL PRIMARY KEY,
location_name VARCHAR(200) NOT NULL,
region_id BIGINT NOT NULL,
note TEXT,
FOREIGN KEY (region_id) REFERENCES region (region_id)
);
CREATE TABLE batch_processing
(
batch_name VARCHAR(20) PRIMARY KEY,
last_execution_date_time TIMESTAMP
);
CREATE TABLE batch_processing_file
(
batch_processing_file_id BIGSERIAL PRIMARY KEY,
batch_name VARCHAR(20) NOT NULL,
file_name VARCHAR(300) NOT NULL
);
데이터 삽입
-- REGION
INSERT INTO region (region_name, creation_timestamp)
VALUES ('서울', current_timestamp);
INSERT INTO region (region_name, creation_timestamp)
VALUES ('강릉', current_timestamp);
INSERT INTO region (region_name, creation_timestamp)
VALUES ('대전', current_timestamp);
INSERT INTO region (region_name, creation_timestamp)
VALUES ('광주', current_timestamp);
INSERT INTO region (region_name, creation_timestamp)
VALUES ('대구', current_timestamp);
INSERT INTO region (region_name, creation_timestamp)
VALUES ('부산', current_timestamp);
INSERT INTO region (region_name, creation_timestamp)
VALUES ('여수', current_timestamp);
INSERT INTO region (region_name, creation_timestamp)
VALUES ('안동', current_timestamp);
INSERT INTO region (region_name, creation_timestamp)
VALUES ('제주도', current_timestamp);
-- LOCATION
INSERT INTO location (location_name, region_id, note)
VALUES ('테디베어 뮤지엄', (SELECT region_id FROM region WHERE region_name = '제주도'), '테디베어의 역사는 물론 예술, 세계여행 등의 테마를 제공하는 테마 뮤지엄 브랜드
입니다.');
INSERT INTO location (location_name, region_id, note)
VALUES ('성산 일출봉', (SELECT region_id FROM region WHERE region_name = '제주도'), '유네스코 세계자연유산에 등재된 제주도의 랜드마크.');
-- BATCH_PROCESSING
INSERT INTO batch_processing (batch_name)
values ('SAMPLE_APP_BATCH');
테이블 확인
select * from <테이블이름>;
select * from region;
select * from location;
데이터베이스 접속 종료
다음 명령어를 입력하면, 데이터베이스 접속이 종료되고 다시 bash 창으로 돌아온다.
\q
샘플 데이터 생성 2️⃣ : 스크립트 파일 이용
위처럼 직접 SQL문을 실행할 수 있지만, 스크립트 파일을 만들어서 자동화할 수 있다.
sql 확장자로 스크립트 파일을 만들고 postgres에 접속 후 ` \i 파일경로`를 이용해서 스크립트를 실행할 수 있다.
\i 파일경로
스크립트 파일 생성
다음 명령어로 sample_data라는 이름의 sql 스크립트 파일을 생성하고, SQL문을 작성한다.
sudo vi sample_data.sql
CREATE TABLE region
(
region_id SERIAL PRIMARY KEY,
region_name VARCHAR(100) NOT NULL,
creation_timestamp TIMESTAMP NOT NULL
);
-- REGION
INSERT INTO region (region_name, creation_timestamp)
VALUES ('서울', current_timestamp);
INSERT INTO region (region_name, creation_timestamp)
VALUES ('강릉', current_timestamp);
INSERT INTO region (region_name, creation_timestamp)
VALUES ('대전', current_timestamp);
INSERT INTO region (region_name, creation_timestamp)
VALUES ('광주', current_timestamp);
INSERT INTO region (region_name, creation_timestamp)
VALUES ('대구', current_timestamp);
스크립트 실행
\i 파일경로
# 예시
\i sample_data.sql
3. 로컬 환경에서 테스트를 위한 데이터베이스 설정
1) 로컬에서 Postgresql 설치 및 연결
프로그램을 로컬에서 테스트하기 위해서 로컬 컴퓨터에 Docker에서 실행되는 postgresql을 설치한다.
docker run -d -p 외부포트번호:5432 -e POSTGRES_PASSWORD="비밀번호" --name 컨테이너이름 postgres
# 예시
docker run -d -p 5432:5432 -e POSTGRES_PASSWORD="ys1234" --name postgres postgres
이 경우, 관리자는 postgres로 생성된다.
컨테이너 확인
docker ps
PostgreSQL 데이터베이스 연결
DBeaver와 같은 프로그램을 사용할 수도 있지만, 인텔리제이의 데이터베이스 연결을 사용하겠다.
인텔리제이에서 우측의 Database 탭을 선택 후, [+] > Data Source > PostgreSQL을 클릭한다.
데이터베이스와 연결하는 방식은 DBeaver와 같은 데이터베이스 관리 프로그램과 거의 똑같다.
- User: postgres (앞에서 도커 컨테이너 생성 시 관리자는 postgres로 생성함)
- Password: 앞에서 설정했던 관리자 비밀번호(POSTGRES_PASSWORD)
드라이버가 없다고 뜨는 경우, 해당 메시지를 눌러 다운로드 받고, Test Connection을 클릭하여 연결이 제대로 되는지 확인한다.
다음 화면과 같이 Succeeded로 뜨는 경우, 성공한 것이다!
2) 샘플 사용자 및 데이터베이스 생성
PostgreSQL에 접속해서 샘플 유저와 데이터베이스를 생성한다.
앞에서 데이터베이스가 잘 연결되었다면, OK 버튼을 눌러서 창을 닫았을 때 console 창이 열렸을 것이다.
이 Postgres 콘솔 창에 명령어를 입력 후, 실행해주면 된다.
create user mywork password 'ys1234' superuser;
create database myworkdb owner mywork;
3) 새로 만든 유저로 재접속해서 샘플 데이터 생성
방금 만든 샘플 유저로 다시 접속해서 샘플 데이터를 생성한다.
create table region(
region_id SERIAL primary key,
region_name VARCHAR(100) not null,
creation_timestamp TIMESTAMP not null
);
insert into region(region_name, creation_timestamp)
values('서울', current_timestamp);
insert into region(region_name, creation_timestamp)
values('제주', current_timestamp);
insert into region(region_name, creation_timestamp)
values('목포', current_timestamp);
insert into region(region_name, creation_timestamp)
values('광주', current_timestamp);
insert into region(region_name, creation_timestamp)
values('부산', current_timestamp);
insert into region(region_name, creation_timestamp)
values('대구', current_timestamp);
select *
from region;
이어서 다음 글에서는 도커 이미지를 빌드해서 ECR에 업로드하는 과정을 살펴보겠습니다.
참고