AWS- EKS 이어서
RDS를 생성 → 베스천 호스트를 생성, 베스천 호스트는 RDS에 접근하기 위한 유일한 포인트이다.
이때 베스천 호스트는 EC2 인스턴스가 될 것
RDS와 EC2 인스턴스는 동일한 VPC를 가지고 있다.
RDS는 public 접근 가능 → 샘플 데이터 삽입, 외부 접속 도구 이용, 환경 설정 x
EC2 인스턴스는 외부접속도구 설치해서 application을 생성, sample data 삽입
✅ 구성 요소와 역할
구성 요소 설명
| RDS (Relational Database Service) | - 데이터베이스를 호스팅하는 서비스- 샘플 데이터를 삽입하고 외부 도구(MySQL Workbench 등)로 접근 가능하게 퍼블릭 접근 허용 |
| Bastion Host (EC2 인스턴스) | - 외부에서 RDS에 접근할 수 있는 유일한 경로- 사용자 또는 애플리케이션이 이 EC2에 접속한 뒤 RDS에 연결- 외부 접속 도구 설치 가능 (예: DBeaver, MySQL CLI 등) |
| VPC (Virtual Private Cloud) | - RDS와 EC2가 같은 네트워크(VPC) 내에 있음- 같은 서브넷 또는 연결 가능한 서브넷에 위치해야 통신 가능 |
🔁 흐름 요약
- RDS 생성
- 퍼블릭 접근 허용 (예: Yes)
- 샘플 데이터 삽입 가능
- 외부 DB 클라이언트(MySQL Workbench 등)로 직접 접속 가능
- EC2 인스턴스 생성 (Bastion Host)
- 동일 VPC에 생성
- 퍼블릭 IP 부여하여 외부에서 SSH 접속 가능
- DB 접속용 툴 설치 가능
- 접속 경로
- 사용자 → SSH로 EC2 접속 (Bastion)
- EC2 내에서 RDS 접속 (DB 클라이언트 또는 커맨드라인 이용)
⚙️ 왜 이렇게 구성하나요?
이유 설명
| 보안 강화 | RDS를 퍼블릭하게 둘 수도 있지만, 장기적으로는 EC2(Bastion)를 통해서만 접근하게 하여 더 안전함 |
| 접속 제어 | Bastion Host를 통해 누가 언제 DB에 접근했는지 추적 가능 |
| 실습 목적 | 퍼블릭 설정을 통해 데이터 삽입과 외부 접속이 가능하므로, 테스트와 개발에 편리 |
📝 한 줄 요약
RDS는 퍼블릭 접근 가능하지만, 실제 DB 연결은 Bastion Host 역할을 하는 EC2 인스턴스를 통해서만 진행하는 구조로 보안과 통제를 강화한 구성입니다.
어제 수업 이어서,,,
- 베스천 호스트 접속
- 세션 서비스 관리자(Systems Manager)로 접속
- 세션 관리자에서 세션 시작을 클릭 (자동으로 생성된 EC2 인스턴스에는 접근할 수 있지만 직접 생성한 EC2 인스턴스에는 세션 관리자에서 접속이 안된다.)
- 동일한 VPC 안에 있는 어떤 EC2 인스턴스도 베스천 호스트가 될 수 있음
- 아무 인스턴스나 선택해서 세션 시작을 클릭
- 세션에서 명령어를 수행
sudo yum install -y git sudo amazon-linux-extras install -y postgresql11 # 이 명령은 amazon linux로 만들어진 인스턴스에서만 수행이 가능하다.- 데이터베이스 엔드포인트 확인
- CloudFormation에서 생성한 스택을 선택해서 출력 탭을 확인하면 RDSEndpoint를 확인할 수 있다. (RDS 서비스에서 확인 가능)
- eks-work-db.c5iksoio0fsi.ap-northeast-2.rds.amazonaws.com
- 데이터베이스 유저 와 비밀번호 확인(AWS Secrets Manager가 비밀번호를 생성)
- 개요에서 확인: eksdbadmin(yaml 파일에서 생성), 8hO3hPa_OVPh5=QK(자동 생성) mywork, )V1+~wRSm4fLIK)o
- 유저 비밀번호 변경
- createuser -d -U 관리자계정 -P -h RDS엔드포인트 사용자계정
- createuser -d -U eksdbadmin -P -h eks-work-db.c5iksoio0fsi.ap-northeast-2.rds.amazonaws.com mywork
- 비밀번호를 입력하는 란이 3번 출력 되는데 앞의 2번은 사용자의 비밀번호이고 마지막 1번은 관리자의 비밀번호이다.
- createuser -d -U 관리자계정 -P -h RDS엔드포인트 사용자계정
- 데이터베이스 생성
- createdb -U 사용자 -h RDS 엔드포인트 -E UTF8 데이터베이스이름
- createdb -U mywork -h eks-work-db.c5iksoio0fsi.ap-northeast-2.rds.amazonaws.com -E UTF8 myworkdb
- createdb -U 사용자 -h RDS 엔드포인트 -E UTF8 데이터베이스이름
Backend Application이 사용할 RDS를 CloudFormation으로 생성
CloudFormation
CloudFormation(yaml 파일이나 GUI Builder를 이용해서 AWS Resource를 생성하는 서비스) 이 사용할 yaml파일 생성
CloudFormation에 접속해서 작업
- yaml 파일을 이용해서 스택을 생성
- 2개의 파라미터만 직접 설정
- EksWorkVPC인데 이 부분은 이미 만들어진 VPC 중 EKS와 관련된 VPC를 선택
- Eks Cluster와 동일한 VPC에 만들면 통신 비용을 지불하지 않는다.
- OpeServeRouteTable을 설정해야 하는데 이 부분은 이전에 만든 eks-work-base 스택의 출력 부분에서 RouteTable 값을 찾아서 선택
- EksWorkVPC인데 이 부분은 이미 만들어진 VPC 중 EKS와 관련된 VPC를 선택
- 생성에 성공하면 EC2 인스턴스가 하나 만들어지고 RDS에 데이터베이스가 생성된다.
- 데이터베이스에 접속
- 이 데이터베이스는 외부에 노출이 되지 않으므로 VPC 외부의 컴퓨터에서는 접속이 불가능하다.
- 베스천 호스트에 접속을 하기 위해서 EC2 인스턴스에 연결하는 방법과 Session Manager를 이용해야 한다.
- 베스천 호스트에 postgresql 클라이언트를 설치(amazon linux라서 설치 방법이 조금 다른다.)
- sudo amazon-linux-extras install -y postgresql11
- End Point 확인: RDS에서 확인 가능하고 CloudFormation의 Stack의 출력 탭에서 확인 가능
- 관리자 비밀번호 확인
- 관리자 아이디는 yaml 파일에서 설정했지만 비밀번호는 AWS Secrets Manager가 만들도록 설정했으므로 Secrets Manager에서 확인해야 한다.
- 관리자 계정은 eksdbadmin
- 관리자 비밀번호는 마스터시크릿값 → 보안 암호값 → 확인
- 계정 생성
- create user -d -U eksdbadmin -P -h <RDS End Point> <계정>
- 데이터베이스 생성
- create -U 계정 -h <RDS End Point> -E UTF8 계정
- 데이터베이스 접속
- psql -U 계정 -h <RDS End Point> 데이터베이스이름
- Spring의 JPA는 Entity에 매핑되는 테이블이 없으면 자동으로 생성해주지만 실무에서는 대부분 테이블을 만들고 연결시키는 방식을 선택한다.
- 데이터베이스 테이블을 원하는 옵션으로 만들기 어렵기 때문
- 테이블 생성
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
);
BackEnd Application을 EKS Cluster 에 배포
1)작업 과정
=>네임스페이스 생성
=>kubeconfig에 네임스페이스 반영
=>데이터베이스 접속용 시크릿 등록
=>API Application을 배포
=>API Application을 외부 공개
2)네임스페이스 생성
=>네임스페이스
- 쿠버네티스는 기본적으로 클러스터 단위로 물리적 구분
- 하나의 클러스터를 네임스페이라는 논리적 구획으로 구분해서 관리하는 것이 가능
=>네임스페이스 생성을 위한 yaml 파일 작성(create_namespace_k8s.yaml)
apiVersion: v1
kind: Namespace
metadata:
name: eks-work
# 리소스 생성
kubectl apply -f create_namespace_k8s.yaml
3)네임스페이스를 반영
=>사용 중인 컨텍스트 정보 확인
kubectl config get-contexts
현재 클러스터 이름: 클러스터 이름: eks-work-cluster.ap-northeast-2.eksctl.io
현재 AUTHINFO 값: adam@eks-work-cluster.ap-northeast-2.eksctl.io
=>현재 컨텍스트에 네임스페이스 반영
kubectl config set-context 컨텍스트이름 --cluster 클러스터이름 --user AUTHINFO값 --namespace 네임스페이스 이름
컨텍스트 생성: kubectl config set-context eks-work --cluster eks-work-cluster.ap-northeast-2.eksctl.io --user adam@eks-work-cluster.ap-northeast-2.eksctl.io --namespace eks-work
=>컨텍스트 변경
kubectl config use-context 컨텍스트이름
kubectl config use-context eks-work
4)데이터베이스 접속 정보를 위한 시크릿 생성
=>데이터베이스 접속 정보는 소스 코드에 포함되어 있는 경우 소스 코드를 형상 관리 사이트에 업로드하는 것은 바람직하지 않습니다.
=>접속 정보는 배포가 될 때 시크릿을 이용해서 배포하는 것을 권장합니다.
=>소스 코드를 수정해서 ECR에 이미지를 푸시
- application.properties 파일을 수정
spring.datasource.url=${DB_URL}
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}
- 아카이브 파일(자바로 실행할 수 있는 압축 파일: jar, war) 생성
리눅스에서 수행하는 명령: sudo chmod 755 ./gradlew
./gradlew clean build
- 빌드 과정
의존성 라이브러리 다운로드
프로그램 컴파일(기본 디렉토리의 파일과 테스트 디렉토리의 파일 모두 컴파일)
테스트 실행(실제 데이터베이스 접속 정보가 없으면 에러가 발생할 수 있는데 이를 해결하는 방법은 테스트 코드를 삭제하거나 테스트를 별도의 데이터베이스 설정을 추가합니다.)
실행 가능한 아카이브 파일 생성(spring boot 프로젝트는 build/libs 디렉토리에 프로젝트이름-0.0.1-SNAPSHOT.jar 파일로 만들어 짐)
- 도커 이미지 빌드
sudo docker build -t k8s/backend-app:1.0.0 --build-arg JAR_FILE=build/libs/eks_backend-0.0.1-SNAPSHOT.jar .
- AWS CLI를 이용해서 ECR에 이미지 배포
레포지토리 생성(k8s/backend-app)
ECR에 로그인: aws ecr get-login-password --region 리전 | docker login --username AWS --password-stdin AWS계정.dkr.ecr.리전.amazonaws.com
aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin 208060188195.dkr.ecr.ap-northeast-2.amazonaws.com
이미지 태그 수정: AWS계정.dkr.ecr.리전/레포리지토리이름:태그
docker tag k8s/backend-app:1.0.0 208060188195.dkr.ecr.ap-northeast-2.amazonaws.com/k8s/backend-app:1.0.0
도커 푸시: docker push 208060188195.dkr.ecr.ap-northeast-2.amazonaws.com/k8s/backend-app:1.0.0
- 시크릿을 저장하기 위한 template 파일을 생성: db_config_k8s.yaml.template
apiVersion: v1
kind: Secret
type: Opaque
metadata:
name: db-config
stringData:
db-url: ${DB_URL}
db-username: mywork
db-password: ${DB_PASSWORD}
- 시크릿에 값을 채워 넣기
DB_URL=jdbc:postgresql://데이터베이스경로/myworkdb DB_PASSWORD=비밀번호 envsubst < db_config_k8s.yaml.template | kubectl apply -f -
DB_URL=jdbc:postgresql://eks-work-db.c5iksoio0fsi.ap-northeast-2.rds.amazonaws.com/myworkdb DB_PASSWORD='wnddkd' envsubst < db_config_k8s.yaml.template | kubectl apply -f -
=>애플리케이션을 배포
- 배포를 위한 템플릿 파일 생성: deployment_backend_app_k8s.yaml.template
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend-app
labels:
app: backend-app
spec:
replicas: 2
selector:
matchLabels:
app: backend-app
template:
metadata:
labels:
app: backend-app
spec:
containers:
- name: backend-app
image: ${ECR_HOST}/k8s/backend-app:1.0.0
imagePullPolicy: Always
ports:
- containerPort: 8080
env:
- name: DB_URL
valueFrom:
secretKeyRef:
key: db-url
name: db-config
- name: DB_USERNAME
valueFrom:
secretKeyRef:
key: db-username
name: db-config
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
key: db-password
name: db-config
readinessProbe:
httpGet:
port: 8080
path: /health
initialDelaySeconds: 15
periodSeconds: 30
livenessProbe:
httpGet:
port: 8080
path: /health
initialDelaySeconds: 30
periodSeconds: 30
- 리소스 생성
ECR_HOST = 계정.dkr.ecr.ap-northeast-2.amazonaws.com envset < deployment_backend_app_k8s.yaml.template | kubectl apply -f -
5)Windows에서 실행해보기 위한 수정(Secret 사용 안함)
=>application.properties의 환경 변수를 제거하고 실제 값을 설정
=>프로젝트 빌드
./gradlew clean build
=>이미지 생성
docker build -t 208060188195.dkr.ecr.ap-northeast-2.amazonaws.com/k8s/backend-app:1.0.0 --build-arg JAR_FILE=build/libs/eks_backend-0.0.1-SNAPSHOT.jar .
=>이미지 푸시
docker push 208060188195.dkr.ecr.ap-northeast-2.amazonaws.com/k8s/backend-app:1.0.0
=>배포를 위한 yaml 파일 생성
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend-app
labels:
app: backend-app
spec:
replicas: 2
selector:
matchLabels:
app: backend-app
template:
metadata:
labels:
app: backend-app
spec:
containers:
- name: backend-container
image: 208060188195.dkr.ecr.ap-northeast-2.amazonaws.com/k8s/backend-app:1.0.0
imagePullPolicy: Always
ports:
- containerPort: 80
=>리소스 생성
=>상태 확인
kubectl get all
6)서비스를 외부에 공개
=>API Application을 배포를 했지만 클러스터 외부에서는 API 호출이 불가능
=>Load Balancer 나 Node Port를 이용하면 외부에서 접속이 가능
=>LoadBalancer를 만들어서 파드를 외부에서 접속할 수 있도록 공개
apiVersion: v1
kind: Service
metadata:
name: backend-app-service
spec:
type: LoadBalancer
selector:
app: backend-app
ports:
- protocol: TCP
port: 80
targetPort: 80
=>리소스 생성
=>LoadBalancer 생성을 확인하고 DNS를 이용해서 웹 브라우저에서 접근
3.애플리케이션 환경 삭제
=>삭제 순서
- 쿠버네티스 상의 애플리케이션 과 서비스를 삭제
- EKS 클러스터 삭제
- 데이터베이스 와 베스천 호스트 삭제
- 기본 리소스 삭제
=>쿠버네티스 상의 애플리케이션 과 서비스를 삭제
- 서비스 삭제: kubectl delete service backend-app-service
- 디플로이먼트 삭제: kubectl delete deployment backend-app
- 확인: kubectl get all
=>EKS 클러스터 삭제
eksctl delete cluster --name 클러스터이름
워커 노드 와 컨트롤 플레인의 삭제가 실행됩니다.
eksctl 명령으로 클러스터를 삭제하면 워커 노드의 삭제가 끝나고 컨트롤 플레인 삭제 처리를 시작한 시점에 프롬프트가 입력 가능한 상태로 돌아옵니다.
프롬프트가 다시 표시된 후에서 CloudFormation에서는 DELETE_IN_PROGRESS 일 수 있습니다.
=>데이터베이스 와 베스천 호스트 삭제
- 데이터베이스는 CloudFormation에서 생성할 때 사용한 스택을 삭제
=>기본 리소스를 삭제: VPC 생성을 삭제
4.서비스 환경에 대한 고려
1)모니터링
=>모니터링 하기 위한 별도의 툴이 필요없는데 AWS에서 기본적으로 제공
=>클러스터 상태 파악
- EKS 서비스에서 구성 부분을 확인
- 데이터 플레인을 EC2로 구축하는 경우는 노드를 스스로 관리해야 합니다.
EKS에만 적용되는 것이 아니고 AWS 서비스로 일반적인 관리 및 운영을 실행하면 됩니다.
- Auto Scaling 기능을 이용해서 데이터 플레인을 구축하기 때문에 최소 숫자의 서버가 동작하도록 되어 있습니다.
AutoScaling 그룹 설정에서 최소 서버 대수를 설정하면 그 대수 아래로 떨어지지 않도록 AWS에서 자동으로 관리
- 데이터 플레인 전체의 부하 상태는 Amazon CloudWatch에서 확인할 수 있습니다.
AutoScaling 그룹 단위의 CPU 사용률 등을 확인할 수 있습니다.
=>애플리케이션 상태 파악
- CloudWatch에는 Container Insights 라는 기능이 존재
- 클러스터 노드, 파드, 네임스페이스, 서비스 레벨의 메트릭을 참조할 수 있습니다.
- CloudWatch Agent 라는 데몬셋으로 동작시킨 후 필요한 메트릭을 CloudWatch로 전송
- 데이터 노드의 IAM 역할에 정책 추가
EC2 관리 콘솔에서 데이터 노드에 해당하는 인스턴스를 선택한 후 상세 정보 페이지에 있는 내용 중 중간에 있는 IAM 역할 아래의 링크를 클릭한 후 정책 연결 버튼을 클릭해서 CloudWatchAgentServerPolicy를 선택해주면 됩니다.
- CloudWatch용 네임스페이스 생성
kubectl apply -f cloudwatch-namespace.yaml
- 파드가 사용할 서비스 계정 생성
kubectl apply -f cwagent-serviceaccount.yaml
- 에이전트가 사용할 configmap 생성
kubectl apply -f cwagent-configmap.yaml
- 데몬셋으로 실행
kubectl apply -f cwagent-daemonset.yaml
RegionLocation
→ 오라클: REGIONLOCATION
→ Postgresql: regionlocation
→ mysql: region_location
mysql은 기본적으로 테이블명에 대문자를 쓰지 않는다.