NetApp Tridentとは

初版: 2021/4/16
2021/8/10 関連投稿一覧を追記
2021/10/3,2022/2/2 新しい記事のリンクを追加

#### 関連投稿一覧
* [NetApp Tridentとは](https://qiita.com/star76/items/fa88d715192f565e5832) 【本投稿】 
* [NetApp Astra とは](https://qiita.com/star76/items/86c1df804fc762b22d8e) 
* [NetApp Astra Service を使ってみる ①GKE事前準備編](https://qiita.com/star76/items/4ec78181db97d0f52eb8)
* [NetApp Astra Service を使ってみる ②AKS事前準備編](https://qiita.com/star76/items/4a2999590fd657082254) 
* [NetApp Astra Service を使ってみる ③Astra UI操作編](https://qiita.com/star76/items/1bb428404b6eb4337dd4)
* [NetApp Astra Control のインストール](https://qiita.com/star76/items/84b1d0732e8ce2dbf4cc)
* [NetApp Astra Control を使ってみる ①UIの操作編](https://qiita.com/star76/items/a746fdb78d07c32ef1bc)
* [NetApp Astra Data Store とは](https://qiita.com/star76/items/ef8e809d9cad24d51e8e) 


# はじめに
NetApp Tridentは、KubernetesとNetAppのストレージを接続するためのプラグインです。

Kubernetesのようなコンテナオーケストレーションツールとストレージプロバイダをつなぐ標準インターフェースとしてCSI(Container Storage Interface)という仕様がありますが、TridentはこのCSIに対応したDriverです。

Tridentを使用することで、ストレージを気にすることなくストレージリソースをオンデマンドにプロビジョニング・管理することができます。
![Screen Shot 2021-04-12 at 15.23.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449507/e4b0b362-be1c-d36e-c2c6-1026737fe5a9.png)

プロビジョニングできるバックエンドのストレージは以下です。
NetApp AFF/FAS、E/EFシリーズ、ONTAP Select、Cloud Volumes ONTAP、NetApp Elementソフトウェア(SolidFire)
プロトコルは、NFSとiSCSIが利用できます。

![Screen Shot 2021-04-12 at 15.22.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449507/934979b3-9e0b-a170-c859-93f17431e060.png)

Tridentは、Kubernetes 1.4から導入されたStorageClassオブジェクトを使用して、Persistent Volume Claim(PVC) オブジェクトの作成時に、Persistent Volume(PV) を動的にプロビジョニングし、マウントします。 

# Tridentを使うと何がいいの?
ではこのTridentを使うと何が便利になるのか、みてみましょう。

## 動的プロビジョニングを使用しない場合
下の図は、K8sのストレージをプロビジョニングする際に、動的プロビジョニングを「使わない」フローの例です。
![Screen Shot 2021-12-08 at 16.45.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449507/c81bcca1-20e7-8715-091b-b85c526c05f1.png)

動的プロビジョニングの仕組みを使わない場合は、この図のようにPVを事前に作成しておく必要があります。
例えば組織がインフラ部門とアプリケーション部門に分かれている場合、PVはストレージの仮想リソースとなるので、インフラ部門が作成することになるかと思います。
よって、アプリケーション開発者は、都度PVの作成依頼をインフラ部門に依頼する必要があります。
もしくはあらかじめPVを作成しておくことでその手間を省くことはできますが、アプリケーション開発者がPersistentVolumeClaimを使って要求した容量サイズより大きいPVがマウントされることもありリソースの無駄が発生する場合があります。
また、例えばアプリケーション開発者が、 既に作成済みのPVのサイズより大きい容量を要求した場合は、割り当てに失敗します。

動的プロビジョニングを行わない場合の操作手順は以下のようになります。
#### 1. PVを作成

```YAML
# test-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: test-volume
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: /home/mirorin/test
```
上記例では簡単にするためにhostPathを使用しています。該当ディレクトリに、index.htmlを用意しておきます。

```
$ kubectl apply -f test-pv.yaml
$ kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                                            STORAGECLASS           REASON   AGE
test-volume                                10Gi       RWO            Retain           Available                                                    standard                        39s
```
#### 2. PVCを作成してPVをBind
```YAML
# test-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-pvc
  namespace: test
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
```
```
$ kubectl create namespace test
$ kubectl apply -f test-pvc.yaml
$ kubectl get pv,pvc -n test
NAME                           CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM           STORAGECLASS   REASON   AGE
persistentvolume/test-volume   10Gi       RWO            Retain           Bound    test/test-pvc                           92s

NAME                             STATUS   VOLUME        CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/test-pvc   Bound    test-volume   10Gi       RWO                           92s
```
STATUSがBoundとなりました。PVCの要求は5Giですが、10GiのPVをつかんでいますね。

#### 3. Podを作成する
```YAML
# test-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-pod
  namespace: test
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx
    ports:
      - containerPort: 80
    volumeMounts:
      - name: test-storage
        mountPath: /usr/share/nginx/html
  volumes:
  - name: test-storage
    persistentVolumeClaim:
      claimName: test-pvc
```

```
$ kubectl apply -f test-pod.yaml
$ kubectl get pod -n test
NAME       READY   STATUS    RESTARTS   AGE
test-pod   1/1     Running   0          56s
```

マウントされたことを確認します。

```
$ kubectl exec -it test-pod -n test -- ls -la /usr/share/nginx/html/
total 12
drwxrwxrwx 2 1000 1000 4096 Apr 13 04:50 .
drwxr-xr-x 3 root root 4096 Apr 10 07:32 ..
-rw-rw-r-- 1 1000 1000   34 Apr 13 04:50 index.html
```

## 動的プロビジョニングを使用する場合
動的プロビジョニングを使うことで、PVCが作成された際に、自動的にPVが作成されます。
よってこの図のようにインフラ部門はアプリケーション開発者からの依頼の都度PVを作る必要もなく、割り当てられるボリュームのサイズに無駄が出ることもなくなります。

![Screen Shot 2021-04-13 at 12.31.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449507/4bd129e6-b839-a3a2-a9c8-0a56447d4b0c.png)

動的プロビジョニングを行うためのProvisionerにTridentを使用した際の操作例は以下のようになります。

#### 事前1. Kubernetes ClusterにTridentをインストール
Tridentのインストール方法は、[こちら](https://netapp-trident.readthedocs.io/)を参照ください。
TridentもK8sのPodの形でデプロイされます。

```
$ kubectl get pod -n trident
NAME                           READY   STATUS    RESTARTS   AGE
trident-csi-6885d67477-4s94l   6/6     Running   6          83d
trident-csi-sdgx8              2/2     Running   2          83d
```
Tridentに関する操作は、tridentctlを使って行います。※ 2021年4月現在の最新バージョンは、21.01.2です。

```
$ tridentctl -n trident version
+----------------+----------------+
| SERVER VERSION | CLIENT VERSION |
+----------------+----------------+
| 20.10.1        | 20.10.1        |
+----------------+----------------+
```

#### 事前2. StorageBackend を作成
Storage Backendと呼ばれるオブジェクトを作成します。
Storage Backendは、ストレージのエンドポイントやログインユーザ情報を記載したJSONファイルを用いて作成します。
以下の例では、NetAppのSolidFireというストレージを使ってBackendを作成しています。
サンプルのjsonファイルは次のようになります。

```json
# backend-solidfire.json
{
    "version": 1,
    "storageDriverName": "solidfire-san",
    "Endpoint": "https://admin:solidfire$@10.128.211.50/json-rpc/12.2",
    "SVIP": "192.168.0.50:3260",
    "BackendName": "mbox",
    "TenantName": "account01",
    "UseCHAP": true,
    "Types": [{"Type": "Bronze", "Qos": {"minIOPS": 100, "maxIOPS": 200, "burstIOPS": 500}},
              {"Type": "Silver", "Qos": {"minIOPS": 1000, "maxIOPS": 2000, "burstIOPS": 4000}},
              {"Type": "Gold", "Qos": {"minIOPS": 3000, "maxIOPS": 4000, "burstIOPS": 6000}}],
    "InitiatorIFace": "default"
}
```

|パラメータ|値|
|:--|:--|
|version|1|
|storageDriverName|solidfire-san|
|Endpoint|https://[ストレージクラスタのログインユーザ]:[ストレージクラスタのログインパスワード]@[ストレージクラスタの管理用VIP]/json-rpc/[Elementバージョン]|
|SVIP|ストレージクラスタのストレージVIP|ポート|
|BackendName|このBackendにつける名前です。任意の名前を指定します。|
|TenantName|ボリュームにアクセスする際のアカウント名です。存在しない場合は自動で作成されます|
|UseCHAP|trueを指定。iSCSI認証にCHAPを使用します。SolidFireのVolumeのiSCSIの認証方式としては「Volume Access Group」※がありますが、Volume Access GroupはTridentの従来の非CSIのフレームワークでのみでサポートされます。(CSIモードで動作するように構成されている場合、TridentはCHAPを使用します) ※「Volume Access Group」はVolumeとInitiatorをグループ化する機能で、グループに属するInitiatorを持つホストは該当Volumeへのアクセスが許可されます。|
|Types|QoSのタイプを記述|
|InitiatorIFace|iSCSI initiatorを記載することで、接続を特定のホストのみからに制限することができます。ホストを指定しない場合は"default"と記述します。|

Backendの作成は、以下のように実施します。

```
$ tridentctl create backend -f backend-solidfire.json -n trident
+------+----------------+--------------------------------------+--------+---------+
| NAME | STORAGE DRIVER |                 UUID                 | STATE  | VOLUMES |
+------+----------------+--------------------------------------+--------+---------+
| mbox | solidfire-san  | 7983351d-cf97-4884-830b-15ab1da01879 | online |       0 |
+------+----------------+--------------------------------------+--------+---------+

$ tridentctl get backend -n trident
+-------+----------------+--------------------------------------+--------+---------+
| NAME  | STORAGE DRIVER |                 UUID                 | STATE  | VOLUMES |
+-------+----------------+--------------------------------------+--------+---------+
| mbox  | solidfire-san  | 6e33be49-c3f1-4272-b3e9-55a9e52b7126 | online |       0 |
+-------+----------------+--------------------------------------+--------+---------+
```

#### 事前3. StorageClass を作成
StorageClassは、ストレージの種類を表すK8sのオブジェクトです。

サンプルのYAMLファイルは次のようになります。

```YAML
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: solidfire-gold
provisioner: netapp.io/trident
parameters:
  snapshots: "true"
  storagePools: "mbox:Gold"
```

「parameters」に記載した値がStorage ProvisionerであるTridentに渡され、Tridentはこの情報を元にどのStorage Backendを使用するかを判断します。

Backendを直接指定する場合は、上記のように「storagePools」パラメータにBackend名を記載します。「storagePools」パラメータを指定した場合、他のパラメータは「storagePools」パラメータの値に上書きされます。

以下のようにBackendを直接指定せず最適なBackendを選択することも可能です。

```YAML
parameters:
  backendType: "solidfire-san"
  IOPS: "1500"
  fsType: "ext4"
```

yamlファイルを元に、StorageClassを作成します。

```
$ kubectl apply -f storage-class-solidfire-gold.yaml
storageclass.storage.k8s.io/solidfire-gold created

$ kubectl get sc
NAME                   PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
solidfire-gold         csi.trident.netapp.io   Delete          Immediate           false                  52s
```

少し面倒なように感じられるかもしれませんが、ここまで実施すれば後は利用者がPVCを作成する都度、自動でPVを作ってくれるようになるので、日々の運用の手間を省くことができます。

操作の手順は、以下のようになります。

#### 1. PVCを作成
```YAML
# test-pvc-2.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-pvc-2
  namespace: test2
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  storageClassName: solidfire-gold
```
```
$ kubectl create namespace test2
$ kubectl apply -f test-pvc-2.yaml
persistentvolumeclaim/test-pvc-2 created
```

```
$ kubectl get pv,pvc -n test2
NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM              STORAGECLASS     REASON   AGE
persistentvolume/pvc-531acf30-5371-4e4c-86e1-d175fb126e2d   5Gi        RWO            Delete           Bound    test2/test-pvc-2   solidfire-gold            4s

NAME                               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS     AGE
persistentvolumeclaim/test-pvc-2   Bound    pvc-531acf30-5371-4e4c-86e1-d175fb126e2d   5Gi        RWO            solidfire-gold   4s
```
PVCの作成とともにPVが作成されました。「CAPACITY」を見ると、要求通り5Giで作成されていますね。

SolidFireのWebUIからも、このPVのVolumeが作成されたことが確認できます。
QoSも正しく反映されていますね。
![Screen Shot 2021-04-14 at 20.17.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449507/be93638c-fad3-5206-f30b-64ede07a13ed.png)

#### 2. Podの作成
Podの作成は通常と同様です。

```YAML
# test-pod-2.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-pod
  namespace: test2
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx
    ports:
      - containerPort: 80
    volumeMounts:
      - name: test-storage
        mountPath: /usr/share/nginx/html
  volumes:
  - name: test-storage
    persistentVolumeClaim:
      claimName: test-pvc-2
```
```
$ kubectl apply -f test-pod-2.yaml
pod/test-pod created
$ kubectl get pod -n test2
NAME       READY   STATUS    RESTARTS   AGE
test-pod   1/1     Running   0          37s
```

# おわりに
Tridentを使って、PVを動的に管理する仕組みの動的プロビジョニングについてご紹介しました。
Trident以外も様々なストレージベンダやクラウドサービスのprovisionerを利用し色々なタイプのボリュームを動的に作成し、割り当てることができます。
今度はTridentを使ったボリュームのバックアップについても記載していこうと思います。