Chapter 7: Persistent Storage – Managing Stateful Applications

Introduction to Persistent Storage

In Kubernetes, Persistent Storage is essential for stateful applications that require data persistence beyond the lifecycle of Pods. Kubernetes provides a robust mechanism for managing storage using PersistentVolumes (PVs) and PersistentVolumeClaims (PVCs).


Why Persistent Storage?

  1. Ephemeral Nature of Pods: Pod storage is temporary; Persistent Storage ensures data continuity.
  2. Stateful Applications: Databases, content management systems, and analytics tools need persistent storage.
  3. Scalability: Easily provision storage across multiple nodes.

Key Kubernetes Storage Concepts

  1. Volumes: Attach storage to a Pod’s lifecycle.
  2. PersistentVolume (PV): A cluster-wide resource representing physical storage.
  3. PersistentVolumeClaim (PVC): A request for storage by a user or application.
  4. StorageClass: Defines the storage type, provisioning mechanism, and parameters.

Step-by-Step Implementation

Step 1: Create a PersistentVolume (PV)

PersistentVolume YAML

Save this as persistent-volume.yaml:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-example
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  hostPath:
    path: "/mnt/data"

Explanation:

  • capacity: Specifies storage size.
  • accessModes:
    • ReadWriteOnce: Single node read/write access.
    • ReadOnlyMany: Multiple nodes read-only access.
    • ReadWriteMany: Multiple nodes read/write access.
  • hostPath: Points to a directory on the node.

Apply the PV:

kubectl apply -f persistent-volume.yaml

Check the PV:

kubectl get pv

Step 2: Create a PersistentVolumeClaim (PVC)

PersistentVolumeClaim YAML

Save this as persistent-volume-claim.yaml:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-example
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 500Mi

Explanation:

  • accessModes: Matches the PV access modes.
  • resources.requests.storage: The requested storage size.

Apply the PVC:

kubectl apply -f persistent-volume-claim.yaml

Check the PVC:

kubectl get pvc

Step 3: Use the PVC in a Pod

Pod YAML

Save this as pod-with-pvc.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: pod-with-pvc
spec:
  containers:
  - name: app-container
    image: nginx
    volumeMounts:
    - mountPath: "/usr/share/nginx/html"
      name: storage-volume
  volumes:
  - name: storage-volume
    persistentVolumeClaim:
      claimName: pvc-example

Apply the Pod:

kubectl apply -f pod-with-pvc.yaml

Verify the Pod is running:

kubectl get pods

Access the mounted volume inside the Pod:

kubectl exec pod-with-pvc -- ls /usr/share/nginx/html

Step 4: Dynamic Provisioning with StorageClass

Create a StorageClass

Save this as storage-class.yaml:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: dynamic-storage
provisioner: kubernetes.io/aws-ebs  # Replace based on your cloud provider
parameters:
  type: gp2

Apply the StorageClass:

kubectl apply -f storage-class.yaml

Update PVC to Use StorageClass

Save this as pvc-with-storage-class.yaml:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-dynamic
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: dynamic-storage

Apply the PVC:

kubectl apply -f pvc-with-storage-class.yaml

Verify the dynamically provisioned PV:

kubectl get pv

Step 5: StatefulSets for Stateful Applications

StatefulSet Example

Save this as statefulset.yaml:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "password"
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: "/var/lib/mysql"
  volumeClaimTemplates:
  - metadata:
      name: mysql-persistent-storage
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 2Gi

Apply the StatefulSet:

kubectl apply -f statefulset.yaml

Verify StatefulSet and PVCs:

kubectl get statefulset
kubectl get pvc

Monitoring Persistent Storage

Check PV and PVC Details

kubectl describe pv pv-example
kubectl describe pvc pvc-example

Check Mounted Volumes in Pods

kubectl exec pod-with-pvc -- df -h

Best Practices

  1. Use StorageClasses: Automate storage provisioning using dynamic provisioning.
  2. Understand Access Modes: Choose the correct access mode based on workload needs.
  3. Set Retain Policies: Use Retain, Recycle, or Delete policies wisely for PVs.
  4. Monitor Storage Usage: Prevent Pods from exhausting allocated storage.

Troubleshooting Persistent Storage

  1. PVC Pending:
    • Check PV availability and access modes.
    • Ensure the storage request matches available PVs.
kubectl describe pvc pvc-example

Volume Not Mounting:

  • Inspect Pod logs and events.
kubectl describe pod pod-with-pvc
kubectl logs pod-with-pvc
  1. Dynamic Provisioning Fails:
    • Verify the StorageClass parameters and provisioner.
    • Check cloud provider configuration (e.g., IAM roles for AWS).

Conclusion

In this chapter, you learned how to:

  1. Use PersistentVolumes and PersistentVolumeClaims for stateful applications.
  2. Dynamically provision storage using StorageClasses.
  3. Leverage StatefulSets for managing applications like databases.

Leave a Reply