Hetzner Cloud CSI Driver

repository·main·Indexed 21 days ago

https://github.com/hetznercloud/csi-driver

A Container Storage Interface (CSI) driver for Hetzner Cloud that enables the use of ReadWriteOnce Volumes within Kubernetes and Docker Swarm. It provides official support for Kubernetes via Helm charts and static manifests, as well as a Beta plugin for Docker Swarm.

Tokens
17.5K
Snippets
50
Records
74
Agent score
73%

What's inside hetznercloud-csi-driver

  1. Understand volume label defaults and constraints

    main

    Default Labels

    By default, the CSI driver automatically applies the following labels to all newly created volumes:

    • pvc-name
    • pvc-namespace
    • pv-name
    • managed-by=csi-driver

    Validation and Errors

    All labels are validated against the Hetzner Cloud API requirements. If a label is invalid, volume creation will fail with an InvalidArgument error.

    Truncation Behavior

    If a label value exceeds 63 characters, the driver automatically truncates it from the left, preserving only the last 63 characters. This is a critical consideration for pvc-name, pvc-namespace, and pv-name if your Kubernetes resource names are very long.

  2. Understand XFS compatibility defaults

    main

    When using xfs as the filesystem type without providing any fsFormatOptions, the driver automatically applies a default mkfs configuration designed to maximize compatibility with older Linux kernels (currently targeting Linux 4.19 via xfsprogs-extra).

    Important behavior changes:

    • If you provide any value for fsFormatOptions, the driver's default compatibility configuration is disabled.
    • When fsFormatOptions is used, you are responsible for ensuring the flags you provide are compatible with your current Linux kernel.
  3. How the hcloud-csi-driver architecture works

    main

    The hcloud-csi-driver follows the standard Container Storage Interface (CSI) architecture, split into two distinct deployment models: a Controller and a Node Driver.

    1. The Controller

    Deployed as a Kubernetes Deployment, the Controller manages cluster-wide volume operations. It consists of the main hcloud-csi-driver container and several sidecar containers (csi-attacher, csi-provisioner, csi-resizer, and liveness-probe).

    • Workflow: The sidecars watch the Kubernetes API for events (like PersistentVolumes or VolumeAttachments). When an event occurs, the sidecars send gRPC requests following the CSI specification to the hcloud-csi-driver container. The driver then communicates with the Hetzner Cloud API via REST to execute operations like creating, attaching, or resizing volumes.

    2. The Node Driver

    Deployed as a Kubernetes DaemonSet, the Node Driver manages node-specific operations. It consists of the main hcloud-csi-driver container and sidecars (csi-node-driver-registrar and liveness-probe).

    • Workflow: The csi-node-driver-registrar registers the driver with the local kubelet. Once registered, the kubelet communicates directly with the hcloud-csi-driver via a Unix socket to perform node-level tasks such as mounting and unmounting volumes. Unlike the Controller, the Node Driver does not communicate with the Kubernetes API or the Hetzner API directly.
  4. Understand the Kubernetes compatibility and versioning policy

    main

    The Hetzner Cloud CSI driver aims to support the latest three versions of Kubernetes.

    Key points of the policy:

    • Support Lifecycle: When a Kubernetes version is marked as End Of Life (EOL), support for it is discontinued, and it is removed from CI testing.
    • Functionality vs. Support: Discontinuing support does not guarantee the driver will not work with an EOL Kubernetes version, but the project will not provide bug fixes for issues specific to unsupported versions.
    • Deployment Matching: To ensure stability, you should use the CSI driver version and the corresponding deployment file that matches your Kubernetes version as specified in the compatibility matrix.
  5. Use the hcloud-volumes StorageClass for Persistent Volumes

    main

    The hcloud-csi driver provides a default StorageClass named hcloud-volumes.

    StorageClass Properties:

    • provisioner: csi.hetzner.cloud
    • volumeBindingMode: WaitForFirstConsumer: The volume is only provisioned once a Pod that uses the claim is scheduled. This ensures the volume is created in the same Hetzner Cloud location as the Pod.
    • reclaimPolicy: Delete: Deleting the PersistentVolumeClaim (PVC) will automatically delete the underlying Hetzner Cloud Volume.

    Usage Pattern: To use Hetzner Volumes, create a PersistentVolumeClaim specifying storageClassName: hcloud-volumes. Because Hetzner Volumes are ReadWriteOnce (RWO), they can only be attached to one node at a time. If using a Deployment, use a strategy: type: Recreate to ensure the old Pod is terminated before the new Pod attempts to attach the volume.

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: csi-pvc
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 10Gi
      storageClassName: hcloud-volumes
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: my-csi-app
    spec:
      replicas: 1
      strategy:
        type: Recreate
      selector:
        matchLabels:
          app: my-csi-app
      template:
        metadata:
          labels:
            app: my-csi-app
        spec:
          containers:
            - name: my-frontend
              image: busybox
              command: ["sleep", "infinity"]
              volumeMounts:
                - name: my-csi-volume
                  mountPath: /data
          volumes:
            - name: my-csi-volume
              persistentVolumeClaim:
                claimName: csi-pvc
  6. Handle major version upgrades

    main
    Major version upgrades may contain breaking changes that require manual intervention. Before performing a major upgrade, you should check the release notes for any specific requirements or breaking changes in the versions you are skipping. For specific instructions on moving from version 1 to version 2, refer to the dedicated guide: upgrading-from-v1-to-v2/.
  7. How volume location is determined

    main

    The CSI controller determines the default location for all volumes during initialization using a prioritized hierarchy of four methods.

    Important Exception: If your StorageClass uses volumeBindingMode: WaitForFirstConsumer, the volume's location is determined by the node where the Pod is scheduled. In this case, the default location logic described below is bypassed.

    Prioritized Location Resolution Order:

    1. Explicit Variable: The HCLOUD_VOLUME_DEFAULT_LOCATION environment variable is checked first.
    2. Server ID: If not explicitly set, the location is derived by querying the server specified by the HCLOUD_SERVER_ID environment variable.
    3. Node Name Lookup: If neither of the above is set, the driver uses the KUBE_NODE_NAME environment variable (defaulting to the node where the CSI controller is scheduled) to query the Hetzner API for a matching server and its location.
    4. Metadata Service Fallback: As a final fallback, the driver queries the Hetzner metadata service to obtain the server ID, which is then used to fetch the location via the Hetzner API.
  8. Deploy the CSI Controller Job

    main

    The CSI Controller manages the lifecycle of volumes. Create a file named hcloud-csi-controller.hcl with the following content. Note that for high availability, count = 2 is used with a distinct_hosts constraint. On a single-node cluster, you may need to modify or remove these stanzas.

    # file: hcloud-csi-controller.hcl
    
    job "hcloud-csi-controller" {
      datacenters = ["dc1"]
      namespace   = "default"
      type        = "service"
    
      group "controller" {
        count = 2
    
        constraint {
          distinct_hosts = true
        }
    
        update {
          max_parallel     = 1
          canary           = 1
          min_healthy_time = "10s"
          healthy_deadline = "1m"
          auto_revert      = true
          auto_promote     = true
        }
    
        task "plugin" {
          driver = "docker"
    
          config {
            # Get the latest version on https://hub.docker.com/r/hetznercloud/hcloud-csi-driver/tags
            image   = "hetznercloud/hcloud-csi-driver:v2.5.1"
            command = "bin/hcloud-csi-driver-controller"
          }
    
          env {
            CSI_ENDPOINT   = "unix://csi/csi.sock"
            ENABLE_METRICS = true
          }
    
          template {
            data        = <<EOH
    HCLOUD_TOKEN="{{ with nomadVar "secrets/hcloud" }}{{ .hcloud_token }}{{ end }}"
    EOH
            destination = "${NOMAD_SECRETS_DIR}/hcloud-token.env"
            env         = true
          }
    
          csi_plugin {
            id        = "csi.hetzner.cloud"
            type      = "controller"
            mount_dir = "/csi"
          }
    
          resources {
            cpu    = 100
            memory = 64
          }
        }
      }
    }
  9. Deploy the CSI Node Job

    main

    The CSI Node job runs on every node to handle volume mounting. Create a file named hcloud-csi-node.hcl. This job uses the system type to ensure it runs on all nodes.

    # file: hcloud-csi-node.hcl
    job "hcloud-csi-node" {
      datacenters = ["dc1"]
      namespace   = "default"
      type        = "system"
    
      group "node" {
        task "plugin" {
          driver = "docker"
    
          config {
            # Get the latest version on https://hub.docker.com/r/hetznercloud/hcloud-csi-driver/tags
            image      = "hetznercloud/hcloud-csi-driver:v2.5.1"
            command    = "bin/hcloud-csi-driver-node"
            privileged = true
          }
    
          env {
            CSI_ENDPOINT   = "unix://csi/csi.sock"
            ENABLE_METRICS = true
          }
    
          template {
            data        = <<EOH
    HCLOUD_TOKEN="{{ with nomadVar "secrets/hcloud" }}{{ .hcloud_token }}{{ end }}"
    EOH
            destination = "${NOMAD_SECRETS_DIR}/hcloud-token.env"
            env         = true
          }
    
          csi_plugin {
            id        = "csi.hetzner.cloud"
            type      = "node"
            mount_dir = "/csi"
          }
    
          resources {
            cpu    = 100
            memory = 64
          }
        }
      }
    }
  10. Scrape metrics using prometheus-operator ServiceMonitor

    main

    If you are using the prometheus-operator, you can enable automatic scraping by configuring the ServiceMonitor in the Helm chart.

    If your Prometheus instance uses a serviceMonitorSelector (for example, the default kube-prometheus-stack which selects on a release label), you must ensure the ServiceMonitor includes matching labels via metrics.serviceMonitor.labels.

    metrics:
      enabled: true
      serviceMonitor:
        enabled: true
        labels:
          release: YOUR_RELEASE