Container Failover Test¶
This guide walks through testing container workload failover by deploying a sample application with multiple replicas, simulating a node failure, and verifying the pods are rescheduled to healthy nodes. This assumes Workload Availability is fully configured with the 120-second failover settings.
Prerequisites¶
- Workload Availability operators installed (NHC, SNR, Descheduler)
- At least 3 worker nodes
- A default StorageClass available (for testing with persistent volumes)
Deploy a Sample Application¶
-
Create a namespace for the test:
-
Deploy a sample application with multiple replicas and a pod anti-affinity rule to spread pods across nodes:
apiVersion: apps/v1 kind: Deployment metadata: name: failover-test-app namespace: failover-test spec: replicas: 3 selector: matchLabels: app: failover-test template: metadata: labels: app: failover-test spec: affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchLabels: app: failover-test topologyKey: kubernetes.io/hostname containers: - name: app image: registry.redhat.io/hi/nginx:latest ports: - containerPort: 8080 resources: requests: memory: "128Mi" cpu: "100m" limits: memory: "256Mi" cpu: "200m" -
Create a Service to front the application:
Verify the Deployment¶
-
Confirm all 3 replicas are running and distributed across different nodes:
You should see pods on 3 different nodes due to the anti-affinity rule.
-
Record which pods are on which nodes:
-
Verify the application is responding through the Service:
Simulate Node Failure¶
-
Pick one of the nodes that has a pod running on it:
-
Record the pod on that node:
-
Start a timer and reboot the node to simulate a failure:
Watch the Failover¶
-
Watch the pods for changes:
You should see the following sequence: - Pods on the failed node remain in
Runningstate initially - After ~50s: node is markedNotReady- After ~80s: NHC creates aSelfNodeRemediationCR - After ~85s:out-of-servicetaint is applied, pods are force-deleted - After ~90s: new pod is scheduled on a healthy node and starts -
Once the replacement pod shows
Running, check the timestamp:You should see 3 pods running again, with the replacement on a different node.
Verify the Failover¶
-
Confirm all replicas are back to Running:
The
AVAILABLEcount should be back to3. -
Verify the Service is still responding without interruption:
Because the Service load balances across all healthy pods, the remaining 2 replicas continued serving traffic during the failover. Once the 3rd pod is rescheduled, full capacity is restored.
-
Check which nodes are now hosting pods:
-
Review the remediation events:
Key Differences from VM Failover¶
| Aspect | Container Pods | Virtual Machines |
|---|---|---|
| Restart behavior | New pod created by Deployment controller | New VMI created by virt-controller |
| Downtime | Zero (other replicas keep serving) | ~120s (single instance restarts) |
| IP persistence | New pod gets a new IP (Service abstracts this) | Same IP via CUDN persistent IPAM |
| Storage | StatefulSet PVCs reattach; Deployment PVCs are fresh | RWX disks reattach to new node |
| Scaling | Multiple replicas provide built-in HA | Single instance, relies on failover |
Why Containers Recover Faster
With multiple replicas behind a Service, container workloads experience zero downtime from the client's perspective during a node failure. The Service immediately stops routing to the unavailable pod, and the remaining replicas handle all traffic. The Deployment controller then creates a replacement pod on a healthy node to restore full capacity — but the application was never actually "down."
Test with a StatefulSet (Persistent Storage)¶
To test failover with persistent volumes, deploy a StatefulSet instead:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: failover-test-stateful
namespace: failover-test
spec:
replicas: 3
serviceName: failover-test-stateful
selector:
matchLabels:
app: failover-test-stateful
template:
metadata:
labels:
app: failover-test-stateful
spec:
containers:
- name: app
image: registry.redhat.io/hi/nginx:latest
ports:
- containerPort: 8080
volumeMounts:
- name: data
mountPath: /var/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
RWO StatefulSet Failover
StatefulSet pods using RWO volumes depend on the out-of-service taint to force-detach the volume from the failed node. Without Workload Availability (NHC + SNR), Kubernetes would wait for the node lease to expire (6+ minutes) before allowing the volume to attach elsewhere.
Cleanup¶
-
Delete the test resources:
-
Wait for the rebooted node to come back: