NTNX>日記

個人的な趣味による Nutanix Community Edition 日記。Japanese のみですみません。

Nutanix Data Services for Kubernetes(NDK)でアプリをバックアップ / リストアしてみる。

この投稿は、Nutanix Advent Calendar 2025 の 10日目です。今日は、Nutanix Data Services for Kubernetes(NDK)2.0 で、NKP クラスタ上にあるアプリのスナップショット取得(バックアップ)→ リストアを実施してみます。

今回の内容です。

 

今回の環境

NKP v2.16.1 のワークロード クラスタを用意してあります。NKP の環境構築についてはこちらをどうぞ。

$ kubectl get nodes
NAME                            STATUS   ROLES           AGE   VERSION
nkpndk-md-0-zv4pm-jkcdc-mz4mg   Ready    <none>          69m   v1.33.5
nkpndk-p82sm-twt5k              Ready    control-plane   70m   v1.33.5

 

作業用マシンに、helm をインストールしてあります。

$ helm version
version.BuildInfo{Version:"v3.19.0", GitCommit:"3d8990f0836691f0229297773f3524598f46bda6", GitTreeState:"clean", GoVersion:"go1.24.7"}

 

NKP v2.16.1 の NKP クラスタには、デフォルトで Nutanix CSI Direver 3.3.8 がインストールされています。

$ kubectl get csidriver csi.nutanix.com -o json | jq -r .metadata.labels
{
  "app.kubernetes.io/instance": "nutanix-csi",
  "app.kubernetes.io/managed-by": "Helm",
  "app.kubernetes.io/management-plane": "PrismCentral",
  "app.kubernetes.io/name": "nutanix-csi-storage",
  "app.kubernetes.io/version": "3.3.8",
  "helm.sh/chart": "nutanix-csi-storage-3.3.8"
}

 

1. NDK のインストール

今回は、NDK 2.0 をインストールします。

 

1-1. Helm Repo の追加

NDK のチャートが公開されている Helm Repo を追加します。

$ helm repo add ntnx-charts https://nutanix.github.io/helm-releases/

 

追加されました。

$ helm repo list
NAME            URL
ntnx-charts     https://nutanix.github.io/helm-releases/

 

NDK 2.0 の Helm Chart が公開されています。

$ helm search repo ntnx-charts/ndk
NAME            CHART VERSION   APP VERSION     DESCRIPTION
ntnx-charts/ndk 2.0.0           2.0.0           Helm chart for Nutanix Data Services for Kubern...

 

1-2. Nutanix DockerHub トークンの入手

Nutainx Support & Insight Portl の、NDK のダウンロードページで、Nutanix DockerHub の nutanixndk ユーザーのトークンを入手します。

 

1-3. NDK のインストール

下記のコマンドで、NDK をインストールします。

helm install ndk ntnx-charts/ndk \
--version 2.0.0 \
-n ntnx-system \
--set config.secret.name=nutanix-csi-credentials \
--set imageCredentials.credentials.username=nutanixndk \
--set imageCredentials.credentials.password='トークン' \
--set tls.server.enable=false

 

実際に実行すると、下記のように表示されます。

$ helm install ndk ntnx-charts/ndk \
--version $NDK_VERSION \
-n ntnx-system \
--set config.secret.name=nutanix-csi-credentials \
--set imageCredentials.credentials.username=$DOCKER_USERNAME \
--set imageCredentials.credentials.password=$DOCKER_PASSWORD \
--set tls.server.enable=false
NAME: ndk
LAST DEPLOYED: Wed Dec 10 11:47:25 2025
NAMESPACE: ntnx-system
STATUS: deployed
REVISION: 1
TEST SUITE: None

 

少し待つと、NDK の Pod が Running になります。

$ kubectl get pods -n ntnx-system -l app.kubernetes.io/name=ndk
NAME                                      READY   STATUS    RESTARTS   AGE
ndk-controller-manager-754bcbf7d4-2jlhg   4/4     Running   0          2m10s

 

NDK のインストールにより、Kubernetes クラスタに下記のような CRD が追加されます。

$ kubectl get crd | grep nutanix
applications.dataservices.nutanix.com                         2025-12-10T11:47:24Z
applicationsnapshotcontents.dataservices.nutanix.com          2025-12-10T11:47:24Z
applicationsnapshotreplications.dataservices.nutanix.com      2025-12-10T11:47:24Z
applicationsnapshotrestores.dataservices.nutanix.com          2025-12-10T11:47:24Z
applicationsnapshots.dataservices.nutanix.com                 2025-12-10T11:47:25Z
appplannedfailovers.dataservices.nutanix.com                  2025-12-10T11:47:25Z
appprotectionplans.dataservices.nutanix.com                   2025-12-10T11:47:25Z
appunplannedfailovers.dataservices.nutanix.com                2025-12-10T11:47:25Z
fileserverreplicationrelationships.dataservices.nutanix.com   2025-12-10T11:47:25Z
filesreplicationpolicies.dataservices.nutanix.com             2025-12-10T11:47:25Z
haapplicationcontents.dataservices.nutanix.com                2025-12-10T11:47:25Z
haapplications.dataservices.nutanix.com                       2025-12-10T11:47:25Z
jobschedulers.scheduler.nutanix.com                           2025-12-10T11:47:25Z
protectionplans.dataservices.nutanix.com                      2025-12-10T11:47:25Z
remotes.dataservices.nutanix.com                              2025-12-10T11:47:25Z
replicationtargets.dataservices.nutanix.com                   2025-12-10T11:47:25Z
storageclusters.dataservices.nutanix.com                      2025-12-10T11:47:25Z

 

kubectl api-resources では、下記のように見えます。

$ kubectl api-resources --api-group=dataservices.nutanix.com
NAME                                 SHORTNAMES       APIVERSION                          NAMESPACED   KIND
applications                         app              dataservices.nutanix.com/v1alpha1   true         Application
applicationsnapshotcontents          asc,ascs         dataservices.nutanix.com/v1alpha1   false        ApplicationSnapshotContent
applicationsnapshotreplications      appsnaprep       dataservices.nutanix.com/v1alpha1   true         ApplicationSnapshotReplication
applicationsnapshotrestores          asr              dataservices.nutanix.com/v1alpha1   true         ApplicationSnapshotRestore
applicationsnapshots                 as               dataservices.nutanix.com/v1alpha1   true         ApplicationSnapshot
appplannedfailovers                  pfo              dataservices.nutanix.com/v1alpha1   true         AppPlannedFailover
appprotectionplans                   appplan          dataservices.nutanix.com/v1alpha1   true         AppProtectionPlan
appunplannedfailovers                upfo             dataservices.nutanix.com/v1alpha1   true         AppUnplannedFailover
fileserverreplicationrelationships   fsrr             dataservices.nutanix.com/v1alpha1   false        FileServerReplicationRelationships
filesreplicationpolicies             frp,frps         dataservices.nutanix.com/v1alpha1   true         FilesReplicationPolicy
haapplicationcontents                haac             dataservices.nutanix.com/v1alpha1   false        HAApplicationContent
haapplications                       haa              dataservices.nutanix.com/v1alpha1   true         HAApplication
protectionplans                      pplan            dataservices.nutanix.com/v1alpha1   true         ProtectionPlan
remotes                              remote,remotes   dataservices.nutanix.com/v1alpha1   false        Remote
replicationtargets                                    dataservices.nutanix.com/v1alpha1   true         ReplicationTarget
storageclusters                                       dataservices.nutanix.com/v1alpha1   false        StorageCluster
$ kubectl api-resources --api-group=scheduler.nutanix.com
NAME            SHORTNAMES   APIVERSION                       NAMESPACED   KIND
jobschedulers                scheduler.nutanix.com/v1alpha1   true         JobScheduler

 

2. デモ アプリ(Wordpress)の起動

バックアップ・リストア対象のアプリケーション用意しておきます。今回は、下記で紹介されている Wordpress を起動します。

 

今回は demo-01 Namespace でアプリを起動します。

$ kubectl create ns demo-01
namespace/demo-01 created

 

Wordpress の DB(MySQL)に設定するパスワードを格納する、Secret を作成します。

$ kubectl create secret generic mysql-pass --from-literal password='nutanix/4u' -n demo-01
secret/mysql-pass created

 

アプリケーションを起動します。今回はオンラインの YAML を直接指定します。

$ kubectl apply -n demo-01 -f https://k8s.io/examples/application/wordpress/mysql-deployment.yaml
service/wordpress-mysql created
persistentvolumeclaim/mysql-pv-claim created
deployment.apps/wordpress-mysql created
$ kubectl apply -n demo-01 -f https://k8s.io/examples/application/wordpress/wordpress-deployment.yaml
service/wordpress created
persistentvolumeclaim/wp-pv-claim created
deployment.apps/wordpress created

 

これで、Wordpress を構成する Kubernetes リソース一式が起動されました。外部接続用の IP アドレスは、10.1.7.93 になっています。

$ kubectl get all -n demo-01
NAME                                   READY   STATUS    RESTARTS   AGE
pod/wordpress-c8b9849f8-tf6wt          1/1     Running   0          4m23s
pod/wordpress-mysql-766bf4cb5c-t4qwp   1/1     Running   0          5m7s

NAME                      TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
service/wordpress         LoadBalancer   10.104.163.199   10.1.7.93     80:32726/TCP   4m23s
service/wordpress-mysql   ClusterIP      None             <none>        3306/TCP       5m7s

NAME                              READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/wordpress         1/1     1            1           4m23s
deployment.apps/wordpress-mysql   1/1     1            1           5m7s

NAME                                         DESIRED   CURRENT   READY   AGE
replicaset.apps/wordpress-c8b9849f8          1         1         1       4m23s
replicaset.apps/wordpress-mysql-766bf4cb5c   1         1         1       5m7s

 

アプリのデータを含む、PVC も作成されています。

$ kubectl get pvc -n demo-01
NAME             STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS     VOLUMEATTRIBUTESCLASS   AGE
mysql-pv-claim   Bound    pvc-27441a18-846c-4b85-912b-4640d067ad19   20Gi       RWO            nutanix-volume                    10m
wp-pv-claim      Bound    pvc-a34dd7f0-40d0-4b8a-a436-6c8fa643500d   20Gi       RWO            nutanix-volume                    10m

 

Web ブラウザで 10.1.7.93 を開くと、Wordpress が利用可能になっています。

 

テスト用に記事を投稿しておきます・・・

 

3. NDK の設定(StorageCluster の作成)

NDK が Nutainx クラスタと連携するための、「StorageCluster」リソースを作成します。

パラメータとして必要になる、Prism Centarl と Prism Element の UUID を確認します。どちらも Web UI から確認できますが、今回は NKP クラスタ ノードのラベルから確認します。

 

$ kubectl get nodes nkpndk-p82sm-twt5k -o json | jq -r .metadata.labels | grep prism
  "csi.nutanix.com/prism-central-uuid": "16222475-b017-4c43-XXXX-XXXXXXXXXXXX",
  "csi.nutanix.com/prism-element-uuid": "00063c9a-1efe-0a33-XXXX-XXXXXXXXXXXX",

 

StorageCluster リソースの YAML を作成します。

 

storage-cluster.yml

  • managementServerUuid:Prism Element の UUID を指定
  • storageServerUuid:Prism Element の UUID を指定

gist.github.com

 

リソースを作成します。

$ kubectl apply -f storage-cluster.yml
storagecluster.dataservices.nutanix.com/st-cluster created

 

StorageCluster リソースが作成されました。

$ kubectl get storageclusters.dataservices.nutanix.com
NAME         AVAILABLE
st-cluster   true

 

4. NDK Application の設定(保護対象の指定)

NDK では、捜査の対象を Application リソースとして定義します。今回は demo-01 Namespace 全体を app-01 Application に含めます。

下記のような YAML ファイルを用意します。

 

ndk-application.yml

gist.github.com

 

 

リソースを作成します。

$ kubectl apply -f yaml/ndk-application.yml -n demo-01
application.dataservices.nutanix.com/app-01 created
$ kubectl get applications -n demo-01
NAME     AGE   ACTIVE   LAST-STATUS-UPDATE
app-01   12s   True     11s

 

5. ApplicationSnapshot の作成

app-01 Application を対象として、NDK のスナップショット(ApplicationSnapshot)を作成します。

下記のような YAML を用意します。

 

ndk-snapshot.yml

gist.github.com

 

ApplicationSnapshot を作成します。

$ kubectl apply -f yaml/ndk-snapshot.yml -n demo-01
applicationsnapshot.dataservices.nutanix.com/app-01-snapshot-01 created

 

作成直後の状態です。

$ kubectl get applicationsnapshot -n demo-01
NAME                 AGE   READY-TO-USE   BOUND-SNAPSHOTCONTENT                      SNAPSHOT-AGE   CONSISTENCY-TYPE
app-01-snapshot-01   25s   false          asc-d33f89b1-1f2b-4154-9050-17a0ed304cd9

 

少し待つと、スナップショットの処理が完了して READY-TO-USE が true になります。

$ kubectl get applicationsnapshot -n demo-01
NAME                 AGE   READY-TO-USE   BOUND-SNAPSHOTCONTENT                      SNAPSHOT-AGE   CONSISTENCY-TYPE
app-01-snapshot-01   32s   true           asc-d33f89b1-1f2b-4154-9050-17a0ed304cd9   1s             CrashConsistent

 

MySQL 用の PVC/PV に対応する Volume Group を確認すると、NDK により Recovery Point が作成されています。

 

6. リストアの実施

あえて Wordpress 関連のリソースを削除して、NDK のスナップショットをリストアしてみます。

 

6-1. 既存リソースの削除

まず、既存の Wordpress 関連リソースを削除してしまいます。

$ kubectl delete deployment -n demo-01 --all
deployment.apps "wordpress" deleted
deployment.apps "wordpress-mysql" deleted
$ kubectl delete pvc -n demo-01 --all
persistentvolumeclaim "mysql-pv-claim" deleted
persistentvolumeclaim "wp-pv-claim" deleted
$ kubectl delete svc -n demo-01 --all
service "wordpress" deleted
service "wordpress-mysql" deleted

 

リソース一式が削除されました。

$ kubectl get all -n demo-01
No resources found in demo-01 namespace.
$ kubectl get pvc -n demo-01
No resources found in demo-01 namespace.
$ kubectl get pv
No resources found

 

ただし、ApplicationSnapshot は残してあります。

$ kubectl get applicationsnapshot -n demo-01
NAME                 AGE   READY-TO-USE   BOUND-SNAPSHOTCONTENT                      SNAPSHOT-AGE   CONSISTENCY-TYPE
app-01-snapshot-01   14m   true           asc-d33f89b1-1f2b-4154-9050-17a0ed304cd9   14m            CrashConsistent

 

6-2. リストアの実行

リストアを実行する、ApplicationSnapshotRestore リソースの YAML を作成します。

 

ndk-restore.yml

gist.github.com

 

リストアを実行します。

$ kubectl apply -f yaml/restore.yml -n demo-01
applicationsnapshotrestore.dataservices.nutanix.com/app-01-restore-01 created

 

少し待つと、COMPLETED が true になります。

$ kubectl get applicationsnapshotrestore -n demo-01
NAME                SNAPSHOT-NAME        COMPLETED
app-01-restore-01   app-01-snapshot-01   true

 

ちなみに、リストアの状態は下記のように確認できます。

$ kubectl describe applicationsnapshotrestore -n demo-01 app-01-restore-01
Name:         app-01-restore-01
Namespace:    demo-01
Labels:       
Annotations:  
API Version:  dataservices.nutanix.com/v1alpha1
Kind:         ApplicationSnapshotRestore
Metadata:
  Creation Timestamp:  2025-12-10T12:55:15Z
  Finalizers:
    dataservices.nutanix.com/application-restore
  Generation:        1
  Resource Version:  89152
  UID:               fcee0a9e-1d1a-4398-81c2-11658f285c4d
Spec:
  Application Snapshot Name:  app-01-snapshot-01
Status:
  Completed:  true
  Conditions:
    Last Transition Time:  2025-12-10T12:55:15Z
    Message:
    Observed Generation:   1
    Reason:                RequestCompleted
    Status:                False
    Type:                  Progressing
    Last Transition Time:  2025-12-10T12:55:15Z
    Message:               All prechecks passed and finalizers on dependent resources set. Skipped restoring resources since they already exist: ["/v1, Kind=Secret, demo-01/mysql-pass","/v1, Kind=ConfigMap, demo-01/kube-root-ca.crt","/v1, Kind=ServiceAccount, demo-01/default"]
    Observed Generation:   1
    Reason:                PrechecksPassed
    Status:                True
    Type:                  PrechecksPassed
    Last Transition Time:  2025-12-10T12:55:15Z
    Message:               Restore requests for all eligible volumes submitted
    Observed Generation:   1
    Reason:                VolumeRestoreRequestsSubmitted
    Status:                True
    Type:                  VolumeRestoreRequestsSubmitted
    Last Transition Time:  2025-12-10T12:55:16Z
    Message:               All eligible application configs restored
    Observed Generation:   1
    Reason:                ApplicationConfigRestored
    Status:                True
    Type:                  ApplicationConfigRestored
    Last Transition Time:  2025-12-10T12:55:31Z
    Message:               All eligible volumes restored
    Observed Generation:   1
    Reason:                VolumesRestored
    Status:                True
    Type:                  VolumesRestored
    Last Transition Time:  2025-12-10T12:55:31Z
    Message:               Application restore successfully finalised
    Observed Generation:   1
    Reason:                ApplicationRestoreFinalised
    Status:                True
    Type:                  ApplicationRestoreFinalised
  Finish Time:             2025-12-10 12:55:31
  Start Time:              2025-12-10 12:55:15
Events:
  Type     Reason                   Age                From  Message
  ----     ------                   ----               ----  -------
  Normal   WaitingForVolumesToBind  59s (x3 over 59s)  NDK   Waiting for PVCs to get Bound. Unbound PVCs: [mysql-pv-claim wp-pv-claim]
  Normal   WaitingForVolumesToBind  59s                NDK   Waiting for PVCs to get Bound. Unbound PVCs: [wp-pv-claim mysql-pv-claim]
  Warning  UpdateStatusFailed       44s (x2 over 60s)  NDK   Operation cannot be fulfilled on applicationsnapshotrestores.dataservices.nutanix.com "app-01-restore-01": the object has been modified; please apply your changes to the latest version and try again

 

これで、リソース削除前の状態にリストアできました。EXTERNAL-IP は自動採番なのですが、空いていた以前とおなじ IP アドレスが割り当てられています。

$ kubectl get all -n demo-01
NAME                                   READY   STATUS    RESTARTS   AGE
pod/wordpress-c8b9849f8-72h87          1/1     Running   0          106s
pod/wordpress-mysql-766bf4cb5c-rpg45   1/1     Running   0          106s

NAME                      TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
service/wordpress         LoadBalancer   10.101.113.100   10.1.7.93     80:32512/TCP   106s
service/wordpress-mysql   ClusterIP      None             <none>        3306/TCP       106s

NAME                              READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/wordpress         1/1     1            1           106s
deployment.apps/wordpress-mysql   1/1     1            1           106s

NAME                                         DESIRED   CURRENT   READY   AGE
replicaset.apps/wordpress-c8b9849f8          1         1         1       106s
replicaset.apps/wordpress-mysql-766bf4cb5c   1         1         1       106s

 

Wordpress でも、さきほど作成した投稿がリストアできています。

 

以上。

©2025 gowatana
クリエイティブ・コモンズ・ライセンスこの 作品 は クリエイティブ・コモンズ 表示 4.0 国際 ライセンスの下に提供されています。