본문 바로가기
클라우드/쿠버네티스

쿠버네티스에 DB를 올려도 될까? — 프로덕션 환경에서의 현명한 선택 🤔

by gasbugs 2026. 3. 28.

"컨테이너 위에 올리면 다 쿠버네티스가 알아서 해주지 않나요?"
많은 개발자들이 처음 쿠버네티스를 접할 때 하는 착각


🎯 이 글에서 다루는 것

  • 쿠버네티스 위에 DB를 올려도 되는 조건과 올리면 안 되는 이유
  • 로그 수집 도구(Fluent Bit, Loki 등)는 왜 컨테이너로 구성해도 괜찮은가
  • 프로덕션 DB를 쿠버네티스 외부로 분리하는 실제 이유
  • 로그 데이터의 법적 보관 의무 (한국 법령 기준)
  • 실무에서 자주 사용하는 구성 패턴과 예제

📌 도입 / 배경

쿠버네티스(Kubernetes)가 보편화되면서 "모든 걸 컨테이너로!" 라는 흐름이 강해졌습니다. 덩달아 "DB도 쿠버네티스 위에 올리면 안 되나?" 라는 질문이 자연스럽게 생겨납니다.

 

짧게 답하면: "올릴 수는 있다. 하지만 프로덕션 환경에서는 신중해야 한다."

 

쿠버네티스는 무상태(stateless) 워크로드에 최적화된 플랫폼입니다. 웹 서버, API 서버처럼 요청을 받고 응답하는 애플리케이션은 Pod가 죽고 다시 살아나도 크게 문제없습니다. 하지만 DB는 다릅니다. 데이터가 사라지면 끝이기 때문입니다.

 

그렇다면 로그(log)는 어떨까요? 로그 수집 에이전트와 로그 저장 DB는 프로덕션 DB와는 결이 다릅니다. 그리고 여기에는 법적인 고려사항까지 얽혀 있습니다.

 

지금부터 하나씩 풀어보겠습니다.


🔍 쿠버네티스의 특성: 왜 DB와 궁합이 까다로운가

쿠버네티스는 "일회용" 철학을 가진 플랫폼

쿠버네티스는 Pod를 언제든 종료하고 새로 생성할 수 있다고 전제합니다. 이것을 Ephemeral(일시적인) 특성이라고 합니다. 노드 장애, 스케일링, 롤링 업데이트… 모든 상황에서 Pod는 언제든 사라질 수 있습니다.

 

DB는 이 철학과 충돌합니다. DB의 핵심은 데이터의 영속성(Persistence) 입니다.

 

쿠버네티스는 이 문제를 해결하기 위해 PV/PVC(Persistent Volume / Persistent Volume Claim) 를 제공하지만, 이것이 완벽한 해답은 아닙니다.

 

프로덕션 DB를 쿠버네티스 밖으로 빼는 5가지 이유

① 데이터 영속성 보장의 어려움

PV를 사용해도 노드가 통째로 죽거나 스토리지 백엔드에 문제가 생기면 데이터 손실 위험이 있습니다. 클라우드 관리형 DB(AWS RDS, Azure Database 등)는 자체적으로 멀티 AZ 복제, 자동 백업, 포인트인타임 복구(PITR)를 제공합니다.

② StatefulSet의 운영 복잡도

쿠버네티스에서 DB를 운영하려면 StatefulSet을 써야 합니다. StatefulSet은 각 Pod에 고유한 ID와 스토리지를 부여하여 순서 있는 배포/삭제를 보장합니다. 그런데 MySQL InnoDB Cluster, PostgreSQL HA, MongoDB ReplicaSet 같은 클러스터링, 페일오버, 리더 선출 로직을 직접 관리하는 것은 상당한 운영 부담입니다.

# StatefulSet 예시 — DB를 K8s에서 운영할 경우
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
spec:
  serviceName: "postgres"
  replicas: 3
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
      - name: postgres
        image: postgres:15
        volumeMounts:
        - name: pgdata
          mountPath: /var/lib/postgresql/data
  volumeClaimTemplates:           # 각 Pod마다 별도 PVC 생성
  - metadata:
      name: pgdata
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 50Gi

위 설정만 봐도 복잡합니다. 여기에 백업 CronJob, 모니터링 Exporter, 네트워크 정책, 보안 컨텍스트까지 더하면 운영팀의 부담은 배가됩니다.

 

③ 네트워크 레이턴시와 스토리지 I/O 성능

쿠버네티스의 네트워크는 오버레이 네트워크(CNI)를 통해 동작합니다. DB는 고속 I/O와 낮은 레이턴시가 핵심인데, 컨테이너화로 인한 네트워크 오버헤드와 스토리지 추상화 레이어가 성능에 영향을 줄 수 있습니다. 특히 NVMe SSD에 직접 접근하는 베어메탈 DB 대비 성능 차이가 발생할 수 있습니다.

 

④ 보안 격리의 어려움

컨테이너는 OS 커널을 공유합니다. 만약 같은 노드에 있는 다른 컨테이너가 취약점을 통해 노드에 접근한다면, DB 데이터까지 위험해질 수 있습니다. 관리형 DB 서비스는 전용 인프라에서 격리되어 운영됩니다.

 

⑤ 라이선스 및 운영 도구 호환성

Oracle, MS SQL Server 같은 상용 DB는 컨테이너 환경에 대한 라이선스 정책이 복잡하고, 공식 지원 수준이 베어메탈보다 낮은 경우가 있습니다.


🪵 그러면 로그(Log) DB는 쿠버네티스에 올려도 될까?

로그 수집 아키텍처의 특성

로그 시스템은 크게 세 계층으로 나뉩니다:

계층 역할 예시 도구
수집 에이전트 각 Pod/Node에서 로그 수집 Fluent Bit, Filebeat
집계/처리 파싱, 필터링, 라우팅 Fluentd, Logstash
저장/조회 로그 저장 및 검색 Loki, Elasticsearch, ClickHouse

수집 에이전트 — 컨테이너로 운영하는 것이 자연스럽다

Fluent Bit 같은 로그 수집 에이전트는 DaemonSet으로 배포하는 것이 표준 패턴입니다. DaemonSet은 각 노드에 하나씩 Pod를 배포합니다. 노드 레벨의 로그 파일(/var/log/containers/)에 접근해서 로그를 수집하는 역할이기 때문입니다.

# Fluent Bit DaemonSet 핵심 부분
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluent-bit
  namespace: logging
spec:
  selector:
    matchLabels:
      app: fluent-bit
  template:
    spec:
      containers:
      - name: fluent-bit
        image: fluent/fluent-bit:2.2
        volumeMounts:
        - name: varlog
          mountPath: /var/log          # 호스트 로그 디렉토리 마운트
          readOnly: true
        - name: containers
          mountPath: /var/lib/docker/containers
          readOnly: true
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: containers
        hostPath:
          path: /var/lib/docker/containers

 

에이전트 자체는 상태를 저장하지 않습니다. Pod가 죽어도 다시 시작되면 그 시점부터 로그를 수집하면 됩니다(약간의 수집 공백은 있을 수 있으나 치명적이지 않음).

로그 저장 DB — 어디에 올릴지는 요구사항에 달려 있다

로그 저장 DB(예: Loki, Elasticsearch)를 쿠버네티스에 올리는 것은 운영 DB보다는 허용 범위가 넓습니다.

이유는 다음과 같습니다:

  • ✅ 로그는 일부 유실되어도 비즈니스에 치명적이지 않은 경우가 많음
  • ✅ 로그 데이터는 재생성 불가능한 원본 데이터가 아님 (소스는 애플리케이션에 있음)
  • ✅ Loki, Elasticsearch 모두 쿠버네티스 환경을 공식 지원하는 Helm Chart 제공
  • ✅ Grafana + Loki + Fluent Bit 스택은 쿠버네티스 네이티브 로깅의 사실상 표준

단, 법적 보관 의무가 있는 로그라면 이야기가 달라집니다. 다음 섹션에서 자세히 다룹니다.


⚖️ 법적 문제 — 로그를 어떻게 보관해야 하나?

이 부분은 실무에서 간과하기 쉽지만 매우 중요합니다.

한국 주요 법령의 로그 보관 의무

법령 대상 보관 항목 보관 기간
개인정보 보호법 개인정보 처리자 전체 개인정보 처리 시스템 접속 기록 최소 6개월 (1만 명 이상 또는 민감정보: 2년)
정보통신망법 정보통신서비스 제공자 개인정보 취급자 접속 기록 최소 6개월
전자금융거래법 금융기관, 전자금융업자 전자금융거래 기록 5년
전자상거래법 온라인 쇼핑몰 등 계약·청약 기록, 대금 결제 기록 등 5년 (계약), 3년 (불만 처리)
의료법 의료기관 진료 기록, 진료 관련 전산 기록 10년 (진료기록부 기준)

📌 개인정보 보호법 시행령 제30조: 접속 기록의 보관·점검 의무. 1만 명 이상의 정보주체 또는 고유식별정보·민감정보를 처리하는 경우 최소 2년 보관 및 월 1회 이상 점검 의무.

법적 보관 의무 로그를 쿠버네티스에만 두면 안 되는 이유

쿠버네티스 내의 PV는 인프라 변경, 클러스터 마이그레이션, 운영 실수로 인해 삭제될 위험이 있습니다. 법적 보관 의무 로그는 반드시 아래 조건을 충족해야 합니다:

  • 삭제·변조 방지: 접근 제어 + 불변 스토리지(WORM, Write Once Read Many)
  • 장기 보존: 의무 기간 동안 안정적으로 보관
  • 검색 및 감사: 보관 기관이나 조사기관 요청 시 즉시 제공 가능

권장 아키텍처: 쿠버네티스에서 수집된 로그는 클라우드 오브젝트 스토리지(AWS S3, Azure Blob Storage, NCP Object Storage)에 장기 보관하고, 쿠버네티스 내부의 로그 DB는 단기 조회 목적으로만 사용하는 이중 구조를 권장합니다.

[Pod 로그] 
    → Fluent Bit (DaemonSet, K8s 내)
    → Loki or Elasticsearch (K8s 내, 단기 조회용: 30~90일)
    → S3 / Azure Blob (장기 보관용, WORM 설정: 법정 기간)

💻 실습 예제: Fluent Bit → S3 이중 출력 설정

# fluent-bit.conf — 로그를 Loki(조회용)와 S3(장기보관)에 동시 전송

[SERVICE]
    Flush        5
    Daemon       Off
    Log_Level    info

[INPUT]
    Name             tail
    Path             /var/log/containers/*.log
    Parser           docker
    Tag              kube.*
    Refresh_Interval 5

# 출력 1: Loki (단기 조회용)
[OUTPUT]
    Name             loki
    Match            kube.*
    Host             loki.monitoring.svc.cluster.local
    Port             3100
    Labels           job=fluentbit

# 출력 2: S3 (법적 보관용, 장기)
[OUTPUT]
    Name                         s3
    Match                        kube.*
    bucket                       my-log-archive-bucket
    region                       ap-northeast-2
    s3_key_format                /logs/%Y/%m/%d/$TAG[4].%H%M%S.gz
    compression                  gzip
    use_put_object               On
    total_file_size              100M      # 100MB 단위로 묶어서 저장
    upload_timeout               600       # 10분마다 강제 업로드

⚠️ 주의사항 / 흔한 실수

① PV 삭제 실수

kubectl delete pvc <name> 명령어 하나로 DB 볼륨이 삭제될 수 있습니다. reclaimPolicy: Retain 설정을 반드시 확인하세요.

apiVersion: v1
kind: PersistentVolume
spec:
  persistentVolumeReclaimPolicy: Retain  # ← 반드시 Retain으로 설정

 

② 로그 수집 에이전트에 과도한 권한 부여

Fluent Bit에 cluster-admin 권한을 주는 경우가 있는데, 이는 보안 위험입니다. 최소 권한 원칙에 따라 필요한 RBAC 권한만 부여하세요.

 

③ 법적 보관 로그를 K8s 클러스터 내부에만 보관

클러스터를 삭제하거나 PV가 유실되면 감사 대응이 불가능합니다. 앞서 설명한 이중 저장 구조를 반드시 구성하세요.

 

④ 로그에 개인정보 포함 여부 미확인

API 요청 로그, 에러 로그에 이름, 이메일, IP 주소 등 개인정보가 포함된다면 그 로그 자체가 개인정보 처리에 해당합니다. 개인정보 보호법상 처리 목적, 보관 기간, 파기 기준을 명확히 정의해야 합니다.


✅ 정리 / 마무리

구분 쿠버네티스 위 운영 권장 대안

구분 쿠버네티스 위 운영 권장 대안
프로덕션 DB ⚠️ 가능하지만 운영 부담 큼 관리형 DB 서비스 (RDS, Azure DB 등)
로그 수집 에이전트 ✅ 권장 (DaemonSet 패턴)
로그 저장 DB (단기) ✅ 가능 (Loki, ES)
법적 보관 의무 로그 ❌ K8s 단독 보관 위험 오브젝트 스토리지 + WORM 병행

 

핵심 요약:

  • 🐳 프로덕션 DB: 쿠버네티스 외부로 분리. 관리형 서비스 활용.
  • 🪵 로그 에이전트: DaemonSet으로 쿠버네티스에 올리는 것이 표준.
  • 📦 로그 저장 DB: 단기 조회용은 K8s 내, 법적 보관 의무 로그는 오브젝트 스토리지에 별도 보관.
  • ⚖️ 법적 의무: 개보법·전자금융거래법 등 해당 법령 확인 후 보관 기간·방식 준수.

다음 단계로는 Grafana + Loki + Fluent Bit 스택을 직접 Helm으로 구성해보는 실습을 추천드립니다.