Coordinated Worker Node Drain
When a Kubernetes worker is cordoned or drained, for example, during a rolling OS upgrade, the Simplyblock Operator
takes the storage node on that worker down gracefully, lets the drain proceed, and brings the node back once the
worker returns. The sequence is a StorageNodeOps with the action HostMaintenance, which the operator raises on its
own. No manual intervention is required.
This is a temporary absence, after which the storage node returns to the same worker. Taking a node out of the cluster for good is a different operation, described in Removing a Storage Node.
How It Is Triggered
The operator watches the Kubernetes nodes. When the worker of a registered storage node is cordoned, it creates a
StorageNodeOps named <storage-node>-maintenance with the action HostMaintenance, owned by the StorageNode. A
worker that hosts several storage nodes gets one operation per node.
kubectl cordon worker-1.example.com
kubectl drain worker-1.example.com --ignore-daemonsets --delete-emptydir-data
kubectl get storagenodeops simplyblock-cluster-worker-1-0-maintenance -n simplyblock -o wide -w
A HostMaintenance operation can also be created by hand, and it then behaves identically, which is useful for
testing the flow without cordoning anything.
Warning
The operator raises the operation only if no object named <storage-node>-maintenance exists yet. A completed
maintenance record is therefore deleted before the next maintenance window of the same worker, otherwise that
window is not coordinated.
kubectl delete storagenodeops simplyblock-cluster-worker-1-0-maintenance -n simplyblock
Steps
| Step | Deadline | Description |
|---|---|---|
Holding |
6 hours | Waits for a maintenance slot, so that no more workers than allowed are in maintenance at once. |
ShuttingDown |
15 minutes | Blocks the eviction of the storage-node pod with a PodDisruptionBudget, then shuts the backend node down. |
Releasing |
15 minutes | Relaxes the budget, so that the drain can evict the pod, and waits until the pod is gone. |
AwaitingHost |
4 hours | Waits until the storage-node API on the worker answers again after the reboot. |
Restarting |
45 minutes | Restarts the backend node, and waits until it is online. |
Cleanup |
5 minutes | Removes the disruption budgets the window put in place. |
The PodDisruptionBudget runs backward from the usual one. It allows no disruption and is created before the
shutdown, so that kubectl drain blocks on the storage-node pod while the backend node is being taken down
gracefully. Relaxing it in Releasing is what lets the drain proceed. On a hyper-converged worker, the operator also
protects its own pod in the same way until Releasing, so that the drain cannot evict the operator before the storage
node is safely offline.
spec.force and spec.reattachVolume of the operation apply to the restart in Restarting.
Note
If the worker does not come back within the four hours of AwaitingHost, the operation fails and the node stays
offline. It is then recovered with a Restart once the worker is back.
Concurrent Maintenance Windows
How many workers may be in maintenance at the same time is capped by the StorageCluster. A window that has passed
Holding holds a slot, counted by distinct worker, so the storage nodes of a multi-socket worker share one slot. A
window that has to wait holds in Holding with a MaintenanceQueued event, and it continues once a slot frees up.
| Field | Description |
|---|---|
spec.maxConcurrentWorkerRestarts |
The number of workers that may be in maintenance at once. Minimum 1, default 1. |
status.maxFaultTolerance |
The fault tolerance the control plane reports for the cluster. |
status.maxConcurrentWorkerRestarts |
The effective cap: the smaller of the two values above. |
apiVersion: storage.simplyblock.io/v1alpha2
kind: StorageCluster
metadata:
name: simplyblock-cluster
namespace: simplyblock
spec:
maxConcurrentWorkerRestarts: 2
kubectl get storagecluster simplyblock-cluster -n simplyblock \
-o jsonpath='{.status.maxConcurrentWorkerRestarts}{" of ftt="}{.status.maxFaultTolerance}{"\n"}'
A value of 1 is the safest setting. The effective value never exceeds the number of simultaneous node outages the
erasure coding scheme of the cluster tolerates, so a higher setting only takes effect on a cluster that can afford it.
Like the other node operations, a maintenance window also holds with a ClusterNotReady event while the cluster is not
active or is rebalancing.
Aborting a Maintenance Window
A maintenance window can be aborted only in Holding, before the node has been taken down. From ShuttingDown
onward, the node is going down for a reboot that nothing else brings it back from, so an abort is not honored, and the
webhook refuses deleting the operation until it is terminal.
Monitoring Maintenance Windows
kubectl get storagenodeops -n simplyblock \
-o custom-columns=NAME:.metadata.name,NODE:.spec.nodeRef,ACTION:.spec.action,PHASE:.status.phase,STEP:.status.step.state \
| grep -E 'NAME|HostMaintenance'
kubectl get events -n simplyblock \
--field-selector reason=MaintenanceQueued