New to KubeDB? Please start here.
Milvus Storage Migration
This guide will show you how to use the KubeDB Ops-manager operator to migrate the persistent volumes of a Milvus database from one StorageClass to another.
Before You Begin
You should be familiar with the following
KubeDBconcepts:An object-storage secret named
my-release-miniomust exist in thedemonamespace.You need at least two
StorageClasses — the current one and the target one. This guide migrates fromlocal-pathtolonghorn-custom:$ kubectl get sc NAME PROVISIONER ALLOWVOLUMEEXPANSION AGE local-path (default) rancher.io/local-path false 11h longhorn-custom driver.longhorn.io true 11h
Note: The yaml files used in this tutorial are stored in docs/guides/milvus/storage-migration/yamls folder in GitHub repository kubedb/docs.
Storage Migration — Standalone Milvus
Deploy a standalone Milvus on local-path and wait until it is Ready:
$ kubectl get pvc -n demo -l app.kubernetes.io/instance=milvus-standalone
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
data-milvus-standalone-0 Bound pvc-... 1Gi RWO local-path 14m
Apply the StorageMigration OpsRequest
storage-migration-standalone.yaml
apiVersion: ops.kubedb.com/v1alpha1
kind: MilvusOpsRequest
metadata:
name: storage-migration
namespace: demo
spec:
type: StorageMigration
databaseRef:
name: milvus-standalone
migration:
storageClassName: longhorn-custom
oldPVReclaimPolicy: Delete
timeout: 10m
Here,
spec.migration.storageClassNameis the targetStorageClass.spec.migration.oldPVReclaimPolicycontrols what happens to the old PersistentVolume (DeleteorRetain).
$ kubectl apply -f https://github.com/kubedb/docs/raw/v2026.6.19/docs/guides/milvus/storage-migration/yamls/storage-migration-standalone.yaml
milvusopsrequest.ops.kubedb.com/storage-migration created
Watch Progress
$ kubectl get milvusopsrequest storage-migration -n demo
NAME TYPE STATUS AGE
storage-migration StorageMigration Successful 87s
$ kubectl describe milvusopsrequest storage-migration -n demo
...
Status:
Conditions:
Message: StorageClass migration is in progress
Reason: Running
Type: Running
Message: pet set deleted; ConditionStatus:True; PodName:milvus-standalone
Type: PetSetDeleted--milvus-standalone
Message: get storage class; ConditionStatus:True
Type: GetStorageClass
...
Phase: Successful
During migration, the operator runs a migrator job to copy the data, recreates the PVC on the new StorageClass, and recreates the pod.
Verify the Migration
The PVC is now backed by longhorn-custom, and the database spec reflects the new class:
$ kubectl get pvc -n demo -l app.kubernetes.io/instance=milvus-standalone
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
data-milvus-standalone-0 Bound pvc-... 1Gi RWO longhorn-custom 33s
$ kubectl get milvuses.kubedb.com milvus-standalone -n demo -o jsonpath='{.spec.storage.storageClassName}'
longhorn-custom
Storage Migration — Distributed Milvus
For a distributed Milvus, migration targets the workloads that carry persistent storage — i.e. streamingnode. Point spec.databaseRef.name at milvus-cluster:
storage-migration-distributed.yaml
apiVersion: ops.kubedb.com/v1alpha1
kind: MilvusOpsRequest
metadata:
name: storage-migration
namespace: demo
spec:
type: StorageMigration
databaseRef:
name: milvus-cluster
migration:
storageClassName: longhorn-custom
oldPVReclaimPolicy: Delete
timeout: 10m
The operator migrates the PVC of every streamingnode replica. Starting from local-path:
$ kubectl get pvc -n demo -l app.kubernetes.io/instance=milvus-cluster -o custom-columns=NAME:.metadata.name,SIZE:.status.capacity.storage,SC:.spec.storageClassName
NAME SIZE SC
data-milvus-cluster-streamingnode-0 1Gi local-path
data-milvus-cluster-streamingnode-1 1Gi local-path
After the migration completes:
$ kubectl get milvusopsrequest storage-migration -n demo
NAME TYPE STATUS AGE
storage-migration StorageMigration Successful 3m40s
$ kubectl get pvc -n demo -l app.kubernetes.io/instance=milvus-cluster -o custom-columns=NAME:.metadata.name,SIZE:.status.capacity.storage,SC:.spec.storageClassName
NAME SIZE SC
data-milvus-cluster-streamingnode-0 1Gi longhorn-custom
data-milvus-cluster-streamingnode-1 1Gi longhorn-custom
$ kubectl get milvuses.kubedb.com milvus-cluster -n demo -o jsonpath='{.spec.topology.distributed.streamingnode.storage.storageClassName}'
longhorn-custom
(This example was run with streamingnode scaled to two replicas; both PVCs are migrated.)
Cleaning up
$ kubectl delete milvusopsrequest -n demo storage-migration
$ kubectl delete milvus.kubedb.com -n demo milvus-standalone
$ kubectl delete ns demo
Next Steps
- Learn about volume expansion of a Milvus database.
- Detail concepts of Milvus object.
- Want to hack on KubeDB? Check our contribution guidelines.































