You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
With global.enableProvidedByTopology=true and a WaitForFirstConsumer StorageClass, volumes can be provisioned in the hcloud CSI controller pod's location instead of the location of the node selected for the workload.
The generated allowedTopologies contains only instance.hetzner.cloud/provided-by=cloud. Because csi-provisioner runs without --strict-topology, the selected node's csi.hetzner.cloud/location is omitted from the CreateVolume request.
Expected behavior
When delayed binding selects a node for a PVC-backed pod, the volume should be created in that node's Hetzner location.
The CreateVolume accessibility requirements should include the selected node's complete CSI topology, including csi.hetzner.cloud/location, while instance.hetzner.cloud/provided-by=cloud continues to prevent provisioning on Robot nodes.
Observed behavior
With global.enableProvidedByTopology=true, the generated StorageClass restricts provisioning using only:
The resulting PV can therefore be created in a different location than the node selected for the pod. The pod then remains unschedulable because the PV node affinity does not match the selected node.
Minimal working example
Run Hetzner Cloud worker nodes in at least two locations.
Enable global.enableProvidedByTopology.
Use the generated StorageClass with volumeBindingMode: WaitForFirstConsumer.
Deploy multiple PVC-backed replicas with topology spread constraints so that Kubernetes selects nodes across the locations:
❯ kubectl get pods,pvc -l app=topology-repro
NAME READY STATUS RESTARTS AGE
pod/topology-repro-54bb978c4-8l6v4 1/1 Running 0 8s
pod/topology-repro-54bb978c4-lc572 0/1 Pending 0 8s
❯ kubectl get events --field-selector involvedObject.kind=Pod,involvedObject.name=topology-repro-54bb978c4-lc572 --sort-by=.lastTimestamp
LAST SEEN TYPE REASON OBJECT MESSAGE
27s Warning FailedScheduling pod/topology-repro-54bb978c4-lc572 0/11 nodes are available: waiting for ephemeral volume controller to create the persistentvolumeclaim "topology-repro-54bb978c4-lc572-data". not found
17s Warning FailedScheduling pod/topology-repro-54bb978c4-lc572 running PreBind plugin "VolumeBinding": binding volumes: pv "pvc-d723297e-20f8-4c06-8406-f330799943a7" node affinity doesn't match node "alpha-prd-k8s-worker-fsn1-b-1": no matching NodeSelectorTerms
16s Warning FailedScheduling pod/topology-repro-54bb978c4-lc572 0/11 nodes are available: 3 node(s) had untolerated taint(s), 4 node(s) didn't match PersistentVolume's node affinity, 4 node(s) didn't match pod topology spread constraints. no new claims to deallocate, preemption: 0/11 nodes are available: 4 No preemption victims found for incoming pod, 7 Preemption is not helpful for scheduling.
❯ kubectl get pv -o jsonpath='{range .items[*]}{.spec.claimRef.name}{"\t"}{.spec.nodeAffinity.required.nodeSelectorTerms[*].matchExpressions[?(@.key=="csi.hetzner.cloud/location")].values[*]}{"\n"}{end}' | grep topology-repro
topology-repro-54bb978c4-8l6v4-data nbg1
topology-repro-54bb978c4-lc572-data nbg1
Additional information
There are two possible fixes:
Enable --strict-topology when global.enableProvidedByTopology=true, so the complete topology of the scheduler-selected node is passed to the CSI driver:
{{- if .Values.global.enableProvidedByTopology }}
- --strict-topology{{- end }}
TL;DR
With
global.enableProvidedByTopology=trueand aWaitForFirstConsumerStorageClass, volumes can be provisioned in the hcloud CSI controller pod's location instead of the location of the node selected for the workload.The generated
allowedTopologiescontains onlyinstance.hetzner.cloud/provided-by=cloud. Becausecsi-provisionerruns without--strict-topology, the selected node'scsi.hetzner.cloud/locationis omitted from theCreateVolumerequest.Expected behavior
When delayed binding selects a node for a PVC-backed pod, the volume should be created in that node's Hetzner location.
The
CreateVolumeaccessibility requirements should include the selected node's complete CSI topology, includingcsi.hetzner.cloud/location, whileinstance.hetzner.cloud/provided-by=cloudcontinues to prevent provisioning on Robot nodes.Observed behavior
With
global.enableProvidedByTopology=true, the generated StorageClass restricts provisioning using only:The Helm chart starts
csi-provisionerwithout--strict-topology: https://github.com/hetznercloud/csi-driver/blob/v2.21.2/chart/templates/controller/deployment.yaml#L193-L206Without strict topology,
external-provisionerusesallowedTopologiesas the requisite topology and does not add the selected node's missingcsi.hetzner.cloud/location: https://github.com/kubernetes-csi/external-provisioner/blob/v6.2.0/pkg/controller/topology.go#L215-L239The hcloud CSI controller initializes the volume location with the controller pod's location and only overrides it when
csi.hetzner.cloud/locationis present in the accessibility requirements: https://github.com/hetznercloud/csi-driver/blob/v2.21.2/internal/driver/controller.go#L82-L88The resulting PV can therefore be created in a different location than the node selected for the pod. The pod then remains unschedulable because the PV node affinity does not match the selected node.
Minimal working example
global.enableProvidedByTopology.volumeBindingMode: WaitForFirstConsumer.Log output
Additional information
There are two possible fixes:
Enable
--strict-topologywhenglobal.enableProvidedByTopology=true, so the complete topology of the scheduler-selected node is passed to the CSI driver:Introduce new flag - strict-topology kubernetes-csi/external-provisioner#282 introduced
--strict-topologyto ensure delayed-bound volumes are created in the topology of the scheduler-selected node. The same safeguard would prevent this issue, whereallowedTopologiesomitscsi.hetzner.cloud/location.Include
csi.hetzner.cloud/locationin the generatedallowedTopologies, so the selected node's location is passed to the CSI driver:This alternative requires the location list to be kept up to date.
I tested both options successfully.
Likely related issues: