Kubernetes Persistent Storage on E2E
1. Introduction
Stateful workloads require storage that persists independently of Pod lifecycles. E2E Kubernetes supports persistent storage using Kubernetes Persistent Volumes (PV) and Persistent Volume Claims (PVC).
This document explains how to configure and use persistent storage from scratch on an E2E Kubernetes cluster, including:
- E2E-specific storage behavior
- Static provisioning
- Dynamic provisioning
- Deploying a sample stateful MySQL application
- Demonstrating why PV and PVC are required
For SFS-based persistent storage (shared filesystem), see Persistent Volume using SFS.
2. Prerequisites
Before starting, ensure the following prerequisites are met:
- An active E2E Kubernetes cluster
- At least one worker node in Ready state
- Access to the E2E Cloud Dashboard
kubectlconfigured with cluster access
Verify cluster access:
kubectl get nodes
3. E2E Storage Behavior (Important)
Default StorageClass Behavior in E2E Kubernetes
By default, no StorageClass is available in an E2E Kubernetes cluster.
At least one Persistent Volume (PV) must be created from the E2E Cloud Dashboard to expose and enable the StorageClass in the cluster.
This step is mandatory before using:
- Static provisioning
- Dynamic provisioning
4. Enable StorageClass in E2E Kubernetes
4.1 Create a Persistent Volume from E2E UI
- Log in to the E2E Cloud Dashboard
- Navigate to Kubernetes
- Go to Persistent Volumes
- Click Create PV
- Select required size (example: 10 Gi)
- Create the PV
The Persistent Volume is created successfully.
4.2 Verify Storage Resources in the Cluster
Once the PV is created from the UI:
- A StorageClass (example:
csi-rbd-sc) is automatically provisioned - A PersistentVolume (PV) is created
- A PersistentVolumeClaim (PVC) is automatically created and bound
kubectl get storageclass
kubectl get pv
kubectl get pvc
Important (E2E Specific): In an E2E Kubernetes cluster, at least one PV must be created from the UI to enable the StorageClass. This is mandatory for both static and dynamic provisioning.
5. Storage Provisioning Models
5.1 Static Provisioning
- Storage is created manually from the E2E Cloud Dashboard
- PV exists before the application is deployed
- PVC is pre-bound
- Recommended for production workloads
5.2 Dynamic Provisioning
- Storage is created automatically when a PVC is created
- Uses a StorageClass
- Recommended for development and testing
6. Verify Persistent Volumes in Kubernetes
kubectl get pv
kubectl get pvc
Expected Output:
- At least one StorageClass exists
- One PV is in
Boundstate - One PVC is in
Boundstate
This PVC will be reused for static volume testing.
7. Database WITHOUT Persistent Volume (Data Loss Scenario)
This section demonstrates why PV and PVC are required.
7.1 Deploy MySQL WITHOUT a Volume
apiVersion: v1
kind: Pod
metadata:
name: test-e2e
namespace: test-mysql
spec:
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
value: e2e@123
- name: MYSQL_DATABASE
value: e2etestdb
Apply the manifest:
kubectl apply -f pod.yaml -n test-mysql
kubectl get pods -n test-mysql
7.2 Insert Data into MySQL
kubectl exec -it -n test-mysql test-e2e -- mysql -u root -p
USE e2etestdb;
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50)
);
INSERT INTO users VALUES (1, 'test-user');
EXIT;
7.3 Delete and Recreate the Pod
kubectl delete pod test-e2e -n test-mysql
Recreate the Pod and check the data again.
Result: Data is LOST
Conclusion (Without PV/PVC)
- Pod filesystem is ephemeral
- Data stored inside containers is not persistent
- Databases must not rely on container filesystem storage
8. Persistent Storage with PV & PVC
In the previous section, we confirmed that data stored inside a Pod is lost when the Pod is deleted. This section demonstrates how Persistent Volumes (PV) and Persistent Volume Claims (PVC) solve this problem on E2E Kubernetes.
9. Static Provisioning: MySQL with PV & PVC
9.1 Architecture
MySQL Pod → PVC (pre-created) → PV (E2E UI) → E2E Storage
9.2 Deploy MySQL Using Existing PVC
apiVersion: v1
kind: Pod
metadata:
name: mysql-static
spec:
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
value: e2e@123
- name: MYSQL_DATABASE
value: e2edb
volumeMounts:
- name: mysql-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-storage
persistentVolumeClaim:
claimName: <existing-pvc-name>
Replace
<existing-pvc-name>with the actual PVC name from your cluster. Runkubectl get pvcto find the available PVC name.
Apply the manifest:
kubectl apply -f e2e-test-pv.yaml
kubectl get pods
9.3 Insert Data into MySQL
Login to the Pod:
kubectl exec -it mysql-static -- mysql -u root -p
9.4 Verify Data Persistence
- Insert data:
USE e2edb;
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50)
);
INSERT INTO users VALUES (1, 'test-user');
- Delete Pod:
kubectl delete pod mysql-static
-
Recreate Pod (apply the same manifest again).
-
Query data again:
mysql> select * from users;
Data is retained.
10. Dynamic Provisioning: MySQL with StorageClass
10.1 Architecture
MySQL Pod → PVC → StorageClass → Auto-created PV → E2E Storage
10.2 Create Namespace
kubectl create namespace mysql-dynamic
10.3 Create PVC (Dynamic)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-dynamic-pvc
namespace: mysql-dynamic
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: csi-rbd-sc
Apply the manifest:
kubectl apply -f pvc.yaml
kubectl get pvc -n mysql-dynamic
The PVC is created.
10.4 Deploy MySQL Using Dynamic PVC
apiVersion: v1
kind: Pod
metadata:
name: mysql-dynamic
namespace: mysql-dynamic
spec:
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
value: e2e@123
- name: MYSQL_DATABASE
value: e2edb
volumeMounts:
- name: mysql-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-storage
persistentVolumeClaim:
claimName: mysql-dynamic-pvc
Apply the manifest:
kubectl apply -f mysql-dynamic.yaml
kubectl get pods -n mysql-dynamic
Once deployed:
- A new PV is created automatically
- Data persists after Pod recreation