Skip to main content

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
  • kubectl configured 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

  1. Log in to the E2E Cloud Dashboard
  2. Navigate to Kubernetes
  3. Go to Persistent Volumes
  4. Click Create PV
  5. Select required size (example: 10 Gi)
  6. 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 Bound state
  • One PVC is in Bound state

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. Run kubectl get pvc to 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

  1. Insert data:
USE e2edb;
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50)
);
INSERT INTO users VALUES (1, 'test-user');
  1. Delete Pod:
kubectl delete pod mysql-static
  1. Recreate Pod (apply the same manifest again).

  2. 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