Skip to main content

Chapter 7: Volumes & Storage

Authored by syscook.dev

What are Volumes and Storage in Kubernetes?

Volumes in Kubernetes provide persistent storage for pods and enable data sharing between containers. Storage is essential for stateful applications that need to persist data beyond the lifecycle of individual pods.

Key Concepts:

  • Volumes: Storage units attached to pods
  • Persistent Volumes (PV): Cluster-wide storage resources
  • Persistent Volume Claims (PVC): Storage requests from users
  • Storage Classes: Dynamic provisioning of storage
  • Volume Types: EmptyDir, HostPath, NFS, Cloud Storage
  • Data Persistence: Ensuring data survives pod restarts

Why Use Volumes and Storage?

1. Data Persistence

Ensure data survives pod restarts and failures.

# Example: Pod with persistent volume
apiVersion: v1
kind: Pod
metadata:
name: database-pod
namespace: production
spec:
containers:
- name: postgres
image: postgres:13
ports:
- containerPort: 5432
env:
- name: POSTGRES_DB
value: "myapp"
- name: POSTGRES_USER
value: "user"
- name: POSTGRES_PASSWORD
value: "password"
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
volumes:
- name: postgres-data
persistentVolumeClaim:
claimName: postgres-pvc

2. Data Sharing

Share data between containers in the same pod.

# Example: Pod with shared volume
apiVersion: v1
kind: Pod
metadata:
name: web-app-pod
namespace: production
spec:
containers:
- name: web-server
image: nginx:1.20
ports:
- containerPort: 80
volumeMounts:
- name: shared-data
mountPath: /usr/share/nginx/html
- name: log-processor
image: fluent/fluent-bit:1.8
volumeMounts:
- name: shared-data
mountPath: /var/log/nginx
volumes:
- name: shared-data
emptyDir: {}

How to Use Volumes and Storage?

1. Volume Types

EmptyDir Volume

# Example: EmptyDir volume for temporary storage
apiVersion: v1
kind: Pod
metadata:
name: temp-pod
spec:
containers:
- name: app
image: nginx:1.20
volumeMounts:
- name: temp-storage
mountPath: /tmp
volumes:
- name: temp-storage
emptyDir:
sizeLimit: 1Gi

HostPath Volume

# Example: HostPath volume for host file access
apiVersion: v1
kind: Pod
metadata:
name: host-pod
spec:
containers:
- name: app
image: nginx:1.20
volumeMounts:
- name: host-storage
mountPath: /host-data
volumes:
- name: host-storage
hostPath:
path: /data
type: DirectoryOrCreate

2. Persistent Volumes

Static PV

# Example: Static persistent volume
apiVersion: v1
kind: PersistentVolume
metadata:
name: postgres-pv
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
hostPath:
path: "/mnt/data/postgres"

Dynamic PV with Storage Class

# Example: Storage class for dynamic provisioning
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: ebs.csi.aws.com
parameters:
type: gp3
iops: "3000"
throughput: "125"
encrypted: "true"
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
reclaimPolicy: Delete

3. Persistent Volume Claims

Basic PVC

# Example: Basic persistent volume claim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-pvc
namespace: production
spec:
storageClassName: fast-ssd
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi

PVC with Specific Requirements

# Example: PVC with specific requirements
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: database-pvc
namespace: production
spec:
storageClassName: fast-ssd
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
selector:
matchLabels:
type: database

Practical Examples

1. Database with Persistent Storage

Step 1: Create Storage Class

#!/bin/bash
# create-storage-class.sh

kubectl apply -f - <<EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: ebs.csi.aws.com
parameters:
type: gp3
iops: "3000"
throughput: "125"
encrypted: "true"
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
reclaimPolicy: Delete
EOF

echo "Storage class created successfully!"

Step 2: Create PVC

#!/bin/bash
# create-pvc.sh

kubectl apply -f - <<EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-pvc
namespace: production
spec:
storageClassName: fast-ssd
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
EOF

echo "PVC created successfully!"

Step 3: Create Database Deployment

#!/bin/bash
# create-database-deployment.sh

kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres-deployment
namespace: production
spec:
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:13
ports:
- containerPort: 5432
env:
- name: POSTGRES_DB
value: "myapp"
- name: POSTGRES_USER
value: "user"
- name: POSTGRES_PASSWORD
value: "password"
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "1000m"
volumes:
- name: postgres-data
persistentVolumeClaim:
claimName: postgres-pvc
EOF

echo "Database deployment created successfully!"

Best Practices

1. Storage Class Configuration

# Good: Proper storage class configuration
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: ebs.csi.aws.com
parameters:
type: gp3
iops: "3000"
throughput: "125"
encrypted: "true"
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
reclaimPolicy: Delete

2. PVC Configuration

# Good: Proper PVC configuration
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: database-pvc
namespace: production
spec:
storageClassName: fast-ssd
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi

3. Volume Mount Configuration

# Good: Proper volume mount configuration
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
subPath: postgres

Common Pitfalls and Solutions

1. Storage Class Issues

# ❌ Problem: No storage class available
# Error: no storage class is default

# ✅ Solution: Set default storage class
kubectl patch storageclass fast-ssd -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

2. PVC Binding Issues

# ❌ Problem: PVC not binding
# Error: no persistent volumes available

# ✅ Solution: Check storage class and node affinity
kubectl get storageclass
kubectl get pv
kubectl describe pvc postgres-pvc

3. Volume Mount Issues

# ❌ Problem: Volume mount fails
# Error: path not found

# ✅ Solution: Check mount path and permissions
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
subPath: postgres

Conclusion

Volumes and storage are essential for stateful applications in Kubernetes. By understanding:

  • What volumes and storage are and their purposes
  • Why they're important for data persistence and sharing
  • How to use them effectively in applications

You can create robust applications that maintain data across pod restarts and failures. Proper configuration ensures that your applications have reliable storage for their data needs.

Next Steps

  • Practice with different storage scenarios
  • Learn about application deployment
  • Move on to Chapter 8: Application Deployment

This tutorial is part of the Kubernetes Mastery series by syscook.dev