서비스 인프라 확장성과 모니터링 설계 [V3] - 100-hours-a-week/6-nemo-wiki GitHub Wiki

Version 3: Kubernetes 도입

1. 아키텍쳐 개요

본 설계에서는 기존 Docker 기반 단일 서버 환경에서 Docker 컨테이너를 직접 운영하던 구조를 , Kubeadm을 통한 Kubernetes 클러스터 기반 고가용성, 확장성, 자동화를 갖춘 인프라를 설계 및 전환하는 것이다. 이를 위해 기존 시스템 분석, 전환 필요성 도출, kubeadm 기반 아키텍쳐 설계, 배포 운영 전략, 장애 대응 시나리오 등을 설명하는 것을 목표로 한다.

2. Kubeadm 기반 클러스터 설계 및 오케스트레이션

2-1. 주요 서비스 구성 요소

현재 서비스는 단일 서버를 넘어 다양한 마이크로서비스(Next.js, Spring Boot, DB, Redis 등)를 구성하고 있으며, 고가용성, 확장성, 그리고 무중단 배포를 요구한다.

이에 따라 다음과 같은 이유로 Kubernetes 클러스터 구성이 필요하다:

  • 수십 개 이상의 컨테이너 서비스를 안정적으로 운영하기 위함
  • 오토스케일링 및 부하 분산 지원
  • 무중단 Rolling Update 적용
  • Self-healing(자동 복구) 기능 확보
  • 무중단 배포 및 자동 롤백 기능 강화
  • GitOps 및 Helm Chart를 통한 자동화된 배포 체계 구축 가능
  • AWS EKS/GKE 대비 비용 절감

2-2 세부 워크로드 배포 전략

노드 종류 주요 역할 구성 서비스
Master Node (AWS) 클러스터 제어판(Control Plane) 관리 etcd, API Server, Controller Manager, Scheduler
Worker Node 1 (AWS) 애플리케이션 워크로드 처리 Next.js Frontend Pod, Spring Boot Backend Pod
Worker Node 2 (AWS) 인프라/DB 처리 전담 NGINX Ingress Controller, ArgoCD, MySQL DB, Redis
GCP 클러스터 AI 서비스 처리 FastAPI, ChromaDB

GCP 클러스터는 비용을 고려하여 그대로 도커 컨테이너화한채로 유지

ㅁㅇㅁㄴㅇㅁㄴㅇㅁㄴㅇㅁ drawio

2-3. Master Node

  • Master Node는 Kubernetes 클러스터의 Control Plane으로서 클러스터 전반의 상태 관리, 스케줄링, 클러스터 이벤트 조정을 책임진다.

  • 사용자의 요청(kubectl 명령어, API 호출 등)을 처리하고, 클러스터 리소스(Pod, Service 등)를 생성, 관리, 감시하는 기능을 수행한다.

  • Master Node가 일시적으로 장애가 발생하더라도, 기존에 실행 중인 워커 노드와 파드들은 동작을 유지할 수 있지만, 새로운 배포나 스케줄링, 클러스터 설정 변경은 불가능해진다.

    ▪️ Master Node를 주요 컴포넌트

    구성 요소 설명
    etcd 클러스터의 모든 상태 정보를 저장하는 고가용성 분산 키-값 저장소. 클러스터의 단일 소스 오브 트루스(Source of Truth) 역할.
    kube-apiserver (api) Kubernetes API 요청을 받아 처리하는 핵심 컴포넌트. 인증, 인가, 데이터 유효성 검사, 클러스터 상태 제공.
    kube-scheduler (sched) 생성된 Pod들을 어떤 워커 노드에 배치할지 결정하는 컴포넌트. 자원 사용량, 정책 등을 고려해 최적의 노드를 선정.
    kube-controller-manager (c-m) 여러 종류의 컨트롤러(예: ReplicaSet Controller, Node Controller)를 관리하여 클러스터 상태를 실제 원하는 상태로 유지시킨다.
    cloud-controller-manager (c-c-m) 클라우드 벤더(AWS, GCP 등)와 관련된 컨트롤러를 관리하는 별도 컴포넌트. (예: 로드밸런서 생성, VM 상태 감시 등)

그림에서 보인 것처럼 etcd, sched, c-m, c-c-m은 Master Node 내부에 있으며, API 서버를 통해 상호작용한다.

2-4. Worker Node 1 (어플리케이션 워크로드)

→ Worker Node 1에서는 Namespace로 구분하여 Next.js와 Spring Boot를 각각 운영한다.

  1. Next.js 서비스
  • Deployment: 실제 실행되는 Pod를 정의하고 관리한다.
  • Service: 내부 Kubernetes 네트워크 상에서 Pod에 안정적으로 접근할 수 있도록 연결해주는 가상 IP를 제공한다.
  • Ingress: 외부 트래픽(HTTP/HTTPS 요청)을 Kubernetes 클러스터 내부의 특정 Service로 라우팅하는 역할을 한다.
  • Next.js는 Ingress 리소스, Service, Deployment를 모두 구성하여, HTTPS 기반 외부 트래픽을 받아 클러스터 내부로 연결하는 구조이다.
  • Ingress 리소스는 외부 요청을 수신하고, 적절한 Service로 트래픽을 분배한다.

2. Spring Boot 서비스

  • Deployment: Spring Boot 어플리케이션 Pod을 정의하고 관리한다.
  • Service: 내부 통신용으로만 설정
  • Spring Boot는 Ingress 리소스를 사용하지 않고, Service를 통해서만 Pod에 접근하도록 설계되었음 → 이는 Spring Boot 서비스가 외부에 직접 노출되지 않고, 클러스터 내부의 다른 서비스와만 통신하기 위해 내부 전용 서비스로 설정되었음을 의미한다.

2-5. Worker Node 2 (인프라 및 DB)

: Worker Node 2에는 Namespace로 구분하여 NGINX Ingress Controller, ArgoCD, Kafka 로 각각 운영된다.

  1. NGINX Ingress Controller
  • 외부 트래픽을 수신하여 Kubernetes Ingress 리소스를 기반으로 적절한 내부 서비스로 라우팅한다.
  • Ingress Controller는 Kubernetes 클러스터에서 생성된 Ingress 리소스를 감시(watch)하고, 해당 리소스에 맞게 트래픽 라우팅 규칙을 동적으로 설정하는 컴포넌트다.
  • 이 프로젝트에서는 NGINX Ingress Controller를 사용하여 외부에서 들어오는 HTTP/HTTPS 요청을 Kubernetes 클러스터 내부 Service로 적절히 전달.
  • NGINX는 단순한 웹 서버가 아니라, Ingress 리소스를 해석해서 동적으로 리버스 프록시 역할을 수행함.
  1. ArgoCD
  • GitOps 기반 배포 자동화 도구로, Helm Chart 업데이트를 자동으로 감지하여 배포를 수행한다.
  1. Kafka 클러스터

    Kafka Broker, Kafka Producer(Spring Boot 내부에서 작동), Kafka Consumer, Zookeeper로 구성된다

  2. DB namespace

    MySQL과 Redis 에 대하여 동일하게 pod로 관리 구성

2-6. MySQL (Database 구성)

: MySQL은 상태 저장형(Stateful) 애플리케이션으로, Pod가 재시작되거나 다른 노드로 이동하더라도 데이터의 영속성을 유지해야 한다.

  • 이를 위해 Kubernetes에서는 PVC(Persistent Volume Claim)와 PV(Persistent Volume)를 사용해 안정적인 스토리지 연결을 보장해야함.
  • 실제 데이터 저장소는 AWS의 EBS(Elastic Block Store)를 활용한다.

▪️ 구성 흐름

  1. PVC (Persistent Volume Claim):
    • MySQL Pod가 요구하는 스토리지 요청을 선언한다. (예: 스토리지 크기, 접근 모드 등)
  2. PV (Persistent Volume):
    • PVC 요청을 수락하고, AWS EBS 기반으로 실제 스토리지 볼륨을 프로비저닝한다.
  3. EBS (Elastic Block Store):
    • AWS 클라우드에서 제공하는 고가용성 Block Storage.
    • 고정된 물리 서버에 의존하지 않고, AZ 내에서 데이터 내구성과 복원성을 보장한다.

▪️ 구성 이유

항목 설명
데이터 영속성 확보 Pod가 재시작되거나 다른 노드로 이동해도 데이터가 유지된다.
고가용성 EBS는 AZ 내 높은 내구성과 가용성을 보장한다.
백업/복원 용이 스냅샷 기능을 통해 주기적 백업 및 복원이 가능하다.
운영 편의성 PVC/PV를 통해 Kubernetes 자원 관점에서 일괄적으로 스토리지를 관리할 수 있다.

따라서 MySQL과 같은 Database 워크로드는 Stateless 애플리케이션과 달리 반드시 PVC-PV-EBS 기반 구조를 통해 안정적인 데이터 저장과 운영이 필요하다.

3. 오케스트레이션 및 배포 전략

3-1. 오케스트레이션 구성

항목 방식
배포 관리 Helm Chart를 이용하여 모든 서비스 배포
CD 파이프라인 GitHub Actions → ArgoCD 자동 연동
오토스케일링 Metrics Server + HPA(Horizontal Pod Autoscaler) 사용
업데이트 전략 Deployment 오브젝트 기반 Rolling Update
장애 복구 Deployment 자동 재시작 정책(RestartPolicy: Always) 설정
  • Helm Chart 구조
helm/
  next/
    Chart.yaml
    values.yaml
    templates/
      deployment.yaml
      service.yaml
      ingress.yaml
  spring/
    Chart.yaml
    values.yaml
    templates/
      deployment.yaml
      service.yaml
      ingress.yaml
  nginx-ingress/
    Chart.yaml
    values.yaml
    templates/
      deployment.yaml
      service.yaml
      ingress.yaml
  argocd/
    Chart.yaml
    values.yaml
    templates/
      deployment.yaml
      service.yaml
      ingress.yaml

→ GitHub Actions를 통해 Chart 업데이트 시 ArgoCD가 자동 배포 트리거

  • 서비스 세부 구성
서비스 파드 복제본 수 포트 볼륨 구성
Next.js Frontend 3 개 3000 없음
Spring Boot Backend 3 개 8080 없음
MySQL DB 3개 (Leader + Replica 2개) 3306 PV + PVC 구성 (EBS)
Redis 3개(Master + Slave 2개 ) 6379 PV + PVC 구성 (EBS)
FastAPI AI 서버 (GCP) 2 개 8000 없음
ChromaDB (GCP) 2 개 8001 PV + PVC 구성 (GCP Persistent Disk)
Kafka/Zookeeper 3개 이상 동적 포트

→ AI서버는 GCP에서 그대로 운영하여 Kubenetes를 도입하지 않고 그대로 도커 컨테이너화여 유지

3-2. CI/CD 및 운영 자동화 상세 흐름

모든 서비스는 각기

독립된 GitHub Repository

에서 관리되며, GitHub Actions 기반의 CI 파이프라인을 통해 운영된다.

  1. CI 단계:
    • 개발자가 main 또는 develop 브랜치에 코드를 Push하면 GitHub Actions가 트리거됨
    • 애플리케이션을 빌드하고, Docker Image를 생성하여 GCP의 GCR 또는 AWS의 ECR에 Push한다.
  2. CD 단계:
    • Kubernetes 클러스터에 설치된 ArgoCD가 Helm Chart 저장소를 지속적으로 감시
    • 개발자가 Helm Chart의 values.yaml 또는 이미지 태그를 수정하여 Git에 Push하면
    • ArgoCD가 변경을 감지하고, Helm 기반으로 클러스터에 배포
  3. 운영 이점:
    • 서비스별 레포가 분리되어 있음에도 불구하고, Helm Chart를 통해 공통적인 배포 전략을 적용
    • Rollback이나 재배포 같은 경우에도 Helm + ArgoCD 조합으로 유연하게 대응 가능
    • GitOps 기반으로 구성되어 배포 히스토리 및 감사 추적이 용이
  4. 장애 격리 및 확장성:
    • 각 서비스는 서로 독립적인 Deployment 및 Service 리소스로 구성되어 있어 → 특정 서비스 장애 시 다른 서비스에 영향 없음
    • Pod 단위로 수평 확장이 가능하며, HPA(Metrics 기반 오토스케일러)도 적용되어 부하 자동 대응 가능
  5. 모니터링 체계 구축
    • 클러스터 및 서비스 메트릭은 Prometheus를 통해 수집된다.
    • 수집된 메트릭은 Grafana 대시보드에서 시각화하여 서비스 상태(트래픽, CPU/메모리 사용량, 에러율 등)를 실시간으로 모니터링한다.
    • 경고(Alerting)는 Prometheus AlertManager를 통해 Slack, Discord 등 외부 시스템으로 전송 가능하게 설정할 수 있다.

4. 캐시 및 메시지 큐 전략

🔹 Spring Boot (Kafka Producer)

  • Namespace, Secret, Service, Deployment, Pod 구성
  • Kafka Producer 역할 명확히 표현됨
  • 내부적으로 Kafka Broker로 메시지를 발행하는 화살표 적절함

🔹 Kafka Broker + Zookeeper

  • Kafka Broker는 여러 개의 Pod로 구성됨 (StatefulSet 유추 가능)
  • Zookeeper가 Kafka 메타데이터 및 클러스터 제어를 담당
  • 위치와 방향성 모두 적절함

🔹 Kafka Consumer

  • 카카오 알림톡 아이콘과 함께 배치된 Consumer 영역 명확함
  • 여러 개의 Pod로 구성되어 소비 처리 병렬 가능성 표현됨
  • Broker → Consumer 방향 흐름도 잘 반영됨

→ Spring Boot는 Kafka Producer 역할을 하며, 사용자의 요청이나 이벤트가 발생했을 때 메시지를 Kafka Broker에 발행한다.

→ Kafka Broker는 이 메시지를 큐에 저장하고, 적절한 Kafka Consumer가 이를 비동기적으로 구독하여 처리한다.

→ 이 구조는 알림톡 서비스와 같은 메시지 기반 이벤트 처리에 매우 적합하다.

→ Kafka Consumer는 메시지를 수신한 후 외부 알림 시스템(예: 카카오톡 API)을 호출하여 실시간 알림을 전송한다.

→ Zookeeper: Kafka의 메타데이터 관리 및 클러스터 노드 간 동기화를 위한 핵심 구성 요소이다.

5. 모니터링 및 지표 수집/시각화 방안

  • Prometheus + Grafana 사용하여 어플리케이션 레벨 모니터링
  • Loki for logs
  • Tempo for tracing
  • Namespace 구분 관리

6. 장애 대응 시나리오 예시

  • Worker Node 장애:
    • 해당 노드에 있던 Pod들이 다른 정상 워커 노드로 스케줄링됨
    • 서비스 다운타임 최소화 (Ingress Controller가 살아있으면 외부 통신 문제 없음)
  • Pod 장애:
    • Kubernetes가 Pod 자동 복구
    • Rolling Update 사용하여 무중단 업데이트