Theme:

모든 데이터가 영구 저장이 필요한 것은 아닌데, 캐시 데이터나 임시 파일은 어떻게 관리하는 것이 효율적일까요?

PersistentVolume은 영구 데이터에 적합하지만, 캐시, 임시 파일, 빌드 아티팩트처럼 Pod 수명과 함께 사라져도 되는 데이터에는 과합니다. Kubernetes는 이런 용도를 위해 emptyDir, hostPath, projected 같은 다양한 볼륨 타입을 제공합니다.

emptyDir — 가장 많이 쓰는 임시 볼륨

emptyDir은 Pod이 생성될 때 빈 디렉토리로 시작하고, Pod이 삭제될 때 함께 사라지는 볼륨입니다.

YAML
apiVersion: v1
kind: Pod
metadata:
  name: shared-data
spec:
  containers:
    - name: writer
      image: busybox:1.36
      command: ['sh', '-c', 'while true; do date >> /data/log.txt; sleep 5; done']
      volumeMounts:
        - name: shared
          mountPath: /data
    - name: reader
      image: busybox:1.36
      command: ['sh', '-c', 'tail -f /data/log.txt']
      volumeMounts:
        - name: shared
          mountPath: /data
  volumes:
    - name: shared
      emptyDir: {}

emptyDir의 핵심 특성

  • Pod 내 여러 컨테이너가 공유 가능합니다
  • 컨테이너 재시작에도 유지됩니다 (Pod이 삭제될 때만 삭제)
  • 기본적으로 노드의 디스크를 사용합니다

대표적인 사용 사례

사용 사례설명
사이드카와 데이터 공유앱이 로그를 쓰고 사이드카가 수집
캐시이미지 처리, 빌드 아티팩트
스크래치 공간대용량 정렬, 임시 파일
체크포인트장기 연산의 중간 결과 저장

memory 미디엄 — RAM 기반 tmpfs

YAML
volumes:
  - name: cache
    emptyDir:
      medium: Memory       # tmpfs 사용
      sizeLimit: 256Mi     # 크기 제한

RAM에 저장하므로 매우 빠르지만, 주의할 점이 있습니다.

  • Pod의 메모리 리소스에 포함됩니다 — limits을 초과하면 OOMKill
  • 노드 재시작 시 데이터 소실
  • sizeLimit을 반드시 설정하세요

sizeLimit

YAML
volumes:
  - name: temp
    emptyDir:
      sizeLimit: 1Gi  # 1Gi 초과 시 Pod이 evict될 수 있음

sizeLimit을 초과하면 kubelet이 Pod을 추방(evict)할 수 있습니다.

hostPath — 호스트 파일시스템 접근

hostPath는 노드의 파일시스템을 Pod에 직접 마운트합니다.

YAML
volumes:
  - name: docker-socket
    hostPath:
      path: /var/run/docker.sock
      type: Socket

hostPath type 옵션

type설명
DirectoryOrCreate디렉토리가 없으면 생성
Directory디렉토리가 존재해야 함
FileOrCreate파일이 없으면 생성
File파일이 존재해야 함
SocketUnix 소켓이 존재해야 함
"" (빈 문자열)체크 없음 (기본값)

hostPath의 적합한 사용 사례

  • DaemonSet에서 노드 로그 수집 (/var/log)
  • 노드 모니터링 에이전트 (/proc, /sys)
  • Docker Socket 접근 (CI/CD 파이프라인)

hostPath의 위험

hostPath는 보안 위험이 크므로 일반 워크로드에는 사용하지 마세요.

  • 컨테이너가 호스트 파일시스템에 직접 접근 가능
  • Pod이 다른 노드로 이동하면 데이터가 다름
  • PodSecurity에서 Baseline/Restricted 프로파일은 hostPath를 제한

projected 볼륨 — 여러 소스를 하나로 결합

projected 볼륨은 ConfigMap, Secret, downwardAPI, serviceAccountToken을 하나의 디렉토리에 합칩니다.

YAML
volumes:
  - name: all-in-one
    projected:
      sources:
        - configMap:
            name: app-config
            items:
              - key: config.yml
                path: config.yml
        - secret:
            name: app-secret
            items:
              - key: api-key
                path: credentials/api-key
        - downwardAPI:
            items:
              - path: labels
                fieldRef:
                  fieldPath: metadata.labels
              - path: cpu-request
                resourceFieldRef:
                  containerName: app
                  resource: requests.cpu
        - serviceAccountToken:
            path: token
            expirationSeconds: 3600
            audience: vault

마운트된 디렉토리 구조는 다음과 같습니다.

PLAINTEXT
/etc/projected/
├── config.yml           # ConfigMap
├── credentials/
│   └── api-key          # Secret
├── labels               # downwardAPI
├── cpu-request          # downwardAPI
└── token                # ServiceAccountToken

downwardAPI — Pod 메타데이터 노출

Pod 자신의 정보를 컨테이너 내부에서 참조할 수 있습니다.

YAML
volumes:
  - name: podinfo
    downwardAPI:
      items:
        - path: "name"
          fieldRef:
            fieldPath: metadata.name
        - path: "namespace"
          fieldRef:
            fieldPath: metadata.namespace
        - path: "node"
          fieldRef:
            fieldPath: spec.nodeName
        - path: "memory-limit"
          resourceFieldRef:
            containerName: app
            resource: limits.memory

VolumeSnapshot — 볼륨 스냅샷

PV의 특정 시점 스냅샷을 생성하고 복원할 수 있습니다. CSI 드라이버가 스냅샷을 지원해야 합니다.

YAML
# 스냅샷 클래스 정의
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
  name: ebs-snapshot
driver: ebs.csi.aws.com
deletionPolicy: Retain
---
# 스냅샷 생성
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: db-snapshot-20260319
spec:
  volumeSnapshotClassName: ebs-snapshot
  source:
    persistentVolumeClaimName: db-data  # 원본 PVC

스냅샷에서 PVC 복원

YAML
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: db-data-restored
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: fast-ssd
  resources:
    requests:
      storage: 20Gi
  dataSource:
    name: db-snapshot-20260319
    kind: VolumeSnapshot
    apiGroup: snapshot.storage.k8s.io

ephemeral 볼륨 (Generic Ephemeral Volumes)

PVC처럼 StorageClass를 사용하지만 Pod 수명에 맞춰 자동으로 생성/삭제되는 볼륨입니다.

YAML
apiVersion: v1
kind: Pod
metadata:
  name: scratch-pod
spec:
  containers:
    - name: app
      image: my-app:1.0
      volumeMounts:
        - name: scratch
          mountPath: /scratch
  volumes:
    - name: scratch
      ephemeral:
        volumeClaimTemplate:
          spec:
            accessModes: ["ReadWriteOnce"]
            storageClassName: fast-ssd
            resources:
              requests:
                storage: 10Gi

emptyDir과 달리 실제 블록 스토리지를 사용하므로, 대용량 임시 데이터에 적합합니다.

볼륨 타입 선택 가이드

용도볼륨 타입수명
컨테이너 간 데이터 공유emptyDirPod
고속 캐시emptyDir (memory)Pod
노드 데이터 접근hostPath노드
설정/시크릿/메타데이터 결합projected실시간 업데이트
대용량 임시 데이터Generic EphemeralPod
영구 데이터PVCPV 정책에 따름
백업/복원VolumeSnapshot명시적 삭제까지

실무에서 주의할 점

  • emptyDir의 sizeLimit을 설정하세요: 제한 없으면 노드 디스크를 가득 채울 수 있습니다
  • hostPath는 DaemonSet에서만: 일반 워크로드에서는 보안 위험이 큽니다
  • Memory 미디엄은 리소스 제한에 포함: OOMKill 원인이 될 수 있습니다
  • VolumeSnapshot을 정기적으로: CronJob과 조합하면 자동 백업이 가능합니다

정리

모든 데이터가 PV가 필요한 것은 아닙니다. emptyDir로 컨테이너 간 공유와 캐싱을, projected로 여러 설정 소스를 결합하고, VolumeSnapshot으로 데이터를 백업합니다. 각 볼륨 타입의 수명과 특성을 이해하고 용도에 맞게 선택하는 것이 핵심입니다.

댓글 로딩 중...