Kubernetes 환경에서 MySQL, Redis, Kafka, Elasticsearch 배포하기

이상훈·2026년 2월 15일

Project

목록 보기
16/17

현재 진행 중인 baro-farm 프로젝트에서는 MySQL, Redis, Kafka, Elasticsearch를 k3s 기반 Kubernetes MSA 환경에 배포해야 했다. 기존에는 AWS의 관리형 서비스(RDS, ElastiCache 등)를 중심으로 인프라를 구성해 왔지만, Kubernetes 환경에서는 같은 인프라도 여러 방식으로 배포하고 운영할 수 있다는 점을 새롭게 알게 되었다. 이번 글에서는 baro-farm 프로젝트에서 각 인프라(MySQL, Redis, Elasticsearch, Kafka)를 어떤 방식으로 배포했는지, 그리고 왜 그런 선택을 했는지 정리해보려고 한다.

MySQL

1. AWS RDS 사용

AWS RDS(Amazon Relational Database Service)는 관계형 데이터베이스를 손쉽게 생성하고 운영할 수 있도록 지원하는 관리형 Database as a Service이다. DB 설치, 버전 관리, 패치, 백업 등의 운영 작업을 AWS가 대신 처리해주기 때문에 개발자는 인프라 관리보다 애플리케이션 개발에 집중할 수 있다. RDS는 다음과 같은 기능을 제공한다.

  • 자동 백업 및 스냅샷 관리
  • Multi-AZ 기반 고가용성 구성
  • 자동 Failover
  • 모니터링 및 장애 감지

Kubernetes 환경에서는 애플리케이션 Deployment에서 DB Endpoint를 Secret이나 환경 변수로 주입하여 외부 RDS와 쉽게 연결할 수 있다.

❌ 선택하지 않은 이유 : 이번 프로젝트에서는 Multi-AZ나 자동 백업 같은 기능이 필수는 아니었고, 프로젝트 규모 대비 RDS 비용이 부담스럽다고 판단했다.


2. MySQL Operator 사용

Operator는 Kubernetes에서 특정 애플리케이션의 운영 지식을 코드로 구현한 Custom Controller이다. 즉 사람이 수행하던 운영 작업을 Kubernetes Controller가 자동으로 수행하도록 만든 구조다. MySQL Operator는 MySQL InnoDB Cluster를 Kubernetes 환경에서 선언적으로 관리할 수 있도록 지원한다. Helm을 통해 Operator를 설치하면 Operator Deployment, CRD(Custom Resource Definition) 리소스가 생성된다. 이후 사용자는 Custom Resource만 정의하면 MySQL 클러스터가 자동으로 생성된다.

apiVersion: mysql.oracle.com/v2
kind: InnoDBCluster
metadata:
  name: mysql-cluster
spec:
  instances: 3
  router:
    instances: 1

Operator는 다음 기능을 제공한다.

  • Primary / Replica 자동 구성
  • Failover 자동화
  • 백업 및 복구 자동화
  • Rolling Update
  • StatefulSet 기반 관리

즉 Kubernetes 환경에서도 Managed DB에 가까운 운영 경험을 제공한다.

❌ 선택하지 않은 이유 : 이번 프로젝트에서는 DB 이중화나 자동 백업이 필수 요구사항이 아니었고, Operator Pod 및 추가 리소스를 운영하는 부담이 있다고 판단했다.


3. 직접 Yaml 작성

가장 기본적인 방법은 Kubernetes 리소스를 직접 YAML로 작성하는 방식이다. MySQL을 Kubernetes에 배포하려면 일반적으로 다음 리소스가 필요하다.

  • StatefulSet : MySQL 컨테이너 정의, 볼륨 마운트, 환경 변수, Health Probe 등을 관리
  • Service : 클러스터 내부 혹은 외부에서 MySQL에 접근하기 위한 네트워크 엔드포인트 제공
  • PersistentVolumeClaim (PVC) : 데이터 영속성 보장을 위한 스토리지 요청
  • ConfigMap / Job (선택) : 초기 스키마 생성이나 데이터 초기화를 위한 작업 정의

왜 StatefulSet과 PV/PVC가 필요한가?
DB는 Stateless 애플리케이션과 달리 상태(State)를 가지는 서비스이다. Pod가 재시작되거나 다른 노드로 이동하더라도 데이터는 유지되어야 한다. 이를 위해 Kubernetes에서는 다음 구조를 사용한다.

StatefulSet

  • Pod 이름 고정(mysql-0, mysql-1)
  • Pod 재생성 시 동일 스토리지 사용

PersistentVolume / PersistentVolumeClaim

  • Pod lifecycle과 독립적인 데이터 저장
  • Pod 재스케줄링 시에도 데이터 유지

즉 Kubernetes에서 DB를 운영할 때는 일반적으로 StatefulSet + Persistent Storage 구조가 사용된다.

❌ 선택하지 않은 이유 : 모든 리소스를 직접 관리해야 하기 때문에 운영 부담이 크고 유지보수성이 떨어진다고 판단했다.


4. Helm 차트 사용

Helm은 Kubernetes 리소스를 패키지 형태로 관리할 수 있는 패키지 매니저이다. 일반적으로 Kubernetes에서 애플리케이션을 배포하려면 StatefulSet, Service, PVC, ConfigMap 등 여러 리소스를 직접 정의해야 한다. 하지만 Helm을 사용하면 이러한 리소스를 Chart 형태로 템플릿화할 수 있고, values.yaml을 통해 설정을 쉽게 관리할 수 있다. 이번 프로젝트에서는 Bitnami MySQL Helm Chart를 사용해 MySQL을 배포했다.

  • Chart.yaml

    apiVersion: v2
    name: baro-mysql
    description: MySQL deployment for baro-farm using the Bitnami MySQL chart as a dependency.
    type: application
    version: 0.1.0
    dependencies:
     - name: mysql
       version: 14.0.3
       repository: https://charts.bitnami.com/bitnami
  • values-mysql.yaml

    global:
     imageRegistry: public.ecr.aws
     security:
       allowInsecureImages: true
    mysql:
     auth:
       existingSecret: mysql-credentials
       database: "baro_db"
       username: "baro_user"
    
     architecture: standalone
    
     primary:
       persistence:
         enabled: true
         storageClass: gp3-ebs
         size: 4Gi
    
       resources:
         requests:
           cpu: "200m"
           memory: "512Mi"
         limits:
           cpu: "500m"
           memory: "1Gi"
    
       service:
         type: NodePort
         nodePorts:
           mysql: 32000
    
     image:
       repository: bitnami/mysql
       tag: 9.4.0-debian-12-r1

✅ 선택한 이유 : Helm Chart를 사용하면 검증된 템플릿을 기반으로 리소스를 빠르게 배포할 수 있다. 또한 values.yaml을 통해 스토리지, 리소스, 인증 정보, 이미지 태그 등의 설정을 선언적으로 관리할 수 있어 운영과 유지보수가 훨씬 수월해진다.


스토리지 선택 – 왜 EBS(gp3)를 썼는가?

MySQL 데이터를 어디에 저장할 것인지도 중요한 설계 포인트였다. AWS 기반의 k3s on EC2 환경에서 고려한 스토리지 옵션은 다음과 같았다.

1. EBS(Elastic Block Store) : EBS는 EC2 인스턴스에 연결하는 블록 스토리지 서비스이다.

  • 단일 AZ에서 동작하지만, EC2 인스턴스가 종료되더라도 볼륨 자체는 유지.
  • EBS CSI Driver를 통해 Kubernetes의 PersistentVolume과 StorageClass로 사용 가능.
  • gp3 타입은 용량, IOPS, 처리량을 독립적으로 설정할 수 있어 DB 워크로드에 적합.

✅ 선택한 이유 : EC2 인스턴스가 종료되더라도 EBS 볼륨 자체는 유지되기 때문에 데이터 영속성을 보장할 수 있다.


2. EFS(Elastic File System) : EFS는 여러 인스턴스에서 동시에 접근 가능한 NFS 기반 파일 스토리지이다.

  • Multi-AZ 환경에서 접근 가능.
  • 여러 노드가 동일한 파일 시스템을 공유 가능.
  • 지연(latency) 및 I/O 특성이 데이터베이스에 적합하지 않음.
  • 비용이 상대적으로 높은 편.
  • 별도의 스토리지 레이어(EFS / NFS 서버)를 운영해야 함.

❌ 선택하지 않은 이유 : 현재 프로젝트 규모에서 별도 스토리지 레이어(EFS/NFS)를 운영하는 것은 오버엔지니어링이라고 판단했다.


3. 로컬 스토리지 : 로컬 스토리지는 특정 노드에 직접 연결된 디스크라고 볼 수 있다. 예를 들어 k3s에서 기본 제공되는 local-path StorageClass가 여기에 해당한다.

  • 구성 자체가 매우 단순.
  • 네트워크 hop이 없어 지연(latency)이 낮음.
  • 노드 장애 시 데이터 유실 가능

❌ 선택하지 않은 이유 : MySQL과 같은 영구 데이터 저장에는 적합하지 않다고 판단했다.


Redis

Redis 역시 MySQL과 마찬가지로 Kubernetes 환경에서 AWS ElastiCache, Redis Operator, 직접 YAML 작성, Helm Chart 사용 등 다양한 방식으로 배포할 수 있다. 이번 프로젝트에서는 MySQL을 Helm Chart로 배포했을 때와 같은 이유로, Redis도 Helm Chart를 활용해 배포했다.

Redis는 이번 프로젝트에서 Refresh Token 저장소와 캐시 용도로만 사용되었기 때문에, 데이터 영속성이 반드시 필요한 상황은 아니었다. 따라서 별도의 PV/PVC를 구성해 영구 스토리지를 붙이지 않고, Stateless한 방식으로 운영했다.


ElasticSearch

Elasticsearch 역시 MySQL과 마찬가지로 Kubernetes 환경에서 AWS OpenSearch Service, Elasticsearch Operator, 직접 YAML 작성, Helm Chart 사용 등 다양한 방식으로 배포할 수 있다. 이번 프로젝트에서는 앞서 MySQL과 Redis를 Helm Chart로 배포했을 때와 같은 맥락으로, Elasticsearch도 Helm Chart를 활용해 배포했다.

다만 Elasticsearch는 상품 검색, 추천, 사용자 행동 로그 분석을 위한 검색 인덱스 데이터를 저장하는 핵심 컴포넌트이기 때문에, 장애가 발생하더라도 인덱스를 가능한 보존할 수 있어야 했다. 따라서 MySQL과 동일하게 EBS 기반 StorageClass를 사용해 PV/PVC를 구성하고, Elasticsearch 데이터를 EBS(gp3)에 영구적으로 저장하도록 설계했다.


Kafka

Kafka 역시 MySQL과 마찬가지로 Kubernetes 환경에서 AWS MSK(Managed Streaming for Apache Kafka), Kafka Operator(Strimzi), 직접 YAML 작성, Helm Chart 사용 등 다양한 방식으로 배포할 수 있다. 이번 프로젝트에서는 이 중에서 Strimzi Kafka Operator를 사용해 Kafka 클러스터를 구성했다.

Kafka는 MySQL처럼 단순히 StatefulSet만 구성한다고 해서 끝나는 서비스가 아니다. Broker 관리, Topic 생성 및 설정, User/ACL 관리, KRaft 설정 등 운영 과정에서 고려해야 할 요소가 많다. 따라서 Operator를 위한 Pod 리소스가 추가로 필요하더라도, Helm 기반의 단순 배포보다는 Operator를 통해 Kafka 리소스를 선언적으로 관리하는 방식이 더 적합하다고 판단했다. 스토리지 구성은 MySQL과 동일하게 EBS 기반 StorageClass를 사용해 PV/PVC를 구성했으며, Kafka 로그 데이터를 EBS(gp3)에 영구적으로 저장하도록 설계했다.


요약

인프라고려한 옵션최종 선택스토리지 전략
MySQLAWS RDS, MySQL Operator, 직접 YAML 작성, Helm ChartHelm ChartEBS(gp3) 기반 PV/PVC
RedisAWS ElastiCache, Redis Operator, 직접 YAML 작성, Helm ChartHelm Chart영속 스토리지 미사용
ElasticsearchAWS OpenSearch, Elasticsearch Operator, 직접 YAML 작성, Helm ChartHelm ChartEBS(gp3) 기반 PV/PVC
KafkaAWS MSK, Strimzi Operator, 직접 YAML 작성, Helm ChartStrimzi Kafka OperatorEBS(gp3) 기반 PV/PVC
profile
Problem Solving과 기술적 의사결정을 중요시합니다.

0개의 댓글