k8s를 사용하면서 다양한 어플리케이션을 pod로 실행하게 되는데, 이때 중요한 데이터는 안전한 스토리지에 보관해야 하는 경우가 발생한다. persistent volume을 활용하면 훨씬 유연하게 volume을 매핑 및 할당 가능하다.
초기 docker의 컨테이너에서 데이터를 저장하는 공간으로 volume을 별도로 지정 가능하도록 정의한다. 다양한 volume type을 지원하며, 사실 persistent volume이 없어도 pod에서 직접 volume을 지정하면 원하는 스토리지를 쉽게 설정할 수 있다.
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: k8s.gcr.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume
emptyDir: {}
awsElasticBlockStore
azureDisk
azureFile
cephfs
cinder
configMap
csi
downwardAPI
emptyDir
fc (fibre channel)
flexVolume
flocker
gcePersistentDisk
glusterfs
hostPath
iscsi
local
nfs
persistentVolumeClaim
projected
portworxVolume
quobyte
rbd
scaleIO
secret
storageos
vsphereVolume
위와 같은 방식으로 volume을 지정하다 보면, volume이 변경 될때 마다 해당 volume을 사용하는 모든 pod의 설정을 변경하여 재 배포하야 하는 상황이 발생한다. 만약 대규모 micro service이고, 다양한 public cloud의 스토리지를 지원해야 한다면 번거로움 발생 --> 결국 설정 오류로 장애유발 가능성 높아짐
위와 같이 pod에서 다양한 volume을 직접 지정하는 방식에서 추상화된 가상의 volume 객체 (persistent volume claim)를 생성하고, 실제 volume의 유형, 사이즈 등 세부적인 스펙은 persistent volume을 연결하는 방식으로 구성한다. 즉 pod는 pvc만 연결하므로, 실제 volume이 변경되면 pvc에서 persistent volume만 다른 것으로 교체하면 된다.
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: task-pv-volume
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/data"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: task-pv-claim
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3Gi
---
apiVersion: v1
kind: Pod
metadata:
name: task-pv-pod
spec:
volumes:
- name: task-pv-storage
persistentVolumeClaim:
claimName: task-pv-claim
containers:
- name: task-pv-container
image: nginx
ports:
- containerPort: 80
name: "http-server"
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: task-pv-storage
GCEPersistentDisk
AWSElasticBlockStore
AzureFile
AzureDisk
CSI
FC (Fibre Channel)
FlexVolume
Flocker
NFS
iSCSI
RBD (Ceph Block Device)
CephFS
Cinder (OpenStack block storage)
Glusterfs
VsphereVolume
Quobyte Volumes
HostPath (Single node testing only -- local storage is not supported in any way and WILL NOT WORK in a multi-node cluster)
Portworx Volumes
ScaleIO Volumes
StorageOS
위의 persistent volume을 이용한 구성을 보면, 항상 PV가 생성되어 있어야 한다. 즉, pod가 향후 몇개가 생성 될 지 알 수 없으므로 이를 예상해서 항상 큰 사이즈의 volume을 일단 생성하고, pod가 요청 할 때마다 이를 할당하는 구조이다.
그런데 cloud 환경에서는 미리 자원을 선점할 필요가 없다. 필요할 때 자원(volume)을 바로 할당할 수 있기 때문인데, 이러한 동적인 구조에서 volume을 직접 지정하는 persistent volume이 아니라 volume에 대한 요건만 정의하고, 요청시에 이 요건에 맞는 pv를 할당하기 위해서 storage class를 사용한다.
보통 운영환경에서는 storage class의 성능을 최대로 높게 하고, 개발 환경에서는 storage calss를 느리지만 안전한 volume에 저장하도록 구성할 수 있다. 즉 운영정책에 따라 storage class를 정의만 하면, 그에 맞는 pv를 바로 생성할 수 있게 된다.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: standard
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2
reclaimPolicy: Retain
allowVolumeExpansion: true
mountOptions:
- debug
volumeBindingMode: Immediate