Volumes in Kubernetes
Volume management in Kubernetes requires considering what type of volume you want to set up and how the volume will be created/provided. I will focus mostly on persistent volumes, but also touch on at least hostpath volumes.
What are Volumes
Volumes are storage that persists as long as a pod exists, and is available to all containers in that pod. It is deleted when the pod is deleted. these are ephemeral volumes that usually will use local or host storage since they are not indicated to last beyond the lifetime of a pod. hostpath, local, emptydir are common types for this.
PersistentVolumes
A PersistentVolume (PV) is a piece of storage like a Volume, but with a lifecycle independent of any pod using the PV.
They can be created manually using a storageClass, PVC
A user can create PV directly by creating a PersistentVolumeClaim (PVC) configured with the StorageClass. The PV is created after the PVC is fulfilled by the storageclass provisioner, so think of the PVC as a request for storage and the PV as fulfillment.
or automatically (dynamically), also with storageClass
If they are created by the system through a chart/deploy/replicaset using the StorageClass and provisioner then it is considered automatic/dynamic. Resources that need storage will use the default StorageClass if one is set without any prompting.
Storage volume providers/provisioners
These will be used mostly with persistent volumes, though they could also be used for regular volumes. If the volume does not need to be persistent however then they don’t provide any advantage and something like a hostpath should be fine.
Cloud storage provisioners
Cloud storage drivers provide storage completely separate from local container or host from a cloud service. GKE, Amazon, DigitalOcean, Azure are some possible providers, there are others.
Storage classes define resources to create storage -
Storageclass defines a provisioner which does the actual storage creation and handling. The storageClassName is used to request storage from that provisioner.
The persistentVolumeReclaimPolicy controls how PV deletion is handled
PVs stick around until they are deleted. The persistentVolumeReclaimPolicy: determines exactly what deleting them means however.
Delete - When the PVC is deleted, the volume it is associated with is also deleted.
Retain - When PVC is deleted, the volume is kept, so the data is preserved and it could be used elsewhere.
Creating PV using PersistentVolumeClaim
This creates a new PersistentVolume from the configured storage class. This example is digitalocean, but it should just be a different storageClassName for other providers.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: docsi-pvc-test
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: do-block-storage
The reclaim policy is not configurable in a PVC
The storageClass determines the default policy, so a modified copy would be needed to change the default.
Patching a pv so the volume reclaim policy it retain, not delete -
If I need a pv to have a retain policy, I just patch it.
kubectl patch pv pvc-d8f04adb-c46b-11e9-af75-6e9f2a8237eb -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'
Example of mounting a persistent volume in a deploy -
In this example the volume was created separately.
This is under spec.template.spec.containers -
volumeMounts:
- mountPath: /data/example
name: persistent-psdata
And this is under spec.template.spec.volumes -
Note that the name is local to the deployment, but the claimName must match the pvc you want to attach.
- name: persistent-example
persistentVolumeClaim:
claimName: docsi-pvc-test
Deleting a pvc -
Have to make sure the pvc is not protected; if first command indicates pvc-protection, it is and you need to remove that protection.
kubectl describe pvc csi-pvc-test | grep Finalizers
This command can then be used to remove protection.
kubectl patch pvc csi-pvc-test -p '{"metadata":{"finalizers": []}}' --type=merge
Then delete it using kubectl delete -
kubectl delete pvc csi-pvc-test
Example using a hostpath volume
A couple quick examples to access files relevant to a specific host. This gives a container access to a socket on the host, and directory to write data to that will be host specific. These are not persistent, but in these cases that works fine.
Set up hostPaths for a directory, file -
- name: dockersock
hostPath:
path: /var/run/docker.sock
- name: data
hostPath:
path: /var/lib/filebeat-data
type: DirectoryOrCreate
Then mount them to be used directly in the containers -
volumeMounts:
- name: data
mountPath: /usr/share/filebeat/data
- name: dockersock
mountPath: "/var/run/docker.sock"
Volumesnapshot -
Point in time image of volumes.
Can use k8s objects or cloud provider tool like doctl -
The object type is VolumeSnapshot. With digitalocean using doctl tool it is:
doctl compute volume snapshot <volume-id> --snapshot-name "Give-it-a-name"
Set up the volumesnapshot
The pvc name is used to select the volume for the snapshot. Make sure to configure the namespace (if you are using them) or the pvc will not be found.
snapshot.yml:
apiVersion: snapshot.storage.k8s.io/v1alpha1
kind: VolumeSnapshot
metadata:
name: csi-do-test-snapshot
namespace: test
spec:
source:
name: docsi-pvc-test
namespace: test
kind: PersistentVolumeClaim
Do the snapshot -
kubectl apply -f snapshot.yml
Restore from the snapshot
A pvc is created using the snapshot as a source. Size needs to be same or greater than original.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mongodb-master-restore
namespace: test
spec:
dataSource:
name: csi-do-test-snapshot
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
Reconnecting a persistent volume that was retained
This applies to a persistent volume that had a retain policy. It only applied when I deleted a cluster but wanted to use the persistent volume in another cluster.
Reclaim the volume
In order to reclaim the volume, I needed to create a PersistentVolume, but with some atypical configuration. This is digitalocean specific. The volumehandle was needed to get the persistent volume to attach the specific volume you are targeting for re-use.
I found this value using doctl command:
doctl compute volume list
Then create the PersistentVolume:
kind: PersistentVolume
apiVersion: v1
metadata:
name: pv-test-retrieve
annotations:
# fake it by indicating this is provisioned dynamically
pv.kubernetes.io/provisioned-by: dobs.csi.digitalocean.com
spec:
storageClassName: do-block-storage
persistentVolumeReclaimPolicy: Retain
capacity:
storage: 2Gi
accessModes:
- ReadWriteOnce
csi:
driver: dobs.csi.digitalocean.com
fsType: ext4
volumeHandle: d9745c38-c46b-11e9-8b09-0a58ac14e056
volumeAttributes:
com.digitalocean.csi/noformat: "true"
Then create a PVC that points to the PV you just set up
In this case the creation order is backward, set up the PV, then do a standard PVC that targets the name you gave to the PV, pv-test-retreive in this case.