Kubernetes 저장 볼륨 활용 가이드

시작하기 전에

컨테이너의 데이터는 기본적으로 영구적이지 않습니다. 컨테이너가 종료되면 데이터도 함께 사라집니다. 이러한 한계를 극복하기 위해 Docker는 Volume 메커니즘을 제공하며, Kubernetes는 더 강력한 Volume 기능과 다양한 플러그인을 지원합니다.

Kubernetes에서 Volume의生命周期는 Pod와 연결됩니다. 컨테이너가 재시작되어도 Volume 데이터는 유지되며, 只有 Pod가 삭제될 때만 Volume이 정리됩니다. 단, Volume 유형에 따라 데이터 보존 여부가 다릅니다. emptyDir의 경우 데이터가 사라지지만, PersistentVolume은 데이터를 보존합니다.

PersistentVolume과 PersistentVolumeClaim 이해하기

PersistentVolume(PV)과 PersistentVolumeClaim(PVC)은 Kubernetes가 제공하는 저장소 추상화 리소스입니다. 관리자는 PV를 통해 저장소를 제공하고, 사용자는 PVC를 통해 저장소를 요청합니다. 이 둘의 관계는 Pod와 Node의 관계와 유사합니다 - 전자가 후자의 리소스를 소비합니다.

生命周期 단계

1. 프로비저닝(Provision): 관리자가 클러스터에 다수의 PV를 생성합니다.

2. 바인딩(Bind): 사용자가 필요한资源和 접근 모드를 지정하여 PVC를 생성합니다. 사용 가능한 PV가 발견되기 전까지 PVC는 바인딩되지 않은 상태로 유지됩니다.

3. 사용(Use): Pod에서 일반 Volume처럼 PVC를 사용할 수 있습니다.

4. 해제(Release): 사용자가 PVC를 삭제하여 저장소 리소스를 회수합니다. PV는 "Released" 상태가 되며, 이전 데이터가 여전히 존재하므로 적절한 처리 전략이 필요합니다.

5. 회수(Reclaim): PV는 세 가지 회수 정책을 가집니다:

  • Retain: 데이터를 수동으로 처리합니다.
  • Delete: PV와 외부 저장소 리소스를 함께 삭제합니다(플러그인 지원 필요).
  • Recycle: 데이터를 삭제하고 새로운 PVC에서 재사용할 수 있습니다(플러그인 지원 필요).

PV 속성

  • 용량: 현재는 저장 크기만 지원하며, 향후 IOPS와 처리량 지원 예정입니다.
  • 접근 모드:
    • ReadWriteOnce: 단일 노드에서 읽기/쓰기 가능
    • ReadOnlyMany: 여러 노드에서 읽기 전용
    • ReadWriteMany: 여러 노드에서 읽기/쓰기 가능
  • 회수 정책: NFS와 HostPath는 회수 지원, AWS EBS, GCE PD, Cinder는 삭제 지원
  • 상태: Available(미바인딩), Bound(바인딩됨), Released(PVC 삭제됨), Failed(자동 회수 실패)

PVC 속성

  • 접근 모드: PV와 동일하며, 자원을 요청할 때 사용
  • 자원 요청: 필요한 저장 용량 지정

주요 Volume 유형

  • emptyDir: Pod가 노드에 할당되면 생성되며, Pod가 노드에서 제거될 때 삭제됩니다. 컨테이너 크래시로는 삭제되지 않습니다.
  • hostPath: 노드의 파일 시스템을 Pod에 마운트합니다.
  • NFS: 네트워크 파일 시스템으로 영구 저장소로 활용됩니다.
  • gcePersistentDisk: Google Cloud Platform 영구 디스크 마운트용
  • awsElasticBlockStore: AWS EBS 볼륨 마운트용
  • gitRepo: Git 저장소의 코드를 클론합니다.
  • Projected Volume: secret, downwardAPI, configMap을 하나의 디렉토리에 매핑합니다.

실습: Volume 유형別 사용법

emptyDir 예제

apiVersion: v1
kind: Pod
metadata:
  name: volume-test
  namespace: default
  labels:
    app: webapp
    tier: frontend
spec:
  containers:
  - name: webserver
    image: nginx:1.19
    ports:
    - name: http
      containerPort: 80
    volumeMounts:
    - name: shared-data
      mountPath: /usr/share/nginx/html
  - name: data-writer
    image: busybox:latest
    volumeMounts:
    - name: shared-data
      mountPath: /data
    command:
    - "/bin/sh"
    - "-c"
    - "while true; do echo $(date) >> /data/index.html; sleep 3; done"
  volumes:
  - name: shared-data
    emptyDir: {}

위 예제에서 두 개의 컨테이너가同一个 emptyDir Volume을 공유합니다. webserver는 웹 서비스를 제공하고, data-writer는 지정된 파일에 데이터를書き込み합니다.

hostPath 예제

apiVersion: v1
kind: Pod
metadata:
  name: hostpath-pod
  namespace: default
spec:
  containers:
  - name: app-container
    image: nginx:1.19
    volumeMounts:
    - name: local-storage
      mountPath: /usr/share/nginx/html
  volumes:
  - name: local-storage
    hostPath:
      path: "/mnt/storage"
      type: DirectoryOrCreate

hostPath Volume은 노드의 로컬 파일 시스템을 Pod에 마운트합니다. type 속성을 통해 디렉토리가 없을 때 생성 여부를 지정할 수 있습니다.

NFS Volume 예제

apiVersion: v1
kind: Pod
metadata:
  name: nfs-pod
  namespace: default
spec:
  containers:
  - name: nfs-client
    image: nginx:1.19
    volumeMounts:
    - name: nfs-volume
      mountPath: /mnt/nfs
  volumes:
  - name: nfs-volume
    nfs:
      path: "/shared/data"
      server: 192.168.1.100

NFS는 영구 저장소로 가장 널리 사용되는 방법입니다. Pod가 삭제되어도 데이터가 유지되며, 여러 Pod에서 동시에 접근할 수 있습니다.

PV와 PVC 생성实战

NFS 서버 설정

# /etc/exports 설정 예시
/data/k8s/volume1 172.16.0.0/16(rw,no_root_squash)
/data/k8s/volume2 172.16.0.0/16(rw,no_root_squash)
/data/k8s/volume3 172.16.0.0/16(rw,no_root_squash)

PV 생성

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-storage-01
  labels:
    type: nfs-storage
    capacity: 5Gi
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Recycle
  nfs:
    path: /data/k8s/volume1
    server: 192.168.1.100
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-storage-02
  labels:
    type: nfs-storage
    capacity: 10Gi
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  nfs:
    path: /data/k8s/volume2
    server: 192.168.1.100
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-storage-03
  labels:
    type: nfs-storage
    capacity: 20Gi
spec:
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteOnce
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    path: /data/k8s/volume3
    server: 192.168.1.100

PV 목록 확인:

kubectl get pv
NAME             CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS
nfs-storage-01   5Gi        RWO,RWX        Recycle          Available
nfs-storage-02   5Gi        RWO            Recycle          Available
nfs-storage-03   20Gi       RWO,RWX        Retain           Available

PVC 및 Pod 생성

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: app-claim
  namespace: default
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  selector:
    matchLabels:
      capacity: 5Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: app-pod
  namespace: default
spec:
  containers:
  - name: app-container
    image: nginx:1.19
    volumeMounts:
    - name: app-storage
      mountPath: /var/data
  volumes:
  - name: app-storage
    persistentVolumeClaim:
      claimName: app-claim

PVC와 PV 바인딩 확인:

kubectl get pvc
NAME        STATUS   VOLUME         CAPACITY   ACCESS MODES
app-claim   Bound    nfs-storage-01 5Gi        RWO

kubectl get pv
NAME             CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS
nfs-storage-01   5Gi        RWO,RWX        Recycle          Bound
nfs-storage-02   10Gi       RWO            Recycle          Available
nfs-storage-03   20Gi       RWO,RWX        Retain           Available

Released 상태의 PV 재사용

PV가 Released 상태가 되면 새로운 PVC와 바인딩할 수 없습니다. 이를 해결하려면 다음 단계를 수행합니다:

1. PVC 및 Pod 삭제

kubectl delete -f pvc-pod.yaml

PV 상태 확인:

kubectl get pv
NAME             CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM
nfs-storage-01   5Gi        RWO,RWX        Recycle          Released    default/app-claim

2. PV의 claimRef 제거

PV가 Released 상태에서 Available 상태로 돌아오지 않는 이유는 spec에 claimRef가 남아있기 때문입니다. 이를 제거해야 새로운 PVC와 바인딩할 수 있습니다.

kubectl edit pv nfs-storage-01

spec.claimRef 섹션을 삭제하고 저장합니다.

3. 상태 확인

kubectl get pv
NAME             CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS
nfs-storage-01   5Gi        RWO,RWX        Recycle          Available

4. PVC 및 Pod 재생성

kubectl apply -f pvc-pod.yaml
kubectl get pv
NAME             CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM
nfs-storage-01   5Gi        RWO,RWX        Recycle          Bound       default/app-claim

참고: 바인딩된 PV는 직접 삭제할 수 없습니다. 먼저 연결된 PVC를 삭제해야 합니다.

태그: kubernetes persistentvolume storage pvc nfs

7월 2일 04:04에 게시됨