Prerequisites #
Kubernetes Secret #
Create a Kubernetes secret with the API token for a Hetzner Cloud project:
# Create Kubernetes secret
kubectl create secret generic hcloud --namespace=kube-system \
--from-literal=token='4euNmosomeAPIkeyOOToVZ'
Hetzner Cloud CSI Driver #
Add Helm Repository #
# Add the Hetzner Cloud Helm repository
helm repo add hcloud https://charts.hetzner.cloud
# Update all Helm repositories
helm repo update
Install Hetzner Cloud CSI Driver #
# Install CSI driver
helm install hcloud-csi hcloud/hcloud-csi \
--namespace kube-system \
--set controller.enabled=true \
--set node.enabled=true
# Shell output:
NAME: hcloud-csi
LAST DEPLOYED: Sun May 11 18:01:44 2025
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
Verify CSI Pods #
# List CSI pods
kubectl get pods -n kube-system -l app.kubernetes.io/instance=hcloud-csi
# Shell output:
NAME READY STATUS RESTARTS AGE
hcloud-csi-controller-c56857668-hwftf 5/5 Running 0 2m19s
hcloud-csi-node-l4k4x 3/3 Running 0 2m19s
hcloud-csi-node-z2v4m 3/3 Running 0 2m19s
hcloud-csi-node-zx5z6 3/3 Running 0 2m19s
Verify StorageClass #
Verify the Hetzner Cloud CSI default storage class:
# Verify the StorageClass
kubectl get sc
# Shell output:
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
hcloud-volumes (default) csi.hetzner.cloud Delete WaitForFirstConsumer true 8m19s
Create StorageClass #
Create a second StorageClass with “reclaimPolicy: Retain”:
# Create a configuration for the StorageClass
vi hcloud-volumes-retain.yml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: hcloud-volumes-retain
provisioner: csi.hetzner.cloud
parameters:
type: network
reclaimPolicy: Retain
volumeBindingMode: Immediate
allowVolumeExpansion: true
# Deploy the StorageClass
kubectl apply -f hcloud-volumes-retain.yml
Verify StorageClass #
# Verify the StorageClass
kubectl get sc
# Shell output:
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
hcloud-volumes (default) csi.hetzner.cloud Delete WaitForFirstConsumer true 10m
hcloud-volumes-retain csi.hetzner.cloud Retain Immediate true 5s
Example PVC #
Create PVC #
# Create a configuration for the PVC
vi example-pvc.yml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: example-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: hcloud-volumes-retain
# Create PVC
kubectl apply -f example-pvc.yml
Verify PVC & PV #
# List PVC
kubectl get pvc
# Shell output:
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
example-pvc Bound pvc-dece0343-335a-4fee-8d48-1503251629be 10Gi RWO hcloud-volumes-retain <unset> 31s
# List PVC
kubectl get pv
# Shell output:
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
pvc-dece0343-335a-4fee-8d48-1503251629be 10Gi RWO Retain Bound default/example-pvc hcloud-volumes-retain <unset> 47s
Verify Storage Volume via GUI #

Delete the PVC & PV #
# Delete the PVC
kubectl delete pvc example-pvc
# Delete the PV
kubectl delete pv pvc-dece0343-335a-4fee-8d48-1503251629be
- Manually delete the volume via the cloud console
Links #
# Official GitHub Repository
https://github.com/hetznercloud/csi-driver
# Official Documentation
https://github.com/hetznercloud/csi-driver/blob/main/docs/kubernetes/README.md#getting-started