Install NDK with NKP

Nutanix Data Service for Kubernetes (NDK) เป็น service ที่ติดตั้งบน Kubernetes Cluster เพื่อทำการ backup application และ replicate ข้อมูลที่ถูก backup ไปยัง Kubernetes cluster ปลายทาง เพื่อให้สามารถ recovery ทั้ง application และข้อมูลได้ โดยใช้กับ use case เช่นการทำ DR โดยการ replicate ข้อมูลไปยังปลายทางมากกว่าหนึ่งปลายทาง การย้าย Application (Application migration) หรือ rebalancing application ไปยัง cluster ที่มี resource ที่เหมาะสม การ snapshots และ restore ภายใน cluster โดยสามารสร้าง schedule และรองรับการ replication ในแบบ near realtime ได้

CRD ที่มาด้วยกับ NDK

Application สำหรับกำหนดกลุ่มของ resource ที่จะทำการ snapshot หรือ replicate
ApplicationSnapshot สร้าง application snapshot สำหรับ source ที่ระบุ (application)
Remote จับคู่ของ NKP instance ระหว่างสอง cluster
ReplicationTarget กำหนด cluster และ namespace ของ cluster ปลายทาง
ApplicationSnapshotReplication ทำการ replicate snapshot ระหร่วง cluster
ApplicationSnapshotRestore ทำการ restore snapshot ที่ local cluster หรือ remote cluster
JobScheduler, ProtectionPlan กำหนด snapshot policy และการจัดเก็บ (retention)
StorageCluster กำหนด Infrastructure ที่จะ support การทำ snapshot และ replication ระหว่าง cluster หรือภายใน cluster

การติดตั้ง NDK โดยต้องติดตั้งทั้ง Kuberntes Cluster ต้นทาง และ Kubernetes Cluster ปลายทาง

ขั้นตอนการติดตั้ง NDK ที่ Kubernetes ต้นทาง

เข้าไปที่ Nutanix Portal เพื่อ copy Download Link เพื่อทำการ download install package และทำการจัดเก็บไว้ใน private registry ภายในสำหรับใช้ในการการติดตั้ง

[nutanix@harbor ~]$ curl -o ndk-1.2.0.tar "https://download.nutanix.com/downloads/ndk/1.2.0/ndk-1.2.0.tar?Expires=1752582997&Key-Pair-Id=APKAJTTNCWPEI42QKMSA&Signature=CGOEgIDQHcJ1fTI8nIMbB5mcrM~5jPFcfS~5PyKDFGQyeNGlfBHyookKrzTTearX6L1aLLyEL6psYlkYIZdDlGIghHQuyb5qQBcxVGqiJ2ENuJD2MZKJkBFb6gnJ5s0JynyfkReAwPU5Ls4Vwb9yZXhzROm25Adezn-noLnkQUpLYQkyNl3~3n3X6xWR7qQQhHbo~QH3GEmYylmfsAcfx78WrH6-t9q3AV-2vhOGFNFz8k4gueqbRAjcLiKJBe7pJ-MlQ1KCo2ZYQMg3OACgqx7epi-2t0ImmpKs0I3rGa0lBqccOggX3n0tfaSED1cwTyjFRRpgFGYWZRX0qdrCvQ__"
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  526M  100  526M    0     0  22.5M      0  0:00:23  0:00:23 --:--:-- 30.1M

unzip file ที่ทำการ download มา

[nutanix@harbor ~]$ tar -xvf ndk-1.2.0.tar

Load container เข้าไปยังระบบของ docker

[nutanix@harbor ~]$ docker image load -i ndk-1.2.0/ndk-1.2.0.tar

ทำการ tag container ที่ load เข้าไปในระบบและ push เข้าไปยัง container private registry ที่เตรียมไว้

[nutanix@harbor ~]$ docker image tag ndk/manager:1.2.0 10.38.53.107/ndk/manager:1.2.0
[nutanix@harbor ~]$ docker image tag ndk/infra-manager:1.2.0 10.38.53.107/ndk/infra-manager:1.2.0
[nutanix@harbor ~]$ docker image tag ndk/job-scheduler:1.2.0 10.38.53.107/ndk/job-scheduler:1.2.0
[nutanix@harbor ~]$ docker image tag ndk/kube-rbac-proxy:v0.17.0 10.38.53.107/ndk/kube-rbac-proxy:v0.17.0
[nutanix@harbor ~]$ docker image tag ndk/bitnami-kubectl:1.30.3 

[nutanix@harbor ~]$ docker push 10.38.53.107/ndk/manager:1.2.0
[nutanix@harbor ~]$ docker push 10.38.53.107/ndk/infra-manager:1.2.0
[nutanix@harbor ~]$ docker push 10.38.53.107/ndk/job-scheduler:1.2.0
[nutanix@harbor ~]$ docker push 10.38.53.107/ndk/kube-rbac-proxy:v0.17.0
[nutanix@harbor ~]$ docker push 10.38.53.107/ndk/bitnami-kubectl:1.30.3

ทำการ set environment variable เพื่อ install ndk

[nutanix@harbor ~]$ cd ~/ndk-1.2.0
[nutanix@harbor ~]$ export CLUSTER_NAME=<<NKP cluster to install NDK on>>
[nutanix@harbor ~]$ export KUBECONFIG=~/nkp-v2.15.0/cli/${CLUSTER_NAME}.conf
[nutanix@harbor ~]$ export LOCAL_REG=<<registry hostname/IP>>:<<port>>

ตรวจสอบว่ามี Nutanix CSI credentials secret ในระบบแล้ว ทั้งนี้ nutanix-csi-credentials จะมีอยู่แล้วถ้า NKP ถูกติดตั้งใช้งานกับ Nutanix Infra Provider

kubectl get secret -n ntnx-system

ถ้าไม่มีต้องสร้างด้วย yaml โดยที่ key คือ base64 encoding ของ “<<PC hostname/IP>>:9440:<<PC userid>>:<<PC userid password>>”

apiVersion: v1
data:
  key: <<encoded creds>>
kind: Secret
metadata:
  name: nutanix-csi-credentials
  namespace: ntnx-system
type: Opaque

ติดตั้ง ndk ด้วย helm cli

helm install ndk -n ntnx-system chart/ \
--set manager.repository=${LOCAL_REG}/ndk/manager \
--set manager.tag=1.2.0 \
--set infraManager.repository=${LOCAL_REG}/ndk/infra-manager \
--set infraManager.tag=1.2.0 \
--set kubeRbacProxy.repository=${LOCAL_REG}/ndk/kube-rbac-proxy \ 
--set kubeRbacProxy.tag=v0.17.0 \
--set bitnamiKubectl.repository=${LOCAL_REG}/ndk/bitnami-kubectl \ 
--set bitnamiKubectl.tag=1.30.3 \
--set jobScheduler.repository=${LOCAL_REG}/ndk/job-scheduler \
--set jobScheduler.tag=1.2.0 \
--set tls.server.clusterName=${CLUSTER_NAME} \
--set config.secret.name=nutanix-csi-credentials

ตัวอย่างค่าที่ใช้ในการติดตั้งครั้งนี้

[nutanix@harbor ndk-1.2.0]$ helm install ndk -n ntnx-system chart/ \
--set manager.repository=10.38.53.107/ndk/manager \
--set manager.tag=1.2.0 \
--set infraManager.repository=10.38.53.107/ndk/infra-manager \
--set infraManager.tag=1.2.0 \
--set kubeRbacProxy.repository=10.38.53.107/ndk/kube-rbac-proxy \
--set kubeRbacProxy.tag=v0.17.0 \
--set bitnamiKubectl.repository=10.38.53.107/ndk/bitnami-kubectl \
--set bitnamiKubectl.tag=1.30.3 \
--set jobScheduler.repository=10.38.53.107/ndk/job-scheduler \
--set jobScheduler.tag=1.2.0 \
--set tls.server.clusterName=nkp-at-next \
--set config.secret.name=nutanix-csi-credentials

ตรวจสอบการติดตั้งด้วยการ get pod ndk-controller-manager ว่าทำงานได้ปกติหรือไม่

[nutanix@harbor ndk-1.2.0]$ kubectl get pod -n ntnx-system
NAME                                      READY   STATUS    RESTARTS   AGE
ndk-controller-manager-79687849d5-8vxdh   4/4     Running   0          22s

สร้าง StorageCluster ของทั้งสอง Kubernetes Cluster ที่ต้องการทำ replication ระหว่างกัน โดย Kubernetes Cluster ที่สองจะต้องติดตั้ง NDK ให้สมบูรณ์ตามตัวอย่างข้างต้น

cd ~/nkp-v2.15.0/cli
export CLUSTER_NAME=<<NKP cluster name>>
export KUBECONFIG=~/nkp-v2.15.0/cli/${CLUSTER_NAME}.conf
export PE_UUID=<<PE UUID>>
export PC_UUID=<<PC UUID>>

cat << EOF >  ${CLUSTER_NAME}-storagecluster.yaml
apiVersion: dataservices.nutanix.com/v1alpha1
kind: StorageCluster
metadata:
 name: ${CLUSTER_NAME}
spec:
 storageServerUuid: ${PE_UUID}
 managementServerUuid: ${PC_UUID}
EOF

ตัวอย่างการสร้าง storage cluster

[nutanix@harbor ~]$ export KUBECONFIG=/home/nutanix/nkp-at-next.conf

[nutanix@harbor ~]$ cat << EOF >  nkp-at-next-storagecluster.yaml
apiVersion: dataservices.nutanix.com/v1alpha1
kind: StorageCluster
metadata:
 name: nkp-at-next
spec:
 storageServerUuid: 0006391e-0ad0-299a-70dd-ac1f6b3fddde
 managementServerUuid: f2b78299-aa10-43b9-94d5-faa3527e3897
EOF

[nutanix@harbor ~]$ k apply -f nkp-at-next-storagecluster.yaml
storagecluster.dataservices.nutanix.com/nkp-at-next created
[nutanix@harbor ~]$ k get storagecluster
NAME          AVAILABLE
nkp-at-next   true

สร้าง Storage Cluster ที่ Kubernetes Cluster ที่สอง

[nutanix@harbor ~]$ export KUBECONFIG=cluster2-kubeconfig.yaml

[nutanix@harbor ~]$ cat << EOF >  cluster2-storagecluster.yaml
apiVersion: dataservices.nutanix.com/v1alpha1
kind: StorageCluster
metadata:
 name: cluster2
spec:
 storageServerUuid: 0006391e-0ad0-299a-70dd-ac1f6b3fddde
 managementServerUuid: f2b78299-aa10-43b9-94d5-faa3527e3897
EOF

[nutanix@harbor ~]$ k apply -f cluster2-storagecluster.yaml
storagecluster.dataservices.nutanix.com/cluster2 created
[nutanix@harbor ~]$ k get storagecluster
NAME       AVAILABLE
cluster2   true

สร้าง application resource ที่ต้องการ snapshot หรือ replication โดยตัวอย่างนี้จะ backup resource ทั้งหมดที่อยู่ภายใต้ namespace แต่ถ้าต้องการ filter เฉพาะบาง resource สามารถกำหนดเพิ่มเติมได้ตามตัวอย่างที่ https://portal.nutanix.com/page/documents/details?targetId=Nutanix-Data-Services-for-Kubernetes-v1_2:top-app-cr-manual-create-cli-k8s-t.html

[nutanix@harbor ~]$ cat << EOF >  wordpress-app-cr.yaml
apiVersion: dataservices.nutanix.com/v1alpha1
kind: Application
metadata:
  name: wordpress-app-cr
  namespace: application
spec:
  applicationSelector:
EOF

[nutanix@harbor ~]$ k apply -f wordpress-app-cr.yaml
application.dataservices.nutanix.com/wordpress-app-cr created

[nutanix@harbor ~]$ k get application -A
NAMESPACE     NAME               AGE   ACTIVE   LAST-STATUS-UPDATE
application   wordpress-app-cr   20s            20s

สร้าง application snapshot ที่ cluster ต้นทาง

cd ~/nkp-v2.15.0/cli
export CLUSTER_NAME=<<NKP cluster name>>
export KUBECONFIG=~/nkp-v2.15.0/cli/${CLUSTER_NAME}.conf
export APP_NAME=<<application name>>
export APP_NAMESPACE=<<application namespace>>

cat << EOF >  ${APP_NAME}-snap.yaml
apiVersion: dataservices.nutanix.com/v1alpha1
kind: ApplicationSnapshot
metadata:
  name: ${APP_NAME}-snap
  namespace: ${APP_NAMESPACE}
spec:
  source:
    applicationRef:
     name: ${APP_NAME}-app-cr 
  expiresAfter: <<#>>m
EOF

ตัวอย่างค่าที่ใช้ในตัวอย่างนี้

[nutanix@harbor ~]$ cat << EOF >  wordpress-snap.yaml
apiVersion: dataservices.nutanix.com/v1alpha1
kind: ApplicationSnapshot
metadata:
  name: wordpress-snap
  namespace: application
spec:
  source:
    applicationRef:
     name: wordpress-app-cr
  expiresAfter: 120m
EOF
[nutanix@harbor ~]$ k apply -f wordpress-snap.yaml
applicationsnapshot.dataservices.nutanix.com/wordpress-snap created

[nutanix@harbor ~]$ kubectl get applicationsnapshot -n application
NAME             AGE   READY-TO-USE   BOUND-SNAPSHOTCONTENT                      SNAPSHOT-AGE   CONSISTENCY-TYPE
wordpress-snap   69s   true           asc-531ae7ca-7afb-40a6-a4f6-403c8e732cfa   36s

ตรวจสอบสถานะของการ snapshot

[nutanix@harbor ~]$ kubectl get applicationsnapshotcontent
NAME                                       READY-TO-USE   AGE    APPLICATIONSNAPSHOT   SNAPSHOTCONTENT-AGE   CONSISTENCYTYPE
asc-531ae7ca-7afb-40a6-a4f6-403c8e732cfa   true           110s   wordpress-snap        77s

ทดสอบ restore application จาก snapshot ที่สร้างขึ้นภายใน cluster เดียวกัน แต่ต่าง namspace ตามตัวอย่างนี้ โดยต้องสร้าง reference grant

export APP_NAME=<<application name>>
export APP_NAMESPACE=<<application namespace>>
export TGT_NAMESPACE=<<target namespace>>
***NOTE: target namespace must exist on target cluster (create if necessary)***
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cat << EOF >  ${APP_NAME}-snap-rg.yaml
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
 name: ${APP_NAME}-snap-rg
 namespace: ${APP_NAMESPACE}
spec:
 from:
 - group: dataservices.nutanix.com
   kind: ApplicationSnapshotRestore
   namespace: ${TGT_NAMESPACE}
 to:
 - group: dataservices.nutanix.com
   kind: ApplicationSnapshot
   name: ${APP_NAME}-snap
EOF

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
kubectl apply -f ${APP_NAME}-snap-rg.yaml
- verify reference grant exists:
kubectl get referencegrant -n ${APP_NAMESPACE}
--> ${APP_NAME}-snap-rg is in the list of reference grants

ตัวอย่างค่าที่ใช้ในการสร้าง reference grant

[nutanix@harbor ~]$ k create ns newapplication
namespace/newapplication created

[nutanix@harbor ~]$ cat << EOF >  wordpress-snap-rg.yaml
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
 name: wordpress-snap-rg
 namespace: application
spec:
 from:
 - group: dataservices.nutanix.com
   kind: ApplicationSnapshotRestore
   namespace: newapplication
 to:
 - group: dataservices.nutanix.com
   kind: ApplicationSnapshot
   name: wordpress-snap
EOF

[nutanix@harbor ~]$ k apply -f wordpress-snap-rg.yaml
referencegrant.gateway.networking.k8s.io/wordpress-snap-rg created

[nutanix@harbor ~]$ kubectl get referencegrant -n application
NAME                AGE
wordpress-snap-rg   35s

สร้าง application restore

cat << EOF >  ${APP_NAME}-rg-restore.yaml
apiVersion: dataservices.nutanix.com/v1alpha1
kind: ApplicationSnapshotRestore
metadata:
  name: ${APP_NAME}-rg-restore
  namespace: ${TGT_NAMESPACE}
spec:
  applicationSnapshotName: ${APP_NAME}-snap
  applicationSnapshotNamespace: ${APP_NAMESPACE}
EOF
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
kubectl apply -f ${APP_NAME}-rg-restore.yaml
- verify restore operation completes successfully (can take a few minutes)
kubectl get applicationsnapshotrestore -n ${TGT_NAMESPACE}
--> ${APP_NAME}-rg-restore shows a COMPLETED status of 'true'
- verify all artifacts referenced in snapshot describe operation have been restored on the target namespace:
***For example***
kubectl get all -n ${TGT_NAMESPACE}
kubectcl get pvc -n ${TGT_NAMESPACE}

ตัวอย่างการ restore application

[nutanix@harbor ~]$ cat << EOF >  wordpress-rg-restore.yaml
apiVersion: dataservices.nutanix.com/v1alpha1
kind: ApplicationSnapshotRestore
metadata:
  name: wordpress-rg-restore
  namespace: newapplication
spec:
  applicationSnapshotName: wordpress-snap
  applicationSnapshotNamespace: application
EOF
[nutanix@harbor ~]$ k apply -f wordpress-rg-restore.yaml
applicationsnapshotrestore.dataservices.nutanix.com/wordpress-rg-restore created

[nutanix@harbor ~]$ kubectl get applicationsnapshotrestore -n newapplication
NAME                   SNAPSHOT-NAME    COMPLETED
wordpress-rg-restore   wordpress-snap   false

[nutanix@harbor ~]$ kubectl get applicationsnapshotrestore -n newapplication
NAME                   SNAPSHOT-NAME    COMPLETED
wordpress-rg-restore   wordpress-snap   true

[nutanix@harbor ~]$ k get all -n newapplication
NAME                                   READY   STATUS    RESTARTS   AGE
pod/wordpress-84f858d9fd-8mjdp         1/1     Running   0          2m24s
pod/wordpress-mysql-556f6f65cc-bjd8q   1/1     Running   0          2m24s

NAME                      TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
service/wordpress         ClusterIP   10.99.164.74   <none>        80/TCP     2m24s
service/wordpress-mysql   ClusterIP   None           <none>        3306/TCP   2m24s

NAME                              READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/wordpress         1/1     1            1           2m24s
deployment.apps/wordpress-mysql   1/1     1            1           2m24s

NAME                                         DESIRED   CURRENT   READY   AGE
replicaset.apps/wordpress-84f858d9fd         1         1         1       2m24s
replicaset.apps/wordpress-mysql-556f6f65cc   1         1         1       2m24s

ตัวอย่างการ restore application snapshot ไปยัง kubernetes cluster ปลายทาง โดยต้องสร้าง Remote cluster ที่ cluster ต้นทางก่อน

- verify ndk intercom service is working on both source & target clusters:
cd ~/nkp-v2.15.0/cli
export SOURCE_NAME=<<NKP source cluster name>>
export TARGET_NAME=<<target cluster name>>
export APP_NAME=<<application name>>
export APP_NAMESPACE=<<application namespace>>
export KUBECONFIG=~/nkp-v2.15.0/cli/${SOURCE_NAME}.conf
kubectl get svc -n ntnx-system
--> load balancer service 'ndk-intercom-service' should exist and have an assigned external IP
kubectl get svc -n ntnx-system --kubeconfig ${TARGET_NAME}.conf
--> load balancer service 'ndk-intercom-service' should exist and have an assigned external IP	
--> cache external IP (needed for the remote cr)
- verify an application snapshot exists and is ready:
kubectl get applicationsnapshot -n ${APP_NAMESPACE}
--> snapshot status for <<app name>>-snap should be "true"
- create remote custom resource:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cat << EOF >  ndk-${TARGET_NAME}-remote.yaml
apiVersion: dataservices.nutanix.com/v1alpha1
kind: Remote
metadata:
  name: ndk-${TARGET_NAME}-remote
spec:
  clusterName: ${TARGET_NAME} 
  ndkServiceIp: <<EXTERNAL IP of target cluster's 'ndk-intercom-service' LB service>> 
  ndkServicePort: 2021
  tlsConfig:
    skipTLSVerify: true
EOF
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--> 'tlsConfig' section may not be needed or may need modified based on how NDK was installed, see following link: https://portal.nutanix.com/page/documents/details?targetId=Nutanix-Data-Services-for-Kubernetes-v1_2:top-remote-cr-create-cli-k8s.html
kubectl apply -f ndk-${TARGET_NAME}-remote.yaml
- verify remote cr is ready:
kubectl get remote
--> ndk-${TARGET_NAME}-remote should be listed and AVAILABLE status set to 'True'

ตัวอย่างการสร้าง Remote cluster

[nutanix@harbor ~]$ cat << EOF >  ndk-cluster2-remote.yaml
apiVersion: dataservices.nutanix.com/v1alpha1
kind: Remote
metadata:
  name: ndk-cluster2-remote
spec:
  clusterName: cluster2
  ndkServiceIp: 10.38.53.17
  ndkServicePort: 2021
  tlsConfig:
    skipTLSVerify: true
EOF
[nutanix@harbor ~]$ k apply -f ndk-cluster2-remote.yaml
remote.dataservices.nutanix.com/ndk-cluster2-remote created
[nutanix@harbor ~]$ k get remote
NAME                  ADDRESS       PORT   AVAILABLE
ndk-cluster2-remote   10.38.53.17   2021   True

สร้าง replication target ที่ต้องการให้ snapshot ทำการ replicate ไป

cat << EOF >  ${APP_NAME}-replicate-target.yaml
apiVersion: dataservices.nutanix.com/v1alpha1
kind: ReplicationTarget
metadata:
  name: ${TARGET_NAME}
  namespace: ${APP_NAMESPACE}
spec:
  namespaceName: ntnx-system
  remoteName: ndk-${TARGET_NAME}-remote
  serviceAccountName: default
EOF

ตัวอย่างการสร้าง Replication Target

[nutanix@harbor ~]$ cat << EOF >  wordpress-replicate-target.yaml
apiVersion: dataservices.nutanix.com/v1alpha1
kind: ReplicationTarget
metadata:
  name: cluster2
  namespace: application
spec:
  namespaceName: ntnx-system
  remoteName: ndk-cluster2-remote
  serviceAccountName: default
EOF
[nutanix@harbor ~]$ k apply -f wordpress-replicate-target.yaml
replicationtarget.dataservices.nutanix.com/cluster2 created
[nutanix@harbor ~]$ k get replicationtarget -A
NAMESPACE     NAME       REMOTE-NAME           REMOTE-NAMESPACE   AVAILABLE
application   cluster2   ndk-cluster2-remote   ntnx-system        True

สร้าง application snapshot replication ไปยัง cluster ปลายทาง

cat << EOF >  ${APP_NAME}-replicate.yaml
apiVersion: dataservices.nutanix.com/v1alpha1
kind: ApplicationSnapshotReplication
metadata:
  name: ${APP_NAME}-replicate
  namespace: ${APP_NAMESPACE}
spec:
  applicationSnapshotName: ${APP_NAME}-snap
  replicationTargetName: ${TARGET_NAME}
EOF

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
kubectl apply -f ${APP_NAME}-replicate.yaml
- monitor an application snapshot replication:
kubectl get applicationsnapshotreplication -n ${APP_NAMESPACE}
--> within a few minutes AVAILABLE status for <<app name>>-snap should be "True"
kubectl get applicationsnapshot -n ntnx-system ${APP_NAME}-snap --kubeconfig ${TARGET_NAME}.conf
--> should list snapshot on target cluster with a READY-TO-USE status of "true"

ตัวอย่างการสร้าง application snapshot replication

***NOTE: This enables application snapshots saved in one cluster to be restored to their original namespace on another cluster***
- verify the NDK reference grant CRD exists on the 'target' cluster:
cd ~/nkp-v2.15.0/cli
export TARGET_NAME=<<NKP target cluster name>>
export KUBECONFIG=~/nkp-v2.15.0/cli/${TARGET_NAME}.conf
kubectl get crd | grep 'referencegrants'
--> the 'referencegrants.gateway.networking.k8s.io' cred should be listed
- create a reference grant:
export APP_NAME=<<application name>>
export TGT_NAMESPACE=<<application's namespace on source cluster>>
***NOTE: target namespace must exist on target cluster (create if necessary)***
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cat << EOF >  ${APP_NAME}-snap-rg-${TARGET_NAME}.yaml
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
 name: ${APP_NAME}-snap-rg-${TARGET_NAME}
 namespace: ntnx-system
spec:
 from:
 - group: dataservices.nutanix.com
   kind: ApplicationSnapshotRestore
   namespace: ${TGT_NAMESPACE}
 to:
 - group: dataservices.nutanix.com
   kind: ApplicationSnapshot
   name: ${APP_NAME}-snap
EOF

ตัวอย่างการสร้าง application snapshot replication

[nutanix@harbor ~]$ cat << EOF >  wordpress-replicate.yaml
apiVersion: dataservices.nutanix.com/v1alpha1
kind: ApplicationSnapshotReplication
metadata:
  name: wordpress-replicate
  namespace: application
spec:
  applicationSnapshotName: wordpress-snap
  replicationTargetName: cluster2
EOF
[nutanix@harbor ~]$ k apply -f wordpress-replicate.yaml
applicationsnapshotreplication.dataservices.nutanix.com/wordpress-replicate created
[nutanix@harbor ~]$ k get applicationsnapshotreplication -A
NAMESPACE     NAME                  AVAILABLE   APPLICATIONSNAPSHOT   REPLICATIONTARGET   AGE
application   wordpress-replicate   False       wordpress-snap        cluster2            12s

[nutanix@harbor ~]$ k get applicationsnapshotreplication -A
NAMESPACE     NAME                  AVAILABLE   APPLICATIONSNAPSHOT   REPLICATIONTARGET   AGE
application   wordpress-replicate   True        wordpress-snap        cluster2            6m57s

[nutanix@harbor ~]$ kubectl get applicationsnapshot -n ntnx-system
NAME             AGE     READY-TO-USE   BOUND-SNAPSHOTCONTENT                                  SNAPSHOT-AGE
wordpress-snap   9m46s   true           asc-531ae7ca-7afb-40a6-a4f6-403c8e732cfa-1980ca1b120   6m58s

สร้าง reference grant สำหรับการ restore โดยต้องสร้างที่ cluster ปลายทาง

- create a reference grant:
export APP_NAME=<<application name>>
export TGT_NAMESPACE=<<application's namespace on source cluster>>
***NOTE: target namespace must exist on target cluster (create if necessary)***
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cat << EOF >  ${APP_NAME}-snap-rg-${TARGET_NAME}.yaml
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
 name: ${APP_NAME}-snap-rg-${TARGET_NAME}
 namespace: ntnx-system
spec:
 from:
 - group: dataservices.nutanix.com
   kind: ApplicationSnapshotRestore
   namespace: ${TGT_NAMESPACE}
 to:
 - group: dataservices.nutanix.com
   kind: ApplicationSnapshot
   name: ${APP_NAME}-snap
EOF

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
kubectl apply -f ${APP_NAME}-snap-rg-${TARGET_NAME}.yaml
- verify reference grant exists:
kubectl get referencegrant -n ntnx-system
--> ${APP_NAME}-snap-rg-${TARGET_NAME} is in the list of reference grants

ตัวอย่างการสร้าง reference grant

[nutanix@harbor ~]$ cat << EOF >  wordpress-snap-rg-cluster2.yaml
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
 name: wordpress-snap-rg-cluster2
 namespace: ntnx-system
spec:
 from:
 - group: dataservices.nutanix.com
   kind: ApplicationSnapshotRestore
   namespace: application
 to:
 - group: dataservices.nutanix.com
   kind: ApplicationSnapshot
   name: wordpress-snap
EOF
[nutanix@harbor ~]$ k apply -f wordpress-snap-rg-cluster2.yaml
referencegrant.gateway.networking.k8s.io/wordpress-snap-rg-cluster2 created
[nutanix@harbor ~]$ k get referencegrant -A
NAMESPACE     NAME                         AGE
ntnx-system   wordpress-snap-rg-cluster2   9s

ทำการ restore application ที่ cluster ปลายทาง

cat << EOF >  ${APP_NAME}-rg-restore-${TARGET_NAME}.yaml
apiVersion: dataservices.nutanix.com/v1alpha1
kind: ApplicationSnapshotRestore
metadata:
  name: ${APP_NAME}-rg-restore-${TARGET_NAME}
  namespace: ${TGT_NAMESPACE}
spec:
  applicationSnapshotName: ${APP_NAME}-snap
  applicationSnapshotNamespace: ntnx-system
EOF

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
kubectl apply -f ${APP_NAME}-rg-restore-${TARGET_NAME}.yaml
- verify restore operation completes successfully (can take a few minutes)
kubectl get applicationsnapshotrestore -n ${TGT_NAMESPACE}
--> ${APP_NAME}-rg-restore-${TARGET_NAME} shows a COMPLETED status of 'true'
- verify all artifacts referenced in snapshot describe operation have been restored on the target namespace:
***For example***
kubectl get all -n ${TGT_NAMESPACE}
kubectcl get pvc -n ${TGT_NAMESPACE}

ตัวอย่างการ restore application

[nutanix@harbor ~]$ cat << EOF >  wordpress-rg-restore-cluster2.yaml
apiVersion: dataservices.nutanix.com/v1alpha1
kind: ApplicationSnapshotRestore
metadata:
  name: wordpress-rg-restore-cluster2
  namespace: application
spec:
  applicationSnapshotName: wordpress-snap
  applicationSnapshotNamespace: ntnx-system
EOF
[nutanix@harbor ~]$ k apply -f wordpress-rg-restore-cluster2.yaml
applicationsnapshotrestore.dataservices.nutanix.com/wordpress-rg-restore-cluster2 created
[nutanix@harbor ~]$ k get applicationsnapshotrestore -A
NAMESPACE     NAME                            SNAPSHOT-NAME    COMPLETED
application   wordpress-rg-restore-cluster2   wordpress-snap   false

[nutanix@harbor ~]$ k get applicationsnapshotrestore -A
NAMESPACE     NAME                            SNAPSHOT-NAME    COMPLETED
application   wordpress-rg-restore-cluster2   wordpress-snap   true
[nutanix@harbor ~]$ k get pod -n application
NAME                               READY   STATUS    RESTARTS   AGE
wordpress-84f858d9fd-zqtrt         1/1     Running   0          78s
wordpress-mysql-556f6f65cc-s2h8m   1/1     Running   0          78s
[nutanix@harbor ~]$