New to KubeDB? Please start here.

Weaviate StorageClass Migration

This guide will show you how to use the KubeDB Ops Manager to migrate a Weaviate cluster from one StorageClass to another.

Before You Begin

  • At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster.

  • Install KubeDB in your cluster following the steps here.

  • You need at least two StorageClasses in your cluster — the one the database currently runs on, and the one you want to migrate to. Verify with:

    $ kubectl get storageclass
    NAME                   PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
    local-path (default)   rancher.io/local-path   Delete          WaitForFirstConsumer   false                  38h
    longhorn               driver.longhorn.io      Delete          Immediate              true                   30m
    
  • You should be familiar with the following KubeDB concepts:

To keep things isolated, this tutorial uses a separate namespace called demo throughout this tutorial.

$ kubectl create ns demo
namespace/demo created

Note: YAML files used in this tutorial are stored in docs/examples/weaviate/storage-migration folder in GitHub repository kubedb/docs.

Deploy Weaviate

In this section, we are going to deploy a Weaviate cluster on the longhorn StorageClass. We will migrate it to local-path in the next step.

apiVersion: kubedb.com/v1alpha2
kind: Weaviate
metadata:
  name: weaviate-sample
  namespace: demo
spec:
  version: 1.33.1
  replicas: 2
  storageType: Durable
  storage:
    storageClassName: longhorn
    accessModes:
      - ReadWriteOnce
    resources:
      requests:
        storage: 3Gi
  deletionPolicy: WipeOut

Let’s create the Weaviate CR and wait for it to become Ready. Then check the current StorageClass of the PVCs:

$ kubectl get pvc -n demo -o custom-columns=NAME:.metadata.name,SC:.spec.storageClassName,SIZE:.status.capacity.storage
NAME                     SC         SIZE
data-weaviate-sample-0   longhorn   3Gi
data-weaviate-sample-1   longhorn   3Gi

The cluster is currently running on the longhorn StorageClass.

Apply StorageMigration OpsRequest

Now, we are going to migrate the cluster from longhorn to local-path.

apiVersion: ops.kubedb.com/v1alpha1
kind: WeaviateOpsRequest
metadata:
  name: storage-migration
  namespace: demo
spec:
  type: StorageMigration
  databaseRef:
    name: weaviate-sample
  timeout: 10m
  migration:
    storageClassName: local-path
    oldPVReclaimPolicy: Delete
  • spec.type specifies that this is a StorageMigration operation.
  • spec.migration.storageClassName specifies the target StorageClass. It must be different from the current one.
  • spec.migration.oldPVReclaimPolicy specifies the reclaim policy applied to the old PersistentVolumes after migration (here, Delete).

Let’s create the WeaviateOpsRequest CR:

$ kubectl create -f https://github.com/kubedb/docs/raw/v2026.7.10/docs/examples/weaviate/storage-migration/ops-request.yaml
weaviateopsrequest.ops.kubedb.com/storage-migration created

For each node, the Ops Manager provisions a new PVC on the target StorageClass, runs a migrator job to copy the data, deletes the old PVC, and re-points the node at the new volume.

$ kubectl get weaviateopsrequest -n demo storage-migration
NAME                TYPE               STATUS       AGE
storage-migration   StorageMigration   Successful   6m

Let’s look at the (abbreviated) status.conditions of the WeaviateOpsRequest:

$ kubectl get weaviateopsrequest -n demo storage-migration -o yaml
...
status:
  conditions:
  - message: StorageClass migration is in progress
    reason: Running
    status: "True"
    type: Running
  - message: get storage class; ConditionStatus:True
    status: "True"
    type: GetStorageClass
  - message: 'p v c created; ConditionStatus:True; PodName:data-migrate-weaviate-sample-0'
    status: "True"
    type: PVCCreated--data-migrate-weaviate-sample-0
  - message: 'job created; ConditionStatus:True; PodName:migrator-weaviate-sample-0'
    status: "True"
    type: JobCreated--migrator-weaviate-sample-0
  - message: PVC Migration Completed for weaviate-sample-0
    reason: PodMigrationCompleted-weaviate-sample-0
    status: "True"
    type: PodMigrationCompleted-weaviate-sample-0
  - message: PVC Migration Completed for weaviate-sample-1
    reason: PodMigrationCompleted-weaviate-sample-1
    status: "True"
    type: PodMigrationCompleted-weaviate-sample-1
  - message: Successfully migrated StorageClass for Weaviate
    reason: StorageMigration
    status: "True"
    type: StorageMigration
  - message: Successfully Migrated Weaviate StorageClass for demo/weaviate-sample
    reason: Successful
    status: "True"
    type: Successful
  observedGeneration: 1
  phase: Successful

Verify the StorageClass Migrated Successfully

Verify that the PVCs are now on the local-path StorageClass and the database is back to Ready:

$ kubectl get pvc -n demo -o custom-columns=NAME:.metadata.name,SC:.spec.storageClassName,SIZE:.status.capacity.storage
NAME                     SC           SIZE
data-weaviate-sample-0   local-path   3Gi
data-weaviate-sample-1   local-path   3Gi

$ kubectl get weaviate -n demo weaviate-sample -o jsonpath='{.spec.storage.storageClassName}{"  "}{.status.phase}'
local-path  Ready

The StorageClass has been migrated from longhorn to local-path successfully.

Next Steps

Cleaning Up

To clean up the Kubernetes resources created by this tutorial, run:

$ kubectl delete weaviateopsrequest -n demo storage-migration
$ kubectl delete weaviate -n demo weaviate-sample
$ kubectl delete ns demo