Kubernetes Volumes
Tags: volumes, configmaps, secrets, persistant
Published: 2023-11-19 17:18:54

## Volumes
Volumes are needed to store data within a container or share data among other containers.
All volumes requested by a Pod must be mounted _before_ the containers within the Pod are started. This applies also to secrets and configmaps.

### Shared Volume
Below you can find a sample of how to create a shared volume.
But be aware that one container can overwrite the data that from the other container.
You can use locking or versioning to overcome this topic.

```
   containers:
   - name: firstcontainer
     image: busybox
     volumeMounts:
     - mountPath: /firstdir
       name: sharevol
   - name: secondcontainer
     image: busybox
     volumeMounts:
     - mountPath: /seconddir
       name: sharevol
   volumes:
   - name: sharevol
     emptyDir: {}  
```


`$ kubectl exec -ti example -c secondcontainer -- touch /seconddir/bla`

`$ kubectl exec -ti example -c firstcontainer -- ls -l /firstdir`

### Persistent Volume - PV
This is a storage abstraction used to keep data even if the Pods is killed. In the Pods you define a volume of that type.
`kubectl get pv`

Sample of a PV with hostPath Type
```
kind: PersistentVolume
apiVersion: v1
metadata:
name: 10Gpv01
labels:
type: local
spec:
capacity:
        storage: 10Gi
    accessModes:
        - ReadWriteOnce
    hostPath:
        path: "/somepath/data01"
```

### Persistent Volume Claim - PVC

With the PVC volumes can be accessed by multiple pods and allow state persistency. 
The cluster attaches the Persistent Volume. 

There is no concurrency checking, so data corruption is probable unless locking takes place outside. 

There are 3 access modes for the PVC:
1. RWO - ReadWriteOnce by a single node
2. ROX - ReadOnlyMany by multiple nodes
3. RWX - ReadWriteMany by many nodes

`kubectl get pvc`

#### Phases to persistent storage
1. Provisioning: Can be done in advance, ie resources from a cloud provider
2. Binding: Once a watch loop on master notices a PVC it requests the access.
3. Using: The volume is mounted to the Pod and can now be used.
4. Releasing: When the pod is down, the PVC is deleted. The resident data remains depending on the `persitenVolumReclaimPolicy`
5. Reclaiming: 
You have three options: Retain, Delete, Recycle 


#### Empty Dir
The kubelet creates an `emptyDir`. It will create the directory in the container but not mount any storage. The data written to that storage is not persistent, as it will be deleted when the Pod is deleted.

```
apiVersion: v1
kind: Pod
metadata:
    name: sample
    namespace: default
spec:
    containers:
    - image: sample
      name: sample
      command:
        - sleep
        - "3600"
      volumeMounts:
      - mountPath: /sample-mount
        name: sample-volume
    volumes:
    - name: sample-volume
            emptyDir: {}
```


#### Other Volume types
##### GCEpersistenDisk and awsElsaticBlockStore
You can mount your GCE or your EBS into your Pods.

##### hostPath
This mounts a resource from the host node filesystem. The resource must be already in advance in order to be used.
- DirectoryOrCreate
- FileOrCreate

##### and many more 
**NFS** - Network File System
**iSCSI** - Internet Small Computer System Interface
**RBD** (RADOS Block Device) - RBD is a block storage device that runs on top of the Ceph distributed storage system. It allows you to create block devices that can be mounted and used like a regular disk. RBD is often used in virtualization environments, providing storage for virtual machines.
**CephFS** - CephFS is a distributed file system built on top of the Ceph storage system.
**GlusterFS** - open-source, distributed file system that can scale out to petabytes of storage. It works by aggregating various storage resources across nodes into a single, global namespace. 

### Dynamic Provisioning
With the kind StorageClass, a user can request a claim, which the API Server fills via auto-provisioning. Common choices for dynamic storage are AWS and GCE.

Sample for gce:
```
apiVersion: storage.k8s.io/v1        
kind: StorageClass
metadata:
  name: you-name-it                        
provisioner: kubernetes.io/gce-pd
parameters:
  type: pd-ssd 
```


### ConfigMaps
This kind of storage is used to store sensitive data, that does not need to be encoded, but should not be stored within the application itself. 
Using configmaps we can decouple the container image from the configuration artifacts.
If configmaps are marked as "optional" they don't need to be mounted before a pod wants to use them.

They can be consumed in various ways:
- Pod environmental variables from single or multiple ConfigMaps
- Use ConfigMap values in Pod commands
- Populate Volume from ConfigMap
- Add ConfigMap data to a specific path in Volume
- Set file names and access mode in Volume from ConfigMap data
- Can be used by system components and controllers.

Create a Configmap from literal:
`kubectl create cm yourcm --from-literal yoursecret=topsecret`

Create a Configmap from a file:
`kubectl -f your-cm.yaml create`

Sample ConfigMap:
```
apiVersion: v1
data:
  yoursecret: topsecret
  level: "3"
kind: ConfigMap
metadata:
  name: yourcm
```
read the configmap
`kubectl get configmap yourcm -o yaml`




### Secrets
This kind of storage is used to store sensitive data, that needs to be encoded. 

A Secret in Kubernetes is base64-encoded by default.
If you want to encrypt secrets, you have to create a **EncryptionConfiguration**.
There is no limit to the number of secrets, but there is a 1MB limit to their size.
Secrets are stored in the tmpfs storage on the host node and are only sent to the host running Pod.



#### Secret as an environmental variable
`kubectl get secrets`
`kubectl create secret generic --help`
`kubectl create secret generic mysecret --from-literal=password=supersecret`

```
spec:
     containers:
     -image: yourimage
      name: yourcontainername
      env:
      - name: ROOT_PASSWORD
        valueFrom: 
         secretKeyRef:
           name: yoursecret
           key: password
```

#### Mounting secrets as volumes
```
spec:
    containers:
    - image: busybox
      name: busy
      command:
        - sleep
        - "3600"
      volumeMounts:
      - mountPath: /mysqlpassword
        name: mysql
    volumes:
    - name: mysql
      secret:
        secretName: mysql
```

Verify that the secret is available in thte container:
`kubectl exec -ti busybox -- cat /mysqlpassword/password`



Further reading:
https://trainingportal.linuxfoundation.org/learn/course/kubernetes-for-developers-lfd259/
Volumes on Kubernetes: https://kubernetes.io/docs/concepts/storage/volumes/
Ceph: https://ubuntu.com/ceph/what-is-ceph