Kubernetes Storage

inuit·2025년 5월 4일

All about 쿠버네티스

목록 보기
11/21
post-thumbnail

최근 업데이트일 2024-11-17

따라하며 배우는 쿠버네티스: Kubernetes Storage

쿠버네티스의 데이터 저장 메커니즘을 알기 위해, Local Volume의 해결책으로 등장하는 Network Volume, PV와 PVC를 살펴보자.

Kubernetes Storage

Pod 내부의 각 컨테이너는 이미지에서 제공되는 고유하게 분리된 파일시스템을 가진다. 

  • Pod는 컨테이너들이 CPU, 메모리, 네트워크 인터페이스 등의 리소스를 공유하며 실행되는 최소 단위로, 논리적 호스트와 유사한 역할을 한다.
  • 컨테이너가 종료되거나 재시작될 경우에도 데이터를 유지할 수 있도록 Storage Volume을 정의하여 사용한다.
    • 마운트: 운영 체제가 파일 시스템을 특정 디렉토리 경로에 연결하여 접근 가능하게 만드는 과정

Node의 Local Storage를 사용하는 Pod의 Local Volume(저장 공간) 타입에는 대표적으로 emptyDir와 hostPath가 있다.


1. Local Volume

  • emptyDir: ephemeral Data를 저장하는데 사용되는 간단한 empty 디렉토리
    • Pod가 실행될 때 노드의 임시 디스크에 디렉터리를 만들고, Pod가 삭제되면 사라진다.
    • Pod의 컨테이너 간에 Volume을 공유하기 위해 사용한다.
    • Pod가 실행되는 도중에만 필요한 데이터를 임시 저장한다.
    • 즉, Node 상에 파일 시스템 레벨로는 존재하지만,
      Kubernetes 리소스 관점에서는 Pod가 삭제되면 자동으로 삭제되는 저장소이다.
apiVersion: v1
kind: Pod
metadata:
  name: emptydir-pod
spec:
  containers:
  - name: busybox
    image: busybox # 디렉토리에 파일 작성 후 sleep
    command: ["sh", "-c", "echo hi > /data/test.txt && sleep 3600"]
    volumeMounts: # Pod의 mount 위치 지정
    - name: shared-storage
      mountPath: /data # Pod IP/data에서 확인
  volumes: 
  - name: shared-storage
    emptyDir: {}
  • hostPath: Node의 파일시스템을 Pod의 디렉터리로 마운트하는 데 사용한다.
    • Node의 지정된 실제 경로를 마운트하여 Pod가 삭제되어도 데이터는 유지된다.
    • Node에 종속적이기 때문에 Pod가 다른 Node에 scheduling되면 데이터를 볼 수 없어서 일반적으로 사용되지 않는다.
apiVersion: v1
kind: Pod
metadata:
  name: hostpath-pod
spec:
  containers:
  - name: busybox
    image: busybox
    command: ["sh", "-c", "echo hi > /mnt/data/test.txt && sleep 3600"]
    volumeMounts: # Pod의 mount 위치 지정
    - name: host-storage
      mountPath: /mnt/data 
  volumes:
  - name: host-storage
    hostPath:
      path: /data/k8s-data # Node의 로컬 파일 시스템 상 위치
      type: DirectoryOrCreate # 디렉토리가 없으면 자동 생성
# data 확인
kubectl exec -it emptydir-pod -- cat /data/test.txt # emptyDir
kubectl exec -it hostpath-pod -- cat /mnt/data/test.txt # hostPath

Pod가 어떤 Node에서 실행될지 모르기 때문에 Network Volume이 필요하다.


2. Network Volume

Stateful Pod가 내부에서 특정 데이터를 보유해야 하거나 데이터를 Node 간에 공유하고 스케줄링 유연성을 보장하려면, 네트워크를 통해 접근 가능한 저장소가 필요하다.

  • 어떤 클러스터 Node에서도 접근이 필요하기에 일반적으로 NAS, SAN, Object Storage 유형의 저장소에 데이터를 저장한다.
    • DAS (Direct Attached Storage): 서버에 물리적으로 직접 꽂는 디스크
      • SSD, NVMe, SATA 드라이브 등이 해당된다.
    • NAS(Network Attached Storage): 여러 사용자가 네트워크를 통해 TCP/IP 네트워크로 공유하는 중앙 집중식 파일 서버
      • 파일 공유가 용이하고, 설치가 간편하다.
      • NFS, GlusterFS, PVC와 PV, Cephfs 등이 해당된다.
        • NFS(Network File System)는 전통적인 UNIX 기반 파일 공유 프로토콜이다.
    • SAN(Storage Area Network): 블록 단위 공유를 위한 고성능 네트워크 스토리지
      • 저장 장치간 데이터 이동이 가능 하며 빠르지만, 가격이 비싸다.
      • iSCSI, AWS EBS, GCP Persistent Disk, Ceph RBD 등이 해당된다.
    • Object Storage: 인터넷 기반 객체 단위 저장소
      • API로 접근할 수 있고 HTTP(S) 기반이며, 확장성 뛰어나고 메타데이터 관리에 유리하다.
      • Ceph Object Gateway, AWS S3 등이 해당된다.
  • Network Volume을 사용하기 위해 Pod의 volumeMounts(Pod 내 마운트 위치)를 지정 후 spec.volumes.nfs.path에 PATH를, spec.volumes.nfs.serverNFS_SERVICE_IP를 작성하여 Pod에서 마운트한다.
  • NFS Volume 마운트는 Worker Node에서 발생해서 서비스의 DNS 이름으로 서버에 접근할 수 없기 때문에, 일단은 NFS 서비스의 Cluster IP를 직접 얻은 뒤, YAML 파일에 사용하는 방식으로 Pod를 생성을 진행한다.

위와 같은 과정으로 Network Volume을 사용하는 것은 Pod마다 NFS 정보를 반복 설정해야 하며, 동적 할당이 불가하기 때문에 추상화와 자동화 등을 제공하는 PersistentVolume(=PV)과 PersistentVolumeClaim(=PVC)을 이용한다.


3. PV와 PVC

동적으로 생성되고 제거되는 Pod들과 분리된 저장소를 추상화하여 사용하게 만들기 위해 등장한 개념

  • 운영자는 미리 저장소(PV)를 구성하고, 개발자는 필요한 시점에 PVC를 통해 저장소를 요청하여 사용한다.
  • PV: 관리자가 미리 생성한 저장소 객체
    • 실제 스토리지 백엔드(NFS, EBS, iSCSI 등)와 연결되어 있으며, PVC를 통해 간접적으로 사용한다.
    • 주요 속성
      • capacity: 스토리지 용량
      • accessModes: 접근 방식
        • ReadWriteOnce: 하나의 노드에서 읽기/쓰기
        • ReadOnlyMany: 여러 노드에서 읽기만 가능
        • ReadWriteMany: 여러 노드에서 읽기/쓰기 가능
      • persistentVolumeReclaimPolicy: PVC 삭제 시 PV의 처리 방식
        • Retain: PV의 데이터 보존
        • Delete: PV와 실제 스토리지 삭제 (주로 동적 프로비저닝)
        • Recycle: 기존 데이터 삭제 후 재사용 (거의 사용 안 함)
  • PVC: 개발자가 Pod 안에서 사용하는 스토리지 요청 객체
    • 필요한 용량(resources.requests.storage)과 접근 방식(accessModes)을 정의한다.
    • 조건에 맞는 PV가 자동으로 바인딩되며, PV의 접근 방식과 호환되어야 연결 가능하다.
    • 주요 속성
      • accessModes: 사용하고자 하는 PV의 accessModes와 동일한 옵션을 사용해야 바운딩이 가능하다
      • requests: 사용을 원하는 용량 명시한다.
      • storage: 사용하고자 하는 최소한의 크기로서 명시한 용량보다 큰 PV도 상관 없다.
  • PV 마운트는 Pod의 spec.containers.volumeMounts에 Pod 내 디렉토리 지정 후 volumes.hostPath를 PV 위치로 지정해서 진행한다.
  • PVC 마운트는 spec.containers.volumeMounts에 Pod 내부 디렉토리 경로 지정 후 volumes.persistentVolumeClaim을 PVC name으로 지정해서 진행한다.
  • 생명 주기
    1. Provisioning: PV를 만드는 단계
      • 정적 프로비저닝: PV를 미리 만들어 두고 사용, 스토리지 용량에 제한이 있을 때
      • 동적 프로비저닝: 요청이 있을 때마다 PV 생성, 사용자가 원하는 용량 만큼 사용 가능
    2. Binding: PV와 PVC를 1대 1로 연결, PVC가 원하는 PV가 생길 때까지 바인딩한다.
    3. Using: Pod에서 PVC를 참조하여 저장소를 사용, StorageObjectInUseProtection에 의해 PVC가 사용 중이면 삭제되지 않는다.
    4. Reclaming: 사용이 끝난 PVC 삭제 후 PV 초기화
  • 데이터베이스 등 지속성이 중요한 앱은 반드시 PVC로 외부 스토리지에 연결해야 한다.
  • 클라우드 환경에서는 대부분 StorageClass를 이용한 동적 프로비저닝을 사용한다.
    • StorageClass: PVC가 생성될 때, 어떤 방식으로 PV를 자동으로 만들지 정의해 놓은 템플릿

4. 실제 사용 예시 (NFS와 PV, PVC)

1. NFS 서버를 Kubernetes 내부에 구성

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-server
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nfs-server
  template:
    metadata:
      labels:
        app: nfs-server
    spec:
      containers: 
      - name: nfs # 이미 만들어진 공개 이미지 사용
        image: itsthenetwork/nfs-server-alpine:latest
        ports:
        - name: nfs
          containerPort: 2049
        securityContext:
          privileged: true # NFS 커널 모듈 사용을 위한 권한 필요
        env:
        - name: SHARED_DIRECTORY 
          value: /exports # 공유 디렉토리 경로 설정
---
apiVersion: v1
kind: Service
metadata:
  name: nfs-service
spec:
  selector:
    app: nfs-server
  ports:
  - name: nfs
    port: 2049
    targetPort: 2049
  clusterIP: None
  • 컨테이너에 포트를 설정하고 이미지를 가져와 Deployment와 Service로 임시 NFS 서버를 열 수 있다.
  • Headless Service로 설정하여 DNS 이름이 Pod에 직접 바인딩된다.

2. PV 생성

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
spec:
  capacity:
    storage: 1Gi # 최대 1GiB까지 PVC에서 요청 가능
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs: # Headless DNS로 NFS Pod 직접 참조
    server: nfs-server-0.nfs-service.default.svc.cluster.local 
    path: /exports/data # 실제 NFS 서버의 공유 디렉토리 경로

3. PVC 생성

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
spec:
  accessModes:
    - ReadWriteMany # PV와 동일한 모드로 설정해야 바인딩 가능
  resources:
    requests:
      storage: 500Mi # 최소 500Mi 요청

4. 실제 Pod에서 PVC 사용

apiVersion: v1
kind: Pod
metadata:
  name: nfs-client
spec:
  containers:
  - name: app
    image: busybox
    command: ["sh", "-c", "echo hi > /mnt/nfs/hello.txt && sleep 3600"]
    volumeMounts: 
    - name: nfs-vol
      mountPath: /mnt/nfs # Pod 내에서 접근할 NFS 디렉토리 경로
  volumes:
  - name: nfs-vol
    persistentVolumeClaim: # 이 PVC를 통해 PV와 연결
      claimName: nfs-pvc
profile
It’s always white night here.

0개의 댓글