Skip to main content

Failover Workflow

Testudo V2 uses the Pilot Light model for DR failover. During normal protection, data and resources are continuously synchronized to the secondary cluster. The secondary cluster keeps a switch-ready resource skeleton, but workloads normally stay at replicas=0 and do not receive production traffic.

This page explains the instance-level failover workflow. For console steps, see Run Instance Failover.

If a failover step fails or times out, the operator may auto-compensate based on the failed stage. See Failover Auto-Compensation.

Pilot Light failover workflow

Editable source: pilot-light-failover-workflow.excalidraw

Pilot Light State

When a DR instance is Protected, the relationship is normally:

ObjectPrimary clusterSecondary cluster
Business workloadsRunningResource skeleton exists, usually with replicas=0
DataContinuously backed upContinuously restored or ready to restore
Kubernetes resourcesOriginal resourcesStandby resources restored by ResourceSync
External trafficRouted by the external traffic systemDoes not serve production traffic

The goal is to reduce cold recovery time. Failover does not create everything from scratch; it activates resources already prepared on the secondary cluster.

Preconditions

Before failover, the instance should normally be:

primaryCluster = current primary cluster
secondaryCluster = current secondary cluster
fsmState = Protected

Check that:

  • The latest DataSync succeeded.
  • The latest ResourceSync succeeded.
  • Standby resources exist on the target cluster.
  • Target-side images, Secrets, StorageClasses, IngressClasses, CRDs, and network dependencies are ready.
  • DNS, gateway, load balancer, or traffic switching procedures are ready outside Testudo.

Testudo orchestrates Kubernetes resource and data recovery. It does not replace external global traffic management.

Standard Steps

Failover creates a DisasterOperation with operationType=failover. The current implementation runs:

PreCheck
-> PauseSchedules
-> FinalSync
-> ScaleDownSource
-> ScaleUpTarget
-> CheckReplicas
-> SwitchRoles

1. PreCheck

The operator checks the instance, DR config, clusters, storage repository, ResourceSync/DataSync state, and restore policy rules.

This step is designed to catch problems before destructive actions start. If precheck fails, source scaling is not executed.

2. PauseSchedules

The operator pauses DataSync and ResourceSync schedules so a new sync does not start while failover is running.

3. FinalSync

The operator triggers one final DataSync and ResourceSync and waits for them to complete.

FinalSync must run before ScaleDownSource because Velero FSB needs source Pods to stay running so it can read mounted PVC data. If source Pods are scaled down first, the final data sync may miss PVC contents.

If the user skips final sync, the operator uses the most recent successful sync point. This is useful when the source cluster is unreachable, but it increases RPO risk.

4. ScaleDownSource

The operator scales workloads down on the current primary cluster. Before scaling down, it records original replica counts for later target activation.

5. ScaleUpTarget

The operator restores Deployment and StatefulSet replica counts on the current secondary cluster.

The target side normally starts from standby resources created by ResourceSync, often with replicas=0.

6. CheckReplicas

The operator checks that target workload replicas were applied. Depending on skipPodReadyCheck, it may also wait for ready replicas.

Use skipPodReadyCheck=true only when an external dependency is expected to keep Pods unready during the transition or when the runbook explicitly accepts that risk.

7. SwitchRoles

After target activation succeeds, the operator switches instance roles:

primaryCluster = old secondary cluster
secondaryCluster = old primary cluster
fsmState = Active

After this step, follow with reprotect when the new primary must protect back to the old primary.

Operation Parameters

Common failover parameters:

ParameterMeaningTypical use
skipFinalSyncSkip the last DataSync/ResourceSyncSource cluster is unreachable, or fast failover from latest known sync point is required
skipPodReadyCheckDo not wait for target Pods to become ReadyBusiness readiness is verified by another system, or readiness probes are expected to fail temporarily
operationTimeoutMinutesOperation-level timeoutLarge workloads or slow storage need longer timeouts

Normal failover example:

{
"operationType": "failover",
"parameters": {
"skipFinalSync": false,
"skipPodReadyCheck": false,
"operationTimeoutMinutes": 60
}
}

Forced failover from the last successful sync point:

{
"operationType": "failover",
"parameters": {
"skipFinalSync": true,
"skipPodReadyCheck": true,
"operationTimeoutMinutes": 30
}
}

After Failover

After failover succeeds:

  • Verify workloads and PVC data on the new primary cluster.
  • Switch external traffic to the new primary cluster.
  • Confirm that the old primary is not still serving traffic.
  • Run reprotect after the environment is stable, so synchronization direction becomes new primary to new secondary.

Common Risks

RiskSymptomRecommendation
FinalSync takes too longOperation timeout or delayed failoverTune schedule, storage throughput, and operation timeout before production
Source cluster is unreachablePreCheck or FinalSync failsUse forced failover only when the runbook accepts the RPO risk
Target dependency is missingWorkloads cannot start after ScaleUpTargetValidate StorageClass, IngressClass, CRD, image pull, Secret, and network dependencies through drills
External traffic not switchedTarget workloads are running but users still hit the old siteKeep global traffic switching in the failover runbook

Drills validate the restore path, but a production failover still needs traffic switching and source/target role control.