Tech ONTAP Blogs
Tech ONTAP Blogs
In a recent blog post, we introduced the advanced data management and protection capabilities of NetApp® Trident™ protect software for stateful Kubernetes applications. We discussed how its Kubernetes-native custom resources (CRs) can help to integrate application protection into your automation and deployment workflows.
This blog post shows you how to easily manage, protect, and restore a stateful Kubernetes application using Trident protect’s CLI tridentctl-protect.
This blog post assumes that you’re working with the default admin user. In an upcoming blog post, we’ll show you how Trident protect’s role-based access model enables you to isolate tenant user activity while using ’s capabilities.
If you plan to follow this blog step by step, you need to have the following available:
Before using the command line utility, you need to install it on the machine you use to access your cluster. Follow these steps, depending on if your machine uses an x64 or ARM CPU.
$ curl -L -o tridentctl-protect https://github.com/NetApp/tridentctl-protect/releases/download/24.10.0/tridentctl-protect-linux-amd64
$ curl -L -o tridentctl-protect https://github.com/NetApp/tridentctl-protect/releases/download/24.10.0/tridentctl-protect-linux-arm64
$ curl -L -o tridentctl-protect https://github.com/NetApp/tridentctl-protect/releases/download/24.10.0/tridentctl-protect-macos-amd64
$ curl -L -o tridentctl-protect https://github.com/NetApp/tridentctl-protect/releases/download/24.10.0/tridentctl-protect-macos-arm64
Then enable execute permissions for the binary you just downloaded:
$ chmod +x ./tridentctl-protect
And copy the binary into any folder that is in your PATH environment on your desktop machine.
Before we can manage and protect the first application, we need to define at least one appVault CR corresponding to an existing object storage bucket, because buckets are used to store application (and snapshot) metadata in addition to backup data by Trident protect.
The following example configures an appVault CR demo backed by an Azure storage container demo in the Azure storage account putest. First, we create a secret containing the accountName and accountKey of the Azure storage account in the default trident-protect namespace:
$ kubectl -n trident-protect create secret generic bucket-demo --from-literal=accountName=putest --from-literal=accountKey=<ACCOUNT-KEY>
With the secret in place, we now create the appVault CR using the tridentctl-protect create appvault subcommand:
$ tridentctl-protect create appvault azure demo --account puneptunetest --bucket demo --endpoint core.windows.net --secret bucket-demo
We check the successful creation of the appVault CR:
$ tridentctl-protect get appvault
+------+----------+-----------+-----+-------+
| NAME | PROVIDER | STATE | AGE | ERROR |
+------+----------+-----------+-----+-------+
| demo | Azure | Available | 9s | |
+------+----------+-----------+-----+-------+
With an appVault CR configured, we’re ready to manage our first application with Trident protect. As a sample application for the purpose of this blog post, we use a simple WordPress application deployed on an Azure Kubernetes Service (AKS) cluster in the namespace wordpress with two persistent volumes provisioned through Trident and backed by Azure NetApp Files volumes:
$ kubectl get all,pvc,volumesnapshots -n wordpress
NAME READY STATUS RESTARTS AGE
pod/wordpress-64955d44c7-hxcpv 1/1 Running 4 (47h ago) 2d
pod/wordpress-mariadb-0 1/1 Running 0 2d
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/wordpress LoadBalancer 10.0.126.27 20.61.36.107 80:31547/TCP,443:30778/TCP 2d
service/wordpress-mariadb ClusterIP 10.0.131.236 <none> 3306/TCP 2d
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/wordpress 1/1 1 1 2d
NAME DESIRED CURRENT READY AGE
replicaset.apps/wordpress-64955d44c7 1 1 1 2d
NAME READY AGE
statefulset.apps/wordpress-mariadb 1/1 2d
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
persistentvolumeclaim/data-wordpress-mariadb-0 Bound pvc-3ca3230a-bbd3-42fd-9eba-9b2f91aa7293 100Gi RWO netapp-anf-perf-premium <unset> 2d
persistentvolumeclaim/wordpress Bound pvc-46c277a5-ac29-48b4-bffd-c78e1d2ec7cf 100Gi RWO netapp-anf-perf-premium <unset> 2d
If your cluster already has any other test application with Trident-provisioned persistent volumes running on it, feel free to use it instead.
Managing this single-namespaced application is as simple as this:
$ tridentctl-protect create application wordpress --namespaces wordpress -n wordpress
Application wordpress created.
The tridentctl-protect command just shown creates the corresponding application CR for us:
$ kubectl -n wordpress get application wordpress -o yaml
apiVersion: protect.trident.netapp.io/v1
kind: Application
metadata:
creationTimestamp: "2024-10-15T13:49:02Z"
finalizers:
- protect.trident.netapp.io/finalizer
generation: 1
name: wordpress
namespace: wordpress
resourceVersion: "9570159"
uid: cb0d2eda-abda-41be-ab9d-0a12b581c4f3
spec:
includedNamespaces:
- labelSelector: {}
namespace: wordpress
status:
conditions:
- lastTransitionTime: "2024-10-15T13:49:02Z"
message: ""
reason: Ready
status: "True"
type: Ready
protectionState: none
Trident protect enforces to create the application data management CRs in the same namespace as their associated application, so we create it in the wordpress namespace.
We can list all managed applications by adding the -A flag to the tridentctl-protect command:
$ tridentctl-protect get apps -A
+-----------+-----------+------------+-------+-----+
| NAMESPACE | NAME | NAMESPACES | STATE | AGE |
+-----------+-----------+------------+-------+-----+
| wordpress | wordpress | wordpress | Ready | 33s |
+-----------+-----------+------------+-------+-----+
For a more complex application covering multiple namespaces, we’d simply specify all the namespaces to be included in the application definition as a comma-separated list after the --namespaces flag and create the application CR in one of these namespaces. The --csr flag allows you to include cluster-scoped resources into the definition of the application, and if you want to include only resources matching the specified key/value pairs, you can include label selectors in parentheses after each namespace. The following example includes only the MariaDB resources of the wordpress application namespace, labeled by app.kubernetes.io/name=mariadb:
$ tridentctl-protect create application wordpress-db --namespaces 'wordpress(app.kubernetes.io/name=mariadb)' -n wordpress
The resulting application CR spec is:
$ kubectl -n wordpress get application wordpress-db -o yaml | yq '.spec'
includedNamespaces:
- labelSelector:
matchLabels:
app.kubernetes.io/name: mariadb
namespace: wordpress
Now that our application is defined, let’s perform some application data management operations on it.
We’ve successfully managed our application by creating an application CR. We can now carry out any other application data management operation in the same manner, and we’ll start with a snapshot.
Execute the following command in your terminal to create the first snapshot wordpress-snap-1 of our sample application.
$ tridentctl-protect create snapshot wordpress-snap-1 --app wordpress --appvault demo -n wordpress
Besides the snapshot and application name, we also need to specify the appVault CR to instruct tridentctl-protect to store the application metadata in this appVault (or bucket).
Even though the application metadata is stored in an external bucket for a snapshot, the Kubernetes persistent volumes are still stored locally on the cluster through Container Storage Interface (CSI) volume snapshots. This means that if the namespace or cluster is destroyed, so will the application snapshot data. This is the key difference between a snapshot and a backup, where the volume snapshot data is also stored on the referenced bucket.
Let’s make sure that our snapshot completed successfully by running the following command. Again, by adding the -A flag, we check snapshots in all available namespaces.
$ tridentctl-protect get snapshots --app wordpress -A
+-----------+------------------+-----------+-----------+-----+-------+
| NAMESPACE | NAME | APP REF | STATE | AGE | ERROR |
+-----------+------------------+-----------+-----------+-----+-------+
| wordpress | wordpress-snap-1 | wordpress | Completed | 31s | |
+-----------+------------------+-----------+-----------+-----+-------+
So, we have successfully taken an application snapshot from our CR definition. Next, let’s make this snapshot more robust in case of a disaster.
As mentioned in the previous section, if our wordpress namespace or the Kubernetes cluster is destroyed, we’ll lose our application’s persistent volumes, including their snapshots. Let’s change that by applying the following command to create a backup from the snapshot we just created.
$ tridentctl-protect create backup wordpress-bkup-1 --app wordpress --appvault demo -n wordpress
Specifying the snapshot is optional; if it isn’t specified, a new snapshot will first be created before the data is copied from the snapshot to the referenced appVault.
We can check the status of the backup with this command and confirm that it completed successfully after some minutes.
$ tridentctl-protect get backup --app wordpress -A
+-----------+------------------+-----------+-----------+-------+-------+
| NAMESPACE | NAME | APP REF | STATE | AGE | ERROR |
+-----------+------------------+-----------+-----------+-------+-------+
| wordpress | wordpress-bkup-1 | wordpress | Completed | 5m44s | |
+-----------+------------------+-----------+-----------+-------+-------+
If we want to protect our application by regularly taking snapshots and backups, we can assign one (or multiple) protection schedules to it. The following command assigns a protection schedule to our sample app that creates a daily snapshot and backup at 17:30 UTC and retains the last three snapshots and backups.
$ tridentctl-protect create schedule wordpress-sched --app wordpress --appVault demo --granularity daily --hour 17 --minute 30 --snapshot-retention 3 --backup-retention 3 -n wordpress
Note that if we don’t specify a name for the schedule, tridentctl-protect will create a unique name for it. The following command shows us all protection schedules assigned to the application wordpress.
$ tridentctl-protect get schedule --app wordpress -A
+-----------+-----------------+-----------+----------------------+---------+-------+-----+-------+
| NAMESPACE | NAME | APP | SCHEDULE | ENABLED | STATE | AGE | ERROR |
+-----------+-----------------+-----------+----------------------+---------+-------+-----+-------+
| wordpress | wordpress-sched | wordpress | Daily:hour=17,min=30 | true | | 24s | |
+-----------+-----------------+-----------+----------------------+---------+-------+-----+-------+
Trident protect allows you to restore your protected application completely or partially from snapshots or backups, either on the same cluster, across clusters, to different namespaces or the same namespace, or to the same or a different storage class. With our sample application protected by a snapshot and a backup, we can now go through some of the possible restore scenarios using the tridentctl-protect utility.
You might remember that when doing restores using the Trident protect CRs, the first step is always to find the appArchivePath of the snapshot or backup to restore from. Luckily, the tridentctl-protect CLI will do this in the background for us, so restores are much more comfortable.
This simple command restores our sample application from the snapshot wordpress-snap-1 into the namespace wordpress-restore-1.
$ tridentctl-protect create snapshotrestore wordpress-restore-1 --namespace-mapping wordpress:wordpress-restore-1 --snapshot wordpress/wordpress-snap-1 -n wordpress-restore-1
The namespace mapping wordpress:wordpress-restore-1 instructs tridentctl-protect to restore resource definitions from the original namespace wordpress in the namespace wordpress-restore-1, which will be created by tridentctl-protect. Note that we create the snapshotrestore CR in the new namespace of the restored application.
A restore from backup works in an analogous way, except that we use the create backuprestore subcommand and obviously specify the backup to restore from, as shown here:
$ tridentctl-protect create backuprestore wordpress-restore-2 --namespace-mapping wordpress:wordpress-restore-2 --backup wordpress/wordpress-bkup-1 -n wordpress-restore-2
If we want to select only certain resources of the application to restore either from a snapshot or backup, we can add filtering options that include or exclude resources of certain kinds or marked with particular labels by adding the --resource-filter-exclude and --resource-filter-include flags to the tridentctl-protect restore command.
For example, the following command would exclude all secrets from the restore.
$ tridentctl-protect create backuprestore wordpress-restore-nosecrets --namespace-mapping wordpress:wordpress-restore-nosecrets --backup wordpress-bkup-1 --resource-filter-exclude '[{"Kind":"Secret","Version":"v1"}]' -n wordpress-restore-nosecrets
Another handy flag is --storage-class-mapping, which allows you to migrate the persistent volumes to a different storage class during a restore operation. For example, this command would restore our wordpress application persistent volumes from the storage class netapp-anf-perf-premium into the storage class netapp-anf-perf-standard:
$ tridentctl-protect create backuprestore wordpress-restore-scmig --namespace-mapping wordpress:wordpress-standard --backup wordpress-bkup-1 --storageclass-mapping netapp-anf-perf-premium:netapp-anf-perf-standard -n wordpress-restore-scmig
When restoring an application from a backup or snapshot to its original namespace on the same cluster, Trident protect first stops the application and removes its resources from the namespace. Then it restores the data from a backup or snapshot, and finally restores the application metadata. To do this, we use tridentctl-protect’s backupinplacerestore and snapshotinplacerestore subcommands or their convenient aliases bir and sir. So, this command will restore wordpress from its backup into the original namespace:
$ tridentctl-protect create bir wordpress-bir-1 --backup wordpress/wordpress-bkup-1 -n wordpress
Restoring from a backup to a different cluster can be a bit tedious if the original backup CR is not available—for example, if the original cluster was lost due to a disaster. In such a scenario, information about available backups and details like the appArchivePath information would need to be found by browsing the information stored in the object storage bucket. Thankfully, tridentctl-protect offers an option to comfortably find the necessary information from the backups in object storage.
In this section, we show how you can restore your application to a different cluster if the backup CRs are not available for some reason.
The destination cluster must obviously have Trident protect installed, access to the object storage bucket containing the backup, and the respective appVault CR defined.
First, we check for the existence and availability of the appVault CR on our second cluster pu-aks-northeu by using the --context flag.
$ tridentctl-protect get appvault --context pu-aks-northeu
+-------+----------+-----------+-------+-------+
| NAME | PROVIDER | STATE | AGE | ERROR |
+-------+----------+-----------+-------+-------+
| demo | Azure | Available | 6d1h | |
| test3 | Azure | Available | 1d20h | |
+-------+----------+-----------+-------+-------+
We also make sure that the namespace we’ll restore the application into does not exist on the destination cluster.
Now we can browse the backup contents of our appVault demo from the target cluster:
$ tridentctl-protect get appvaultcontent demo --show-resources backup --show-paths --context pu-aks-northeu
+---------------+-----------+--------+-------------------------+---------------------------+---------------------------------------------------------------------------------------------------------------------+
| CLUSTER | APP | TYPE | NAME | TIMESTAMP | PATH |
+---------------+-----------+--------+-------------------------+---------------------------+---------------------------------------------------------------------------------------------------------------------+
| pu-aks-westeu | wordpress | backup | wordpress-bkup-1 | 2024-10-30 08:37:40 (UTC) | wordpress_3b9abe58-59c1-48d7-a6e8-6bc02eb1e5b3/backups/wordpress-bkup-1_e52def64-e69c-4ac6-8020-6d36e8e97b96 |
| pu-aks-westeu | wordpress | backup | wordpress-bkup-restic-1 | 2024-10-30 08:43:03 (UTC) | wordpress_3b9abe58-59c1-48d7-a6e8-6bc02eb1e5b3/backups/wordpress-bkup-restic-1_cad87a5d-25ab-4a87-8601-558d0ec38654 |
+---------------+-----------+--------+-------------------------+---------------------------+---------------------------------------------------------------------------------------------------------------------+
The output shows us the available backups in the appVault, their originating clusters, the corresponding application name, timestamp, and appArchivePath. With this information at hand, it’s now a simple task to restore our sample application to the destination cluster by providing the appVault name and appArchivePath information to the tridentctl-protect create backuprestore command:
$ tridentctl-protect create backuprestore wordpress-restore --namespace-mapping wordpress:wordpress --appvault demo --path wordpress_3b9abe58-59c1-48d7-a6e8-6bc02eb1e5b3/backups/wordpress-bkup-1_e52def64-e69c-4ac6-8020-6d36e8e97b96 -n wordpress --context pu-aks-northeu
We can also filter the listed backups by using the --app flag, which is helpful in real-life scenarios with larger environments and more backups.
Finally, let’s take a look at three more options and subcommands of tridentctl-protect.
The get all subcommand creates a list of all Trident protect CRs configured on the cluster and accessible by the user executing the command.
$ tridentctl-protect get all -A
The --dry-run flag, which can be used with all create subcommands, prints only the object that’s about to be created, without actually sending it. This can be very helpful when you want to create more complex manifests to include in your automation workflows. For example, this command prints the manifest for a backuprestore CR with storage mapping and exclude filters:
$ tridentctl-protect create backuprestore wordpress-restore-scmig --namespace-mapping wordpress:wordpress-standard --backup wordpress-bkup-1 --storageclass-mapping netapp-anf-perf-premium:netapp-anf-perf-standard --resource-filter-exclude '[{"Kind":"Secret","Version":"v1"}]' -n wordpress-restore-mig --dry-run
apiVersion: protect.trident.netapp.io/v1
kind: BackupRestore
metadata:
creationTimestamp: null
name: wordpress-restore-scmig
namespace: wordpress-restore-mig
spec:
appArchivePath: wordpress_cb0d2eda-abda-41be-ab9d-0a12b581c4f3/backups/wordpress-bkup-1_01d063df-fe0a-4ff4-aee1-f5c544da6284
appVaultRef: demo
namespaceMapping:
- destination: wordpress-standard
source: wordpress
resourceFilter:
resourceMatchers:
- kind: Secret
version: v1
resourceSelectionCriteria: exclude
storageClassMapping:
- destination: netapp-anf-perf-standard
source: netapp-anf-perf-premium
status:
conditions: null
state: ""
Last, the --show-full-error flag enables you to see the full error message if a data management command fails, as in this example.
$ tridentctl-protect get snapshot -A
+--------------+---------+-------+--------+-------------------------+
| NAME | APP REF | STATE | AGE | ERROR |
+--------------+---------+-------+--------+-------------------------+
| pgsql-snap-1 | pgsql | Error | 10m34s | Application.protect.... |
+--------------+---------+-------+--------+-------------------------+
$ tridentctl-protect get snapshot --show-full-error -A
+--------------+---------+-------+--------+---------------------------------------+
| NAME | APP REF | STATE | AGE | ERROR |
+--------------+---------+-------+--------+---------------------------------------+
| pgsql-snap-1 | pgsql | Error | 10m45s | Application.protect.trident.netapp.io |
| | | | | "pgsql" not found |
+--------------+---------+-------+--------+---------------------------------------+
In summary, we installed the Trident protect CLI tridentctl-protect on our workstation and then showed how it simplifies ad hoc data management operations like backup and restore. We also showed how tridentctl-protect simplifies application restores to a different cluster in disaster recovery scenarios, where the original cluster or backup CR is no longer available.