시작하기 전에
컨테이너의 데이터는 기본적으로 영구적이지 않습니다. 컨테이너가 종료되면 데이터도 함께 사라집니다. 이러한 한계를 극복하기 위해 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를 삭제해야 합니다.