Using volume snapshots

In Google Kubernetes Engine (GKE), you can use the Kubernetes volume snapshot feature for persistent volumes in your GKE clusters.

Volume snapshots let you create a copy of your volume at a specific point in time. You can use this copy to bring a volume back to a prior state or to provision a new volume.

From version 1.17 or later, you can provision and attach volume snapshots with the following components:

Requirements

You must meet the following requirements to use volume snapshots on GKE:

  • Use a CSI driver that supports snapshots. Snapshots are not supported by the in-tree persistent disk driver.

  • Use control plane (master) versions that are GKE versions 1.17 or later. To use the Compute Engine persistent disk CSI Driver in a VolumeSnapshot, use GKE versions 1.17.6-gke.4 or later. To use the Filestore CSI Driver in a VolumeSnapshot, use GKE versions 1.21 or later.

  • Have an existing PersistentVolumeClaim to use for a snapshot. The PersistentVolume you use for a snapshot source must be managed by a CSI driver. You can verify that you're using a CSI driver by checking that the PersistentVolume spec has a csi section with driver: pd.csi.storage.gke.io or filestore.csi.storage.gke.io. If the PersistentVolume is dynamically provisioned by the CSI driver as described in the following sections, it's managed by the CSI driver.

Before you begin

Before you start, make sure you have performed the following tasks:

Set up default gcloud settings using one of the following methods:

  • Using gcloud init, if you want to be walked through setting defaults.
  • Using gcloud config, to individually set your project ID, zone, and region.

Using gcloud init

If you receive the error One of [--zone, --region] must be supplied: Please specify location, complete this section.

  1. Run gcloud init and follow the directions:

    gcloud init

    If you are using SSH on a remote server, use the --console-only flag to prevent the command from launching a browser:

    gcloud init --console-only
  2. Follow the instructions to authorize gcloud to use your Google Cloud account.
  3. Create a new configuration or select an existing one.
  4. Choose a Google Cloud project.
  5. Choose a default Compute Engine zone for zonal clusters or a region for regional or Autopilot clusters.

Using gcloud config

  • Set your default project ID:
    gcloud config set project PROJECT_ID
  • If you are working with zonal clusters, set your default compute zone:
    gcloud config set compute/zone COMPUTE_ZONE
  • If you are working with Autopilot or regional clusters, set your default compute region:
    gcloud config set compute/region COMPUTE_REGION
  • Update gcloud to the latest version:
    gcloud components update

Creating and using a volume snapshot

The examples in this document show you how to do the following:

  1. Create a PersistentVolumeClaim and Deployment.
  2. Add a file to the PersistentVolume that the Deployment uses.
  3. Create a VolumeSnapshotClass to configure the snapshot.
  4. Create a volume snapshot of the PersistentVolume.
  5. Delete the test file.
  6. Restore the PersistentVolume to the snapshot you created.
  7. Verify that the restoration worked.

To use a volume snapshot, you must complete the following steps:

  1. Create a VolumeSnapshotClass object to specify the CSI driver and deletion policy for your snapshot.
  2. Create a VolumeSnapshot object to request a snapshot of an existing PersistentVolumeClaim.
  3. Reference the VolumeSnapshot in a PersistentVolumeClaim to restore a volume to that snapshot or create a new volume using the snapshot.

Create a PersistentVolumeClaim and a Deployment

  1. To create the PersistentVolumeClaim object, save the following manifest as my-pvc.yaml:

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: my-pvc
    spec:
      storageClassName: standard-rwo
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 1Gi
    

    For spec.storageClassName, you can specify any storage class that uses a supported CSI driver. This example uses the standard-rwo storage class installed by default with the Compute Engine persistent disk CSI driver. For more information, refer to Using the Compute Engine persistent disk CSI driver.

  2. Apply the manifest:

    kubectl apply -f my-pvc.yaml
    
  3. To create a Deployment, save the following manifest as my-deployment.yaml:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: hello-app
    spec:
      selector:
        matchLabels:
          app: hello-app
      template:
        metadata:
          labels:
            app: hello-app
        spec:
          containers:
          - name: hello-app
            image: google/cloud-sdk:slim
            args: [ "sleep", "3600" ]
            volumeMounts:
            - name: sdk-volume
              mountPath: /usr/share/hello/
          volumes:
          - name: sdk-volume
            persistentVolumeClaim:
              claimName: my-pvc
    
  4. Apply the manifest:

    kubectl apply -f my-deployment.yaml
    
  5. Check the status of the Deployment:

    kubectl get deployment hello-app
    

Add a test file to the volume

  1. List the pods in the Deployment:

    kubectl get pods -l app=hello-app
    

    The output is similar to the following:

    NAME                         READY   STATUS    RESTARTS   AGE
    hello-app-6d7b457c7d-vl4jr   1/1     Running   0          2m56s
    
  2. Create a test file in a Pod:

    kubectl exec POD_NAME -- sh -c 'echo "Hello World!" > /usr/share/hello/hello.txt'
    

    Replace POD_NAME with the name of the Pod.

  3. Verify that the file exists:

    kubectl exec POD_NAME -- sh -c 'cat /usr/share/hello/hello.txt'
    

    The output is similar to the following:

    Hello World!
    

Create a VolumeSnapshotClass object

Create a VolumeSnapshotClass object to specify the CSI driver and deletionPolicy for your volume snapshot. You can reference VolumeSnapshotClass objects when you create VolumeSnapshot objects.

  1. Save the following manifest as volumesnapshotclass.yaml. You can use either API version v1beta1 or v1 depending on the version of GKE on your cluster.

    v1beta1

    Use the v1beta1 API version for clusters running versions 1.21 or earlier.

    apiVersion: snapshot.storage.k8s.io/v1beta1
    kind: VolumeSnapshotClass
    metadata:
      name: my-snapshotclass
    driver: pd.csi.storage.gke.io
    deletionPolicy: Delete
    

    v1

    Use the v1 API version for clusters running versions 1.21 or later.

    apiVersion: snapshot.storage.k8s.io/v1
    kind: VolumeSnapshotClass
    metadata:
      name: my-snapshotclass
    driver: pd.csi.storage.gke.io
    deletionPolicy: Delete
    

    In this example:

    • The driver field is the CSI driver to use to provision the snapshot. pd.csi.storage.gke.io uses the Compute Engine persistent disk CSI Driver.

    • ThedeletionPolicy field tells GKE what to do with the VolumeSnapshotContent object and the underlying snapshot when the bound VolumeSnapshot object is deleted. Specify Delete to delete the VolumeSnapshotContent object and the underlying snapshot. You can also specify Retain if you want to keep the VolumeSnapshotContent and underlying snapshot.

    To use a custom storage location, add a storage-locations parameter to the snapshot class (this requires cluster version 1.21 or later).

    apiVersion: snapshot.storage.k8s.io/v1
    kind: VolumeSnapshotClass
    metadata:
      name: my-snapshotclass
    parameters:
      storage-locations: us-east2
    driver: pd.csi.storage.gke.io
    deletionPolicy: Delete
    
  2. Apply the manifest:

    kubectl apply -f volumesnapshotclass.yaml
    

Create a VolumeSnapshot

A VolumeSnapshot object is a request for a snapshot of an existing PersistentVolumeClaim object. When you create a VolumeSnapshot object, GKE automatically creates and binds it with a VolumeSnapshotContent object, which is a resource in your cluster like a PersistentVolume object.

  1. Save the following manifest as volumesnapshot.yaml. You can use API version v1beta1 or v1.

    v1beta1

    Use the v1beta1 API version for clusters running versions 1.21 or earlier.

    apiVersion: snapshot.storage.k8s.io/v1beta1
    kind: VolumeSnapshot
    metadata:
      name: my-snapshot
    spec:
      volumeSnapshotClassName: my-snapshotclass
      source:
        persistentVolumeClaimName: my-pvc
    

    v1

    Use the v1 API version for clusters running versions 1.21 or later.

    apiVersion: snapshot.storage.k8s.io/v1
    kind: VolumeSnapshot
    metadata:
      name: my-snapshot
    spec:
      volumeSnapshotClassName: my-snapshotclass
      source:
        persistentVolumeClaimName: my-pvc
    
  2. Apply the manifest:

    kubectl apply -f volumesnapshot.yaml
    

    After you create a volume snapshot, GKE creates a corresponding VolumeSnapshotContent object in the cluster. This object stores the snapshot and bindings of VolumeSnapshot objects. You do not interact with VolumeSnapshotContents objects directly.

  3. To confirm that GKE created the VolumeSnapshotContents object, run the following command:

    kubectl get volumesnapshotcontents
    

    The output is similar to the following:

    NAME                                               AGE
    snapcontent-cee5fb1f-5427-11ea-a53c-42010a1000da   55s
    

After the volume snapshot content is created, the CSI driver you specified in the VolumeSnapshotClass creates a snapshot on the corresponding storage system. After GKE creates a snapshot on the storage system and binds it to a volume snapshot object on the cluster, the snapshot is ready to use. You can check the status by running the following command:

kubectl get volumesnapshot \
  -o custom-columns='NAME:.metadata.name,READY:.status.readyToUse'

If it's ready to use, the output is similar to the following:

NAME               READY
my-snapshot        true

Delete the test file

  1. Delete the test file you created:

    kubectl exec POD_NAME -- sh -c 'rm /usr/share/hello/hello.txt'
    
  2. Verify that the file no longer exists:

    kubectl exec POD_NAME -- sh -c 'cat /usr/share/hello/hello.txt'
    

    The output is similar to the following:

    cat: /usr/share/hello/hello.txt: No such file or directory
    

Restore the volume snapshot

You can reference a VolumeSnapshot in a PersistentVolumeClaim to provision a new volume with data from an existing volume or restore a volume to a state that you captured in the snapshot.

To reference a VolumeSnapshot in a PersistentVolumeClaim, add the dataSource field to your PersistentVolumeClaim.

In this example, you reference the VolumeSnapshot you created in a new PersistentVolumeClaim and update the Deployment to use the new claim.

  1. Save the following manifest as pvc-restore.yaml:

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: pvc-restore
    spec:
      dataSource:
        name: my-snapshot
        kind: VolumeSnapshot
        apiGroup: snapshot.storage.k8s.io
      storageClassName: standard-rwo
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 1Gi
    
  2. Apply the manifest:

    kubectl apply -f pvc-restore.yaml
    
  3. Update my-deployment.yaml to use the new PersistentVolumeClaim:

    ...
    volumes:
    - name: my-volume
      persistentVolumeClaim:
        claimName: pvc-restore
    
  4. Apply the updated manifest:

    kubectl apply -f my-deployment.yaml
    

Check that the snapshot restored successfully

To check that the snapshot was successfully restored, get the name of the new Pod GKE creates for the updated Deployment:

kubectl get pods -l app=hello-app

Verify that the test file exists:

kubectl exec NEW_POD_NAME -- sh -c 'cat /usr/share/hello/hello.txt'

Replace NEW_POD_NAME with the name of the new Pod GKE created.

The output is similar to the following:

Hello World!

Cleaning up

  1. Delete the VolumeSnapshot:

    kubectl delete volumesnapshot my-snapshot
    
  2. Delete the VolumeSnapshotClass:

    kubectl delete volumesnapshotclass my-snapshotclass
    
  3. Delete the Deployment:

    kubectl delete deployments hello-app
    
  4. Delete the PersistentVolumeClaim objects:

    kubectl delete pvc my-pvc pvc-restore
    

What's next