Skip to content

About

Open, Multi-Cloud, Multi-Cluster Kubernetes Orchestration

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Β 
Β 

Latest commit

Β 

History

6,477 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

PV Migration for StatefulSet Failover in Karmada

Branch: pvmigration | Base: karmada-io/karmada (CNCF Incubating Project)
Developed at: DCN Lab, Soongsil University
Development period: Jan 2025 – Aug 2025

Go Kubernetes CNCF


πŸ“Œ Problem

Karmada supports multi-cluster workload failover β€” but StatefulSets with PersistentVolumes (PV) are not handled.

When a StatefulSet is rescheduled to a new cluster:

Cluster A (failed)          Cluster B (target)
  StatefulSet ───────────────▢  StatefulSet
  PVC ─── PV (NFS)                 PVC ─── ??? ← PV missing β†’ pod stays Pending

The StatefulSet arrives in the target cluster but its PVs do not. Pods remain in Pending because PVCs cannot bind.

Root cause: Karmada's failover pipeline propagates resources tracked in ResourceBinding, but PersistentVolume objects are cluster-scoped and excluded from the propagation path. No existing mechanism migrates them.


πŸ’‘ Solution: Three-Controller Pipeline

This branch adds three new controllers to pkg/controllers/pvsync/ and registers them in cmd/controller-manager/, alongside a targeted modification to the existing applicationfailover controller.


πŸ—οΈ Architecture

image

πŸ”§ Controller Details

1. PVSyncController

Watches Work objects in execution namespaces. For each Work containing a StatefulSet:

  1. Extracts volumeClaimTemplates to build PVC name prefixes
  2. Connects to the member cluster via ClusterDynamicClientSetFunc
  3. Lists all PVs; filters by namespace + VCT prefix match (only relevant PVs)
  4. Serializes each PV spec as YAML, stores in a ConfigMap
  5. Creates/updates a metadata Work with SuspendDispatching: true β€” metadata only, no actual PV created

Labels on metadata Work:

pvsync.karmada.io/type:        metadata
pvsync.karmada.io/source-sts:  <namespace>.<name>
pvsync.karmada.io/source-work: <work-name>
pvsync.karmada.io/cluster:     <cluster-name>

2. PVMigrationController

Watches ResourceBinding for StatefulSets with Unhealthy aggregated status.

  1. Builds current cluster set from rb.Spec.Clusters
  2. Compares against clusters in PV metadata Works β€” detects rescheduling
  3. For each new target cluster: reads PV specs from ConfigMap metadata Works, creates PV Work (NFS-backed PersistentVolume)
  4. Parallel readiness check β€” spawns one goroutine per PV Work, polls phase (Available/Bound)
  5. When all PVs ready: releases suspension.dispatching with retry.RetryOnConflict to handle update races
  6. Deletes stale metadata Works from old clusters

Work naming: SHA1-hashed short suffix prevents name collisions across multiple PVs.

3. PVCleanupController

Manages full lifecycle of pvsync resources using the Kubernetes finalizer pattern.

  • Registers pvsync.karmada.io/cleanup finalizer on all StatefulSet ResourceBinding objects
  • On RB deletion: removes all associated pvsync Works and deletes orphan PV/PVC from member clusters via dynamic client (deleteOrphanPVResources)
  • On cluster change: garbage-collects Works from clusters no longer in rb.Spec.Clusters

4. RBApplicationFailoverController (modification)

In evictBinding(), added StatefulSet detection:

  • If the evicted resource is a StatefulSet, sets suspension.dispatching = true before failover proceeds
  • Prevents Karmada scheduler from re-dispatching the StatefulSet while PV migration is in progress

πŸ—‚οΈ Files Changed

File Type Description
cmd/controller-manager/app/controllermanager.go Modified Registered pvSync, pvMigration, pvCleanup controllers
pkg/controllers/pvsync/pvsync_controller.go New PVSyncController
pkg/controllers/pvsync/pvmigration_controller.go New PVMigrationController
pkg/controllers/pvsync/pvcleanup_controller.go New PVCleanupController
pkg/controllers/applicationfailover/rb_application_failover_controller.go Modified StatefulSet suspension on eviction

Net addition: ~1,000+ lines of Go across 5 files


🧠 Key Engineering Decisions

Decision Rationale
Metadata Work with SuspendDispatching Stores PV specs inside Karmada's own Work CRD β€” no external storage needed; suspension prevents unintended PV creation
Finalizer on ResourceBinding Guarantees cleanup even if operator deletes the RB before migration completes
Parallel goroutine readiness check Multiple PVCs per StatefulSet need independent readiness polling; sequential polling adds unnecessary latency
retry.RetryOnConflict on suspension update ResourceBinding is updated by multiple controllers; retry prevents losing updates under concurrent writes
SHA1 short hash for Work names Kubernetes name length limit (63 chars) exceeded with rb.Name + pvName + clusterName

⚠️ Current Limitations & Future Work

Item Status
NFS-only PV source type CSI driver support planned
No upstream PR yet Pending test coverage + CSI support
Unit / e2e tests Not yet written
Watch-based readiness Currently polling; Kubernetes Watch would be cleaner

πŸ“Š Scope

  • 3 new Kubernetes controllers implemented from scratch in Go
  • 1 existing controller modified (applicationfailover)
  • 1 controller-manager registration updated
  • Iterative development over 5 months with multiple design revisions

About

Open, Multi-Cloud, Multi-Cluster Kubernetes Orchestration

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages