Deploying Stateful Applications Using vCluster and Persistent Volume Integration

Tania Duggal
7 Minute Read

Virtual clusters are lightweight, isolated environments to run Kubernetes clusters within an existing host cluster. It gives the flexibility to manage Kubernetes workloads without the overhead of managing separate clusters. This way running k8s clusters is useful in multi-tenant environments and in workflows where isolation is required for different teams or applications.

However, when dealing with stateful applications (like databases), it becomes important to manage persistent storage. Stateful applications depend on stable storage for data persistence, and without proper configuration, their state may be lost upon pod restarts. In this tutorial, we will learn about deploying stateful applications within a virtual cluster, persistent volume (PV) integration and configuration.

Understanding vCluster and Stateful Applications

A virtual cluster is a Kubernetes cluster running inside another Kubernetes cluster (called the host cluster). Traditional Kubernetes clusters run independently, but virtual clusters work differently—they share resources from the main (host) cluster while still providing their own separate environments. This isolation makes them suitable for having multiple Kubernetes clusters given for each team or environment while not creating separate clusters. Virtual Cluster makes you feel like you have an independent cluster, but you're still using the host cluster’s resources.

Running stateful applications in Kubernetes commonly involves configuring persistent storage and ensuring data is not lost when pods are rescheduled. In a virtual cluster setup, you get the flexibility of an isolated environment with the ease of using the underlying host cluster's storage resources.

Prerequisites

Before starting this tutorial, make sure you have the following tools and access:

  1. A Kubernetes host cluster (v1.16+): A running Kubernetes cluster where the virtual cluster will be created. I am using Kind for this tutorial.
  2. kubectl: A command-line tool to interact with Kubernetes clusters.
  3. Helm: A package manager for Kubernetes, required for managing Kubernetes applications. Helm v3.10.0+ is preferred.
  4. Administrative Access to the K8s Cluster: You need permissions to create resources like namespaces, deployments, and storage classes in your host cluster.

Creating a Virtual Cluster

First, you have to create a virtual cluster on the host machine:

1. Install vCluster CLI

To create and manage virtual clusters, you need to install the vcluster CLI. Whatever OS you are working with (this example uses Linux), download instructions are in the docs.

# Download vcluster CLI
curl -L -o vcluster "<https://github.com/loft-sh/vcluster/releases/latest/download/vcluster-linux-amd64>" && sudo install -c -m 0755 vcluster /usr/local/bin && rm -f vcluster

# Verify installation
vcluster --version

Once your installation is successful, you should have a similar output:


2. Deploy a Virtual Cluster:

Let’s first allow the vcluster to access storage classes from the host cluster. You have created a values.yamlfile with the following configuration:

controlPlane:
 distro:
   k3s:
     enabled: true
 statefulSet:
   scheduling:
     podManagementPolicy: OrderedReady
sync:
 toHost:
   persistentVolumes:
     enabled: true
   storageClasses:
     enabled: true

To deploy a virtual cluster with the values.yaml, use the following command:

vcluster create my-statefulvcluster --namespace vcluster-state -f values.yaml

After successful creation, you should have a similar output:


This command creates a new namespace (vcluster-state) in your current Kubernetes cluster and deploys a virtual cluster named my-statefulvcluster.

3. Connecting to your Virtual Cluster:

Once the virtual cluster is created, you will automatically be in the virtual cluster context. If not, use the following command to connect manually:

vcluster connect my-statefulvcluster -n vcluster-state

After connecting, you’re now within the virtual cluster my-statefulvcluster, which is completely isolated from the main Kubernetes cluster.

Integrating Persistent Volumes with vCluster

Persistent volumes (PVs) and persistent volume claims (PVCs) are components in Kubernetes used to manage storage. PV is a storage resource in a Kubernetes cluster that represents a physical storage device. It could be a cloud disk, NFS share, or local storage.

PVC is a request for storage made by a pod. It specifies the size, access modes, and storage class. In a Kubernetes cluster, when a pod requests storage, it uses PVCs, which get bound to PVs. Let’s follow the steps to integrate PV with your virtual cluster:

1. Setting Up Storage Classes in the Host Cluster

A StorageClass provides a way to define the provisioner and parameters for the storage used in your cluster. Your host cluster may already have a standard StorageClass, but we’ll verify and configure it to be used in the virtual cluster.

# Verify available StorageClasses in the host cluster
kubectl get storageclass

Here, we have a default standard StorageClass available, but you can create one using storage tools like Longhorn, Ceph, or OpenEBS, depending on your storage needs.


2. Setting Up PV Provisioning in vCluster

In the virtual cluster, we need to set up a StorageClass that maps to the host cluster's storage provisioner. This allows the virtual cluster to access storage resources from the host cluster.

cat <<EOF | kubectl apply -f -
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: standard
provisioner: rancher.io/local-path # Use your host cluster's provisioner
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: false
EOF

This StorageClass will use the rancher.io/local-path provisioner, but it should match the storage provisioner available in your host cluster.


3. Demonstrating PV and PVC Mapping to the Host Cluster

Now, we can create a PersistentVolumeClaim (PVC) in the virtual cluster that will bind to the available PersistentVolume (PV) in the host cluster.

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
  namespace: default
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: standard
EOF

Deploying a Stateful Application in vCluster

We'll deploy MySQL as our stateful application. StatefulSets in Kubernetes are designed for managing stateful applications, ensuring that each pod gets a unique identifier and persistent storage.

Make sure you are connected to the vCluster CLI before deploying the application.

1. Deploy the Application in the vCluster

We will now deploy MySQL as a StatefulSet in the virtual cluster, using the PVC we created for persistent storage.

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
  namespace: default
spec:
  serviceName: mysql
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:latest
        ports:
        - containerPort: 3306
          name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "password123"
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
        resources:
          requests:
            memory: "1Gi"
            cpu: "500m"
          limits:
            memory: "2Gi"
            cpu: "1000m"
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pvc
EOF

After this, check now the status of the PVC that you have created above, it's in the Bound status which means it is successfully linked to the PV and ready to be used by a pod.

kubectl get pvc mysql-pvc

2. Testing Data Persistence Across Pod Restarts

To verify that data is persisted across pod restarts, we can interact with MySQL, insert some data, and then delete the pod to see if the data is retained.

a. Verify Objects in Host Cluster:

Before proceeding, confirm the objects in the host cluster:

kubectl get pods -n vcluster-state

You can see above, you have enabled the persistent volume sync, vCluster created the persistent volumes that are created in vCluster itself in the host cluster.


b. Access your MySQL pod:

kubectl exec -it mysql-0 -- mysql -uroot -ppassword123

b. Create test database and data:

CREATE DATABASE test;
USE test;
CREATE TABLE example (id INT, name VARCHAR(50));
INSERT INTO example VALUES (1, 'test-data');
exit


c. Delete the pod:

kubectl delete pod mysql-0

d. Wait for the new pod to be ready:

kubectl wait --for=condition=ready pod/mysql-0

Since this is a StatefulSet, the pod will automatically recreate.

e. Verify data persistence:

kubectl exec -it mysql-0 -- mysql -uroot -ppassword123 -e "USE test; SELECT * FROM example;"

Your data (test-data) is still present after the pod restart, indicating successful data persistence.

Final Thoughts

Following this tutorial, you’ve learned how to deploy a stateful application in a vCluster, integrating persistent storage from the host cluster for data persistence. Virtual clusters excel at running stateful applications by providing isolated Kubernetes environments while efficiently sharing the host cluster's storage resources—combining the benefits of multi-tenancy with simplified storage management.

This makes clusters an ideal solution for teams needing to run multiple isolated stateful workloads without the overhead of managing separate physical clusters.

Ready to try vCluster? Explore vCluster documentation, join the vCluster Slack community, and start experimenting with the flexibility of virtual clusters today!

Sign up for our newsletter

Be the first to know about new features, announcements and industry insights.