Using Volume Group Snapshots with LINSTOR in Kubernetes

Version 2.10.0 of the LINSTOR® Operator for Kubernetes, developed by LINBIT®, introduces support for volume group snapshots, a feature that enables crash-consistent, point-in-time snapshots of multiple persistent volumes simultaneously. Kubernetes 1.36 promoted the VolumeGroupSnapshot API to General Availability (GA) under the groupsnapshot.storage.k8s.io/v1 API group.

Before volume group snapshots, a Kubernetes operator could only take snapshots of one persistent volume at a time. For stateful applications that distribute their data across multiple PVCs (for example, a database that separates data from write-ahead logs, or a web application that stores relational data and user-uploaded media in separate volumes), this meant accepting a window of inconsistency between snapshots. Volume group snapshots close that window by instructing the CSI driver to snapshot all grouped volumes atomically, at the exact same point in time.

This article will guide you through setting up, testing, and verifying the volume group snapshot feature by using LINSTOR in Kubernetes.

Prerequisites

To follow the instructions in this article, you will need:

  • A running Kubernetes cluster, version 1.36 or later.
  • LINSTOR Operator version 2.10.0 or later deployed in your cluster. If you do not yet have LINSTOR in your cluster, you can follow the Integrating LINBIT® SDS with Kubernetes, a Quick Start Guide.
  • LINSTOR storage backed by LVM thin-provisioned or ZFS thin-provisioned pools, which are required for snapshot support.
  • CRDs from the CSI external-snapshotter project, and snapshot-controller deployment, version 8.x. The steps in the next section cover installing these if you do not yet have them.

 

Enabling volume group snapshot support

Enabling volume group snapshots requires a one-time configuration change across three places: the CSI snapshotter CRDs, the snapshot-controller deployment, and the LINSTOR Operator’s CSI controller.

Installing the CSI snapshotter CRDs

The group snapshot CRDs ship alongside the standard snapshot CRDs in the external-snapshotter project. If you have already installed the CRDs by using the external-snapshotter repository, your deployment likely has the group snapshot CRDs already.

To install or update the snapshot CRDs, including the group snapshot CRDs, run the following command:

kubectl apply -k https://github.com/kubernetes-csi/external-snapshotter//client/config/crd

After applying the CRDs, verify that the group snapshot resources are available:

kubectl api-resources --api-group=groupsnapshot.storage.k8s.io

The output should list the three group snapshot resources:

NAME                          SHORTNAMES            APIVERSION                        NAMESPACED   KIND
volumegroupsnapshotclasses    vgsclass,vgsclasses   groupsnapshot.storage.k8s.io/v1   false        VolumeGroupSnapshotClass
volumegroupsnapshotcontents   vgsc,vgscs            groupsnapshot.storage.k8s.io/v1   false        VolumeGroupSnapshotContent
volumegroupsnapshots          vgs                   groupsnapshot.storage.k8s.io/v1   true         VolumeGroupSnapshot

Deploying the snapshot-controller

If you have not already deployed the snapshot-controller, install it from the external-snapshotter project:

kubectl apply -k https://github.com/kubernetes-csi/external-snapshotter//deploy/kubernetes/snapshot-controller

After applying, verify that the snapshot-controller pods are running:

kubectl get pods -n kube-system -l app.kubernetes.io/name=snapshot-controller
NAME                                   READY   STATUS    RESTARTS   AGE
snapshot-controller-58b6fc7b8f-7vc9q   1/1     Running   0          15s
snapshot-controller-58b6fc7b8f-hdjjk   1/1     Running   0          15s

Enabling the CSIVolumeGroupSnapshot feature gate in the snapshot-controller

The snapshot-controller requires the CSIVolumeGroupSnapshot feature gate to be explicitly enabled to process VolumeGroupSnapshot objects. Run the following command to add the feature gate to the snapshot-controller deployment.

kubectl patch deployment snapshot-controller -n kube-system --type=json \
  -p='[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--feature-gates=CSIVolumeGroupSnapshot=true"}]'

❗ IMPORTANT: This command assumes that the snapshot-controller deployment is in the kube-system namespace and that the first container in the pod spec is the snapshot-controller container, which is true for the standard external-snapshotter deployment manifests. If your deployment differs, adjust the namespace and JSON patch path accordingly.

Enabling the CSIVolumeGroupSnapshot feature gate in the LINSTOR Operator

The LINSTOR Operator deploys a csi-snapshotter sidecar container inside the LINSTOR CSI controller pod. This sidecar handles the actual CSI CreateVolumeGroupSnapshot API calls to the LINSTOR CSI driver and also requires the feature gate to be enabled.

To enable it, patch the LinstorCluster resource to override the applicable environment variable in the csi-snapshotter container:

kubectl patch linstorcluster linstorcluster --type=merge --patch '
spec:
  csiController:
    podTemplate:
      spec:
        containers:
        - name: csi-snapshotter
          env:
          - name: FEATURE_GATE_CSI_VOLUME_GROUP_SNAPSHOT
            value: "true"
'

After applying the patch, the LINSTOR Operator will restart the CSI controller pod with the updated environment variable. You can verify this by confirming the new pod picks up the setting.

kubectl get pods -n linbit-sds -l "app.kubernetes.io/component=linstor-csi-controller" \
  -o jsonpath='{range .items[0].spec.containers[?(@.name=="csi-snapshotter")]}{range .env[*]}{.name}: {.value}\n{end}{end}'

The output should show FEATURE_GATE_CSI_VOLUME_GROUP_SNAPSHOT: true.

Creating a volume group snapshot class

VolumeGroupSnapshotClass defines how group snapshots should be created, in the same way that a VolumeSnapshotClass defines how individual volume snapshots should be created. Create a VolumeGroupSnapshotClass that references the LINSTOR CSI driver.

apiVersion: groupsnapshot.storage.k8s.io/v1
kind: VolumeGroupSnapshotClass
metadata:
  name: linstor-group-snapshots
driver: linstor.csi.linbit.com
deletionPolicy: Delete

Apply this to your cluster:

kubectl apply -f linstor-group-snapshots-class.yaml

Taking a volume group snapshot

The following example demonstrates taking a crash-consistent group snapshot of a web application that uses two LINSTOR-backed PVCs: one for database storage, and one for user-uploaded media.

Grouping the PVCs by using a label

Volume group snapshots use Kubernetes label selectors to identify which PVCs should be included in a group. The two PVCs in this example were created with a group: my-app label. If your existing PVCs do not yet have this label, you can add it using the kubectl label command.

kubectl label pvc my-app-database group=my-app
kubectl label pvc my-app-uploads group=my-app

The following YAML creates the two PVCs used in this example:

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: my-app-database
  namespace: default
  labels:
    group: my-app
spec:
  storageClassName: linstor-csi-lvm-thin-r1
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: my-app-uploads
  namespace: default
  labels:
    group: my-app
spec:
  storageClassName: linstor-csi-lvm-thin-r1
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi

Creating a volume group snapshot

With the PVCs labeled, create a VolumeGroupSnapshot that uses a label selector to identify all PVCs belonging to the group.

apiVersion: groupsnapshot.storage.k8s.io/v1
kind: VolumeGroupSnapshot
metadata:
  name: my-app-snapshot
  namespace: default
spec:
  volumeGroupSnapshotClassName: linstor-group-snapshots
  source:
    selector:
      matchLabels:
        group: my-app

Apply this to your cluster:

kubectl apply -f my-app-snapshot.yaml

Verifying the group snapshot

After creating the VolumeGroupSnapshot, you can watch its status until it reports READYTOUSE: true:

kubectl get volumegroupsnapshot my-app-snapshot --watch

The output will update as the snapshot progresses:

NAME              READYTOUSE   VOLUMEGROUPSNAPSHOTCLASS   VOLUMEGROUPSNAPSHOTCONTENT                    CREATIONTIME   AGE
my-app-snapshot                linstor-group-snapshots                                                                 5s
my-app-snapshot   false        linstor-group-snapshots    groupsnapcontent-81349afd-...                                8s
my-app-snapshot   true         linstor-group-snapshots    groupsnapcontent-81349afd-...                 2s             12s

When the VolumeGroupSnapshot becomes ready, the snapshot-controller automatically creates an individual VolumeSnapshot object for each PVC that was part of the group. You can list these individual snapshots, along with which PVC each was created from, by running.

kubectl get volumesnapshot -n default

The SOURCEPVC column identifies which PVC each individual VolumeSnapshot corresponds to:

NAME                                                                          READYTOUSE   SOURCEPVC          RESTORESIZE   CREATIONTIME
snapshot-7df4c9b9345f004500ba96484bf9a6f92d36b64df3607cc9e3164241fa6a70e8    true         my-app-database    10Gi          2s
snapshot-ffbe7dedd160590f8101fa0950a12c4a39582a60aba57b8e6c23f55c402237ea    true         my-app-uploads     20Gi          2s

Restoring from a group snapshot

To restore volumes from a group snapshot, create new PVCs that reference the individual VolumeSnapshot objects created by the group snapshot. The dataSource field on each PVC references the specific VolumeSnapshot for the volume you want to restore.

Use the kubectl get volumesnapshot output from the previous step to match the snapshot names to the PVCs you want to restore.

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: my-app-database-restore
  namespace: default
spec:
  storageClassName: linstor-csi-lvm-thin-r1
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  dataSource:
    name: snapshot-7df4c9b9345f004500ba96484bf9a6f92d36b64df3607cc9e3164241fa6a70e8
    kind: VolumeSnapshot
    apiGroup: snapshot.storage.k8s.io
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: my-app-uploads-restore
  namespace: default
spec:
  storageClassName: linstor-csi-lvm-thin-r1
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
  dataSource:
    name: snapshot-ffbe7dedd160590f8101fa0950a12c4a39582a60aba57b8e6c23f55c402237ea
    kind: VolumeSnapshot
    apiGroup: snapshot.storage.k8s.io

After applying this YAML, both restore PVCs will be provisioned from the snapshot data and will reach Bound status quickly:

kubectl get pvc my-app-database-restore my-app-uploads-restore
NAME                       STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS
my-app-database-restore    Bound    pvc-9293ffe4-84f1-4051-ad5c-81235746dd67   10Gi       RWO            linstor-csi-lvm-thin-r1
my-app-uploads-restore     Bound    pvc-46ee2702-ab4a-40f2-b502-c84ba1c80616   20Gi       RWO            linstor-csi-lvm-thin-r1

You can then attach these restored PVCs to new pods or update your application deployment to point to the restored volumes.

Use cases for volume group snapshots

The following sections give overviews of some common use cases for volume group snapshots in Kubernetes.

Databases with separate data and log volumes

Many database engines, such as PostgreSQL or MySQL, perform better when data files and write-ahead logs (WALs) are on separate volumes. Volume group snapshots ensure that both volumes are captured at an identical point in time, which is essential for a consistent restore. A WAL snapshot taken even milliseconds after the data snapshot could reflect transactions not yet committed to the data volume.

Multi-tiered application backups

A web application might store relational data in a database volume and user-uploaded files in a separate media volume. A group snapshot captures both volumes in the same atomic operation. This guarantees that the database state and the uploaded file inventory are consistent with each other.

Taking a backup before upgrading

Before a major application upgrade that involves schema changes or data migrations across multiple PVCs, a volume group snapshot creates a single consistent rollback point. If the upgrade fails partway through, you can restore all volumes together to the state before the upgrade, without the risk of having partial migration artifacts.

Final thoughts

Using LINSTOR to take and restore volume group snapshots is a straightforward way to have crash-consistent multi-volume backups in Kubernetes, without requiring application-level quiescence or coordination. After enabling the feature gates, and a VolumeGroupSnapshotClass is in place, the workflow is as simple as labeling your PVCs and creating a VolumeGroupSnapshot object. This makes for a declarative, Kubernetes-native approach to multi-volume disaster recovery.

If you are new to LINSTOR in Kubernetes and want to try it using the convenience of container images in the official LINBIT container registry, drbd.ioreach out to the LINBIT team to request evaluation access. Alternatively, you can use the freely available upstream project, the Piraeus Operator, to deploy LINSTOR in Kubernetes.

Picture of Matt Kereczman

Matt Kereczman

Matt Kereczman is a Solutions Architect at LINBIT with a long history of Linux System Administration and Linux System Engineering. Matt is a cornerstone in LINBIT's technical team, and plays an important role in making LINBIT and LINBIT's customer's solutions great. Matt was President of the GNU/Linux Club at Northampton Area Community College prior to graduating with Honors from Pennsylvania College of Technology with a BS in Information Security. Open Source Software and Hardware are at the core of most of Matt's hobbies.

Talk to us

LINBIT is committed to protecting and respecting your privacy, and we’ll only use your personal information to administer your account and to provide the products and services you requested from us. From time to time, we would like to contact you about our products and services, as well as other content that may be of interest to you. If you consent to us contacting you for this purpose, please tick above to say how you would like us to contact you.

You can unsubscribe from these communications at any time. For more information on how to unsubscribe, our privacy practices, and how we are committed to protecting and respecting your privacy, please review our Privacy Policy.

By clicking submit below, you consent to allow LINBIT to store and process the personal information submitted above to provide you the content requested.

Talk to us

LINBIT is committed to protecting and respecting your privacy, and we’ll only use your personal information to administer your account and to provide the products and services you requested from us. From time to time, we would like to contact you about our products and services, as well as other content that may be of interest to you. If you consent to us contacting you for this purpose, please tick above to say how you would like us to contact you.

You can unsubscribe from these communications at any time. For more information on how to unsubscribe, our privacy practices, and how we are committed to protecting and respecting your privacy, please review our Privacy Policy.

By clicking submit below, you consent to allow LINBIT to store and process the personal information submitted above to provide you the content requested.