Google Cloud with Google Cloud NetApp Volumes - Configuration

Updated

OpenShift Virtualization Storage Configuration for Google Cloud NetApp Volumes (GCNV)

Applicable to: OpenShift Virtualization 4.21.2+ on Red Hat OpenShift Container Platform 4.21+ (GCP) with NetApp Trident CSI driver.

Overview

Google Cloud NetApp Volumes (GCNV) provides NFS-based shared storage for OpenShift Virtualization workloads on Google Cloud. GCNV supports ReadWriteMany (RWX) in Filesystem mode, which enables VM live migration, and is provisioned through the NetApp Trident CSI driver.

Important: This guide covers the Flex File service level only. When creating storage pools, select the File storage type (not "Unified"). Flex Unified (which adds iSCSI/block support) is not covered in this release.

This guide walks you through Trident installation and configuration on an OpenShift cluster that already has GCNV resources provisioned on the Google Cloud side.

What you will do in this guide:

  1. Install Trident
  2. Create a TridentBackendConfig for GCNV
  3. Create the StorageClass
  4. Create a VolumeSnapshotClass
  5. Set the filesystem overhead
  6. Verify the setup

Prerequisites

Storage pool sizing: GCNV Flex pools are limited to 50 volumes per pool (Content from docs.cloud.google.com is not included.GCNV storage pool limits). Each Flex pool has a minimum capacity of 1 TiB. Create multiple pools and list them all in the TridentBackendConfig - Trident distributes volumes across pools automatically. For example, 4 pools support ~200 volumes, 16 pools support ~800 volumes.

For the full GCNV preparation checklist (service account, PSA, storage pools, API key), see Content from docs.netapp.com is not included.Prepare to configure a GCNV backend.

Configuration Steps

Step 1: Install Trident

Choose one of the two options below.

Option A: Via the OpenShift Web Console (operator)

  1. Navigate to Ecosystem > Software Catalog and search for "Trident"
  2. Install the NetApp Trident operator (version 26.02.0 or later)
  3. Once installed, go to Installed Operators and open Trident
  4. Click Create TridentOrchestrator
  5. Switch to YAML view, ensure the full CR looks like the following (add enableConcurrency: true), and click Create:
kind: TridentOrchestrator
apiVersion: trident.netapp.io/v1
metadata:
  name: trident
spec:
  IPv6: false
  debug: true
  nodePrep: []
  imagePullSecrets: []
  imageRegistry: ''
  namespace: trident
  silenceAutosupport: false
  enableConcurrency: true

For full details, see Content from docs.netapp.com is not included.Manually deploy the Trident operator.

Option B: Via tridentctl (CLI)

Download the Trident installer and run tridentctl install:

export TRIDENT_VERSION="26.02.0"

wget "https://github.com/NetApp/trident/releases/download/v${TRIDENT_VERSION}/trident-installer-${TRIDENT_VERSION}.tar.gz"
tar -xf "trident-installer-${TRIDENT_VERSION}.tar.gz"
cd trident-installer

./tridentctl install --enable-concurrency -n trident --kubeconfig "${KUBECONFIG}"

For full details, see Content from docs.netapp.com is not included.Install using tridentctl.

You can also install Trident using Helm. See Content from docs.netapp.com is not included.Use Trident Helm Chart for details.

Verify

Regardless of which option you chose, verify Trident is running:

oc get torc trident -o jsonpath='{.status.status}'

Expected output: Installed. Verify the pods:

oc get pods -n trident

You should see a trident-controller, trident-node-linux DaemonSet pods, and the trident-operator pod all in Running state.

Step 2: Create the Credentials Secret and TridentBackendConfig

This step creates the Secret and TridentBackendConfig together, following the pattern from the Content from docs.netapp.com is not included.official NetApp GCNV examples. The Secret holds the sensitive credential fields (private_key and private_key_id) from your trident-admin.json key file, and the TridentBackendConfig references it via credentials.name.

List all of your storage pools in the storagePools array - Trident will distribute volumes across them, which is critical given the 50-volume-per-pool limit. For the full list of backend configuration parameters, see Content from docs.netapp.com is not included.GCNV backend configuration options.

Get your GCP project number:

gcloud projects describe "${GCP_PROJECT_ID}" --format="value(projectNumber)"

Create a file named gcnv-backend-flex.yaml with the following content. Replace all <placeholder> values:

---
apiVersion: v1
kind: Secret
metadata:
  name: trident-admin
  namespace: trident
type: Opaque
stringData:
  private_key_id: "<private_key_id from trident-admin.json>"
  private_key: |
    -----BEGIN PRIVATE KEY-----
    <private_key from trident-admin.json>
    -----END PRIVATE KEY-----
---
apiVersion: trident.netapp.io/v1
kind: TridentBackendConfig
metadata:
  name: gcnv-backend-flex
  namespace: trident
spec:
  version: 1
  storageDriverName: google-cloud-netapp-volumes
  backendName: gcnv-flex
  projectNumber: "<your-project-number>"
  location: "<worker-node-zone>"
  storage:
    - labels:
        performance: flex
      serviceLevel: flex
  storagePools:
    - <pool-prefix>-flex-pool-1
    - <pool-prefix>-flex-pool-2
    - <pool-prefix>-flex-pool-3
    - <pool-prefix>-flex-pool-4
  apiKey:
    type: service_account
    project_id: "<your-gcp-project-id>"
    client_email: "<your-service-account>@<your-gcp-project-id>.iam.gserviceaccount.com"
    client_id: "<client-id-from-json>"
    auth_uri: https://accounts.google.com/o/oauth2/auth
    token_uri: https://oauth2.googleapis.com/token
    auth_provider_x509_cert_url: https://www.googleapis.com/oauth2/v1/certs
    client_x509_cert_url: "https://www.googleapis.com/robot/v1/metadata/x509/<your-service-account>%40<your-gcp-project-id>.iam.gserviceaccount.com"
  credentials:
    name: trident-admin

Tip: All the apiKey fields and the Secret stringData values come from your trident-admin.json file. You can extract the non-sensitive apiKey portion with:

jq 'del(.private_key_id, .private_key)' trident-admin.json

Note: backendName is a user-chosen friendly name for Trident's internal identification (visible in tridentctl get backend). It does not reference any external GCP resource. The StorageClass selects this backend via the selector: "performance=flex" parameter, which matches the labels.performance: flex defined in the storage section above.

Important: For Flex zonal pools, location must be the zone (e.g. us-central1-a). For Flex regional pools or Standard/Premium/Extreme, use the region (e.g. us-central1).

Note: The storagePools list is optional. If omitted, Trident will use any pool with the matching service level in the configured location. Explicitly listing pools is only necessary if you want to restrict which pools Trident uses (e.g. when pools in the same project/location are shared across clusters).

Apply both resources:

oc apply -f gcnv-backend-flex.yaml

Wait for the backend to become ready:

oc get tridentbackendconfig gcnv-backend-flex -n trident -o jsonpath='{.status.lastOperationStatus}'

Expected output: Success. If it shows Failed, check the backend details:

oc describe tridentbackendconfig gcnv-backend-flex -n trident

For more examples (virtual pools, SMB, topology), see Content from docs.netapp.com is not included.GCNV backend configuration examples.

Adding More Pools Later

When you need more volume capacity, Content from docs.cloud.google.com is not included.create additional storage pools in GCP and add their names to the storagePools list in the TridentBackendConfig:

oc edit tridentbackendconfig gcnv-backend-flex -n trident

Add the new pool name to spec.storagePools and save. Trident picks up the change automatically.

Step 3: Create the StorageClass

Create a StorageClass that uses the Trident backend. This is what users and CDI will reference when creating PVCs.

Create a file named gcnv-flex-storageclass.yaml with the following content:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gcnv-flex
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
    storageclass.kubevirt.io/is-default-virt-class: "true"
provisioner: csi.trident.netapp.io
parameters:
  backendType: "google-cloud-netapp-volumes"
  selector: "performance=flex"
allowVolumeExpansion: true

Apply:

oc apply -f gcnv-flex-storageclass.yaml

If the cluster already has a default StorageClass (e.g. standard-csi), remove the default annotation:

oc annotate storageclass standard-csi storageclass.kubernetes.io/is-default-class-

Verify only gcnv-flex is the default:

oc get storageclass

You should see gcnv-flex (default) in the output.

Step 4: Create the VolumeSnapshotClass

A VolumeSnapshotClass is required for VM snapshot and restore operations.

Create a file named gcnv-csi-snapclass.yaml with the following content:

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
  name: gcnv-csi-snapclass
driver: csi.trident.netapp.io
deletionPolicy: Delete

Apply:

oc apply -f gcnv-csi-snapclass.yaml

Step 5: Set the Filesystem Overhead

NFS volumes consume part of their provisioned capacity for filesystem metadata. The recommended filesystem overhead for GCNV is 10%. Without this, CDI may provision PVCs that are too small for operations that need temporary space (e.g. gzipped exports). See This content is not included.ONTAP Volume Space Reporting for details.

Patch the HyperConverged CR to set the overhead for the gcnv-flex StorageClass:

oc patch hyperconverged kubevirt-hyperconverged -n openshift-cnv --type=merge -p '
{
  "spec": {
    "filesystemOverhead": {
      "storageClass": {
        "gcnv-flex": "0.10"
      }
    }
  }
}'

Verify CDI picked up the new value:

oc get cdiconfig -o jsonpath='{.items[0].status.filesystemOverhead}'

You should see gcnv-flex listed with 0.10.

Verification

Run through these checks to confirm everything is working:

1. Trident pods are running:

oc get pods -n trident

All pods should be Running.

2. Backend is healthy:

oc get tridentbackendconfig -n trident

Status should show Bound and Success.

3. StorageClass exists and is default:

oc get storageclass gcnv-flex

4. VolumeSnapshotClass exists:

oc get volumesnapshotclass gcnv-csi-snapclass

5. Create a test PVC:

Create a file named gcnv-test-pvc.yaml with the following content:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: gcnv-test-pvc
  namespace: default
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
  storageClassName: gcnv-flex

Apply:

oc apply -f gcnv-test-pvc.yaml

Wait for it to bind:

oc get pvc gcnv-test-pvc -n default

Status should be Bound. Clean up:

oc delete pvc gcnv-test-pvc -n default

Quick Reference

ResourceNamePurpose
NamespacetridentTrident operator and controller pods
Secrettrident-adminGCP service account credentials
TridentBackendConfiggcnv-backend-flexConnects Trident to GCNV storage pools
StorageClassgcnv-flexDefault StorageClass for VM disks
VolumeSnapshotClassgcnv-csi-snapclassEnables VM snapshot/restore
HyperConverged patchfilesystemOverhead: gcnv-flex: "0.10"10% NFS filesystem overhead for CDI

Key Limitations

For known errors, quotas, and platform-level constraints, see Google Cloud with Google Cloud NetApp Volumes - Known errors and limits.

LimitValueNotes
Minimum volume size1 GiBUse minimumSupportedPvcSize in StorageProfile
Volumes per Flex pool50Use multiple pools in TridentBackendConfig
Volume modeFilesystem onlyNo block mode support (NFS backend)
Access modesRWO, RWX, ROXAll in Filesystem mode
fstrim / discardNot supportedNFS does not support TRIM

External References

Category
Components
Article Type