3-Tier 아키텍처와 S3 스토리지 구현 가이드

김남우 ·2025년 3월 22일
0

AWS

목록 보기
11/13
post-thumbnail

3-Tier 아키텍처와 S3 스토리지 구현 가이드

1. 시스템 아키텍처 진화

단일 컨테이너에서 3-Tier 아키텍처로

Insupanda 프로젝트는 다음과 같은 단계로 진화했습니다:

1.1 초기 구현 (단일 컨테이너)

  • 단일 백엔드 컨테이너 내에서 모든 처리
  • 컨테이너 내부 스토리지 사용 (임시 데이터)
  • 확장성과 고가용성 부족

1.2 2-Tier 아키텍처 도입

  • 백엔드 서비스와 데이터 스토리지 분리
  • EmptyDir → EBS 볼륨 (PVC)으로 전환
  • 데이터 지속성 확보

1.3 3-Tier 아키텍처 완성

  • 프론트엔드, 백엔드, 데이터 스토리지 완전 분리
  • EBS → S3로 데이터 스토리지 변경
  • 확장성과 가용성 크게 향상

2. 스토리지 선택의 진화

2.1 EmptyDir의 한계

처음에는 간단한 구성으로 쿠버네티스의 EmptyDir 볼륨을 사용했습니다:

volumes:
- name: data-volume
  emptyDir: {}

문제점:

  • 포드 재시작 시 데이터 손실
  • 벡터 DB와 같은 영구 데이터 저장에 부적합
  • 멀티 포드 환경에서 데이터 공유 불가

2.2 EBS 볼륨 도입

2-Tier 구조로 전환하면서 영구 스토리지가 필요해졌고, EBS를 선택했습니다:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: vector-db-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: gp2
  resources:
    requests:
      storage: 10Gi

장점:

  • 영구 데이터 저장 가능
  • 포드 재시작해도 데이터 유지
  • 백업 및 복원 지원

한계:

  • 가용성 영역(AZ) 제약: EBS 볼륨은 단일 AZ에 제한됨
  • 배포 중 다음과 같은 오류 발생:
    "EBS 볼륨이 EC2 인스턴스에 연결되지 않음"
  • 다중 AZ 환경에서 노드와 볼륨의 AZ 불일치 문제
  • 동시 읽기/쓰기 지원 제한 (ReadWriteOnce)

2.3 S3로의 자연스러운 전환

3-Tier 아키텍처 완성과 함께 S3로 전환한 이유:

  1. 가용성 영역 제약 극복

    • S3는 리전 수준 서비스로 AZ 제약 없음
    • 어떤 노드에서도 접근 가능
  2. 확장성 향상

    • 사실상 무제한 스토리지 용량
    • 대규모 벡터 데이터베이스 저장에 적합
  3. 비용 효율성

    • 사용한 만큼만 비용 지불
    • 운영 부담 감소
  4. 분산 시스템 지원

    • 여러 서비스에서 동시 접근 가능
    • 중앙 집중식 데이터 관리

3. S3 스토리지 구현 방법

3.1 백엔드 코드 수정

class RAGService:
    def __init__(self):
        # S3 연결 설정
        self.use_s3 = os.getenv("USE_S3", "false").lower() == "true"
        self.s3_bucket = os.getenv("S3_BUCKET_NAME")
        self.s3_prefix = os.getenv("S3_PREFIX", "vector_db")
        
        if self.use_s3:
            import boto3
            self.s3_client = boto3.client('s3')
            
    def load_collection(self, collection_name):
        if self.use_s3:
            # S3에서 데이터 로드
            s3_path = f"{self.s3_prefix}/{collection_name}"
            # S3 처리 로직...
        else:
            # 로컬 파일시스템 로직...

3.2 인프라 설정 변경

ConfigMap 설정

apiVersion: v1
kind: ConfigMap
metadata:
  name: insupanda-config
data:
  USE_S3: "true"
  S3_PREFIX: "vector_db"
  AWS_REGION: "ap-northeast-2"

Secret 설정

apiVersion: v1
kind: Secret
metadata:
  name: insupanda-secrets
type: Opaque
data:
  AWS_ACCESS_KEY_ID: "<base64_encoded>"
  AWS_SECRET_ACCESS_KEY: "<base64_encoded>"
  S3_BUCKET_NAME: "<base64_encoded>"

배포 YAML에서 볼륨 마운트 제거

# 이전: 볼륨 마운트 포함
spec:
  containers:
  - name: backend
    volumeMounts:
    - name: vector-db
      mountPath: /app/vector_db
  volumes:
  - name: vector-db
    persistentVolumeClaim:
      claimName: vector-db-pvc

# 이후: 볼륨 마운트 제거, S3 사용
spec:
  containers:
  - name: backend
    # 볼륨 마운트 없음, S3에서 직접 로드

3.3 데이터 초기화 작업 변경

apiVersion: batch/v1
kind: Job
metadata:
  name: vector-db-init
spec:
  template:
    spec:
      containers:
      - name: init
        command: ["/bin/sh", "-c"]
        args:
        - |
          # S3 버킷 확인 및 초기화
          if ! aws s3 ls s3://${S3_BUCKET_NAME}/${S3_PREFIX}/; then
            # 초기 데이터 S3에 업로드
            aws s3 sync /app/initial_data/ s3://${S3_BUCKET_NAME}/${S3_PREFIX}/
          fi

4. 3-Tier 아키텍처의 완성

최종적으로 Insupanda 프로젝트는 다음과 같은 3-Tier 아키텍처로 완성되었습니다:

  1. 프론트엔드 계층

    • Flutter 웹 애플리케이션
    • Nginx 서버로 정적 콘텐츠 제공
    • 사용자 인터페이스 담당
  2. 백엔드 계층

    • FastAPI 서버 (Python)
    • 벡터 DB 검색 및 비즈니스 로직 처리
    • 프록시 서버를 통한 API 요청 처리
  3. 데이터 계층

    • AWS S3로 벡터 데이터베이스 저장
    • 확장성 및 가용성 보장
    • 멀티 AZ 지원

5. 장점 및 교훈

장점

  • 고가용성: 가용성 영역 제약 없이 서비스 운영 가능
  • 확장성: 데이터 양에 상관없이 시스템 확장 가능
  • 유지보수: 인프라 관리 부담 감소
  • 비용 효율: 실제 사용량에 따른 비용 지불

교훈

  • 초기 아키텍처 설계 시 확장성 고려 필요
  • 스토리지 선택은 프로젝트 요구사항에 맞게 진화해야 함
  • 클라우드 네이티브 서비스(S3)를 활용하면 인프라 복잡성 감소
  • 쿠버네티스에서는 영구 스토리지 전략이 중요한 설계 요소

이 문서는 3-Tier 프로젝트의 스토리지 전략 진화와 3-Tier 아키텍처 구현에 관한 가이드입니다. 프로젝트 초기 단계에서는 단순한 구성으로 시작했지만, 운영 경험을 통해 점진적으로 개선되었습니다. EBS의 한계를 경험한 후 S3로 전환함으로써 보다 견고하고 확장 가능한 시스템을 구축할 수 있었습니다.

profile
✨A.I로 0에서 1을 만드는 법✨ - woo;D

0개의 댓글