Replicating and Recovering Application
In this section we will deploy a sample workload, snapshot the Application components and recover.
- Same namespace recovery
- Cross namespace recovery
Deploying a Sample Application
-
On
VSCode
menu, selectTerminal
>New Terminal
-
Browse to
ndk
directory -
Source the .env file
-
Change to default namespace
-
Create a stateful workload
kubectl apply -f - <<EOF apiVersion: v1 kind: PersistentVolumeClaim metadata: labels: app: app1 name: az-claim-1 spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi EOF kubectl apply -f - <<EOF apiVersion: v1 kind: Pod metadata: name: app-1 labels: app: app1 spec: containers: - name: app image: docker.io/library/busybox:1.36.1 command: ["/bin/sh"] args: ["-c", "while true; do echo $(date -u) ; sleep 5; done"] volumeMounts: - name: persistent-storage mountPath: /data volumes: - name: persistent-storage persistentVolumeClaim: claimName: az-claim-1 EOF
-
Watch the workload components until they are running
-
Once the pvc and pod are running, inject some data into the persistent storage
Now we have a stateful workload which we can replicate and recover using NDK
NDK Recover to the Same Namespace
Tip
NDK uses labels to select kubernetes resources to act upon.
-
Define a NDK
Application
custom resource to replicate our deployed application with labelapp1
-
Take a local cluster snapshot of the
app1
application -
View the progress
Wait until the status of snapshot becomes true$ k get applicationsnapshot -w NAME AGE READY-TO-USE BOUND-SNAPSHOTCONTENT SNAPSHOT-AGE app1-snap 11s false asc-8af85cca-3da7-468c-96fb-db54ec2cf940 app1-snap 37s true asc-8af85cca-3da7-468c-96fb-db54ec2cf940 36s
Observe the Application components that are included and statusName: app1-snap Namespace: default API Version: dataservices.nutanix.com/v1alpha1 Kind: ApplicationSnapshot Metadata: Creation Timestamp: 2025-07-08T01:34:41Z Spec: Expires After: 48h0m0s Source: Application Ref: Name: app-1 Status: Bound Application Snapshot Content Name: asc-3c1e253a-266d-46fd-8559-d8aa189fea78 Creation Time: 2025-07-08T01:35:13Z Expiration Time: 2025-07-10T01:35:13Z Ready To Use: true Summary: Snapshot Artifacts: cilium.io/v2/CiliumEndpoint: Name: app-1 v1/PersistentVolumeClaim: Name: az-claim-1 v1/Pod: Name: app-1 Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal AcquireAppConfigWaiting 2m47s NDK ApplicationSnapshotContent's app config acquisition is waiting to be processed Normal VolumeSnapshotWaiting 2m45s NDK ApplicationSnapshotContent's volume snapshot phase is waiting to be processed Normal FinalizeSnapshotWaiting 2m16s NDK ApplicationSnapshotContent's finalize phase is waiting to be processed
Relationship between NDK custom resources
We can observe that the
ApplicationSnapshot
andApplicationSnapshotContent
NDK custom resources are related.ApplicationSnapshotContent
also shows the Nutanix infrastructure components of theApplicationSnapshot
custom resources such as Nutanix volumes.Refer to the highlighted parts in the following command output.
kubectl get ApplicationSnapshot NAMESPACE NAME AGE READY-TO-USE BOUND-SNAPSHOTCONTENT SNAPSHOT-AGE default app1-snap 4h33m true asc-8af85cca-3da7-468c-96fb-db54ec2cf940 4h33m
kubectl get ApplicationSnapshotContent -oyaml apiVersion: v1 items: - apiVersion: dataservices.nutanix.com/v1alpha1 kind: ApplicationSnapshotContent metadata: creationTimestamp: "2025-07-08T02:00:06Z" finalizers: - dataservices.nutanix.com/app-snap - dataservices.nutanix.com/app-snap-content generation: 1 name: asc-8af85cca-3da7-468c-96fb-db54ec2cf940 resourceVersion: "7484635" uid: 9ed65107-b400-4d75-9acd-c0a7a0aede81 spec: applicationSnapshotRef: name: app1-snap namespace: default source: applicationRef: name: app-1 namespace: default status: applicationSnapshotSummary: applicationSnapshotHandle: name: asc-8af85cca-3da7-468c-96fb-db54ec2cf940 volumeClaimHandleMap: az-claim-1: NutanixVolumes-0d77026f-f513-4b20-4c4f-822d31e0c4d4 volumeSnapshotHandleMap: NutanixVolumes-0d77026f-f513-4b20-4c4f-822d31e0c4d4: 5acbcd9e-fde3-4fe5-aabd-11a4b080a044:ea8518bb-3453-4748-bbd0-713eb9358c5b
-
The NDK controller manager will also have logs of the snapshot operation. This will be useful for troubleshooting purposes
$ kubectl logs -f -n ntnx-system deploy/ndk-controller-manager {"level":"info","timestamp":"2025-07-08T01:35:12.909Z","caller":"applicationsnapshotcontent/asc_finalize.go:38","msg":"resource regulated: ApplicationSnapshotContent's finalize phase is waiting to be processed","controller":"applicationsnapshotcontent","controllerGroup":"dataservices.nutanix.com","controllerKind":"ApplicationSnapshotContent","ApplicationSnapshotContent":{"name":"asc-3c1e253a-266d-46fd-8559-d8aa189fea78"},"namespace":"","name":"asc-3c1e253a-266d-46fd-8559-d8aa189fea78","reconcileID":"a0cf1641-40d7-4d51-b948-10cf9bae84e0","requestId":"7566b4fa-0eda-4ffd-b34e-76daf2311148"} {"level":"info","timestamp":"2025-07-08T01:35:13.381Z","caller":"utils/controller.go:36","msg":"Ensuring finalizer on objects","controller":"applicationsnapshot","controllerGroup":"dataservices.nutanix.com","controllerKind":"ApplicationSnapshot","ApplicationSnapshot":{"name":"app1-snap","namespace":"default"},"namespace":"default","name":"app1-snap","reconcileID":"5af23527-5d34-4992-ab02-99ba4af2a401","finalizer":"dataservices.nutanix.com/app-snap-2a003355dcfd33a75426095a4a71154b"}
-
Observe the event
Create Recovery Point
operation in Prism Central -
Delete the app to simulate a failure
-
Restore the app from
applicationSnapshot
custom resource -
Monitor the progress of
ApplicationSnapshotRestore
custom resource -
Verify if app1 pvc and pod are restored
-
Check if data is present within the data mount
/data
inside the pod -
Observe the event
Restore Recovery Point
operation in Prism Central
Cross Namespace Recovery
NDK offers cross-namespace recovery capabilites. With this NKP or any supported K8s platform administrator can recover applicationSnapshot
custom resource to a different namespace within the same K8s cluster.
-
Create a referenceGrant resouce to grant permission to restore specific application snapshots from one namespace to another.
kubectl apply -f - <<EOF apiVersion: gateway.networking.k8s.io/v1beta1 kind: ReferenceGrant metadata: name: _reference_grant_name namespace: _source_namespace spec: from: - group: dataservices.nutanix.com kind: ApplicationSnapshotRestore namespace: _target_namespace to: - group: dataservices.nutanix.com kind: ApplicationSnapshot name: _appplication_snapshot_name EOF
kubectl apply -f - <<EOF apiVersion: gateway.networking.k8s.io/v1beta1 kind: ReferenceGrant metadata: name: cross-ns-rg namespace: default spec: from: - group: dataservices.nutanix.com kind: ApplicationSnapshotRestore namespace: restore to: - group: dataservices.nutanix.com kind: ApplicationSnapshot name: app1-snap EOF
-
Create a target namespace
-
Create and
applicationSnapshotRestore
custom resource to restore to targetrestore
namespace -
Monitor the progress of
ApplicationSnapshotRestore
custom resourceWait until the status of ApplicationSnapshotRestore custom resource is trueName: cross-ns-asr Namespace: restore API Version: dataservices.nutanix.com/v1alpha1 Kind: ApplicationSnapshotRestore Metadata: Creation Timestamp: 2025-07-08T05:40:31Z Finalizers: dataservices.nutanix.com/application-restore Generation: 1 Resource Version: 7484636 Spec: Application Snapshot Name: app1-snap Application Snapshot Namespace: default Status: Completed: true Conditions: Last Transition Time: 2025-07-08T05:40:31Z Message: Observed Generation: 1 Reason: RequestCompleted Status: False Type: Progressing Last Transition Time: 2025-07-08T05:40:31Z Message: All prechecks passed and finalizers on dependent resources set Observed Generation: 1 Reason: PrechecksPassed Status: True Type: PrechecksPassed Last Transition Time: 2025-07-08T05:40:31Z Message: Restore requests for all eligible volumes submitted Observed Generation: 1 Reason: VolumeRestoreRequestsSubmitted Status: True Type: VolumeRestoreRequestsSubmitted Last Transition Time: 2025-07-08T05:41:32Z Message: All eligible application configs restored Observed Generation: 1 Reason: ApplicationConfigRestored Status: True Type: ApplicationConfigRestored Last Transition Time: 2025-07-08T05:41:47Z Message: All eligible volumes restored Observed Generation: 1 Reason: VolumesRestored Status: True Type: VolumesRestored Last Transition Time: 2025-07-08T05:41:47Z Message: Application restore successfully finalised Observed Generation: 1 Reason: ApplicationRestoreFinalised Status: True Type: ApplicationRestoreFinalised Finish Time: 2025-07-08 05:41:47 Start Time: 2025-07-08 05:40:31
-
Verify if app1 pvc and pod are restored
-
Check if data is present within the data mount
/data
inside the pod
We have now successfully restored our application accross namespaces.