Tridentでボリュームを払い出すプールを制御する（Storage Pool基礎編）

こんにちは。NetAppの大野です。  
今回は NetAppの CSI Driverである、[Trident] [^Trident] について受ける質問として比較的多かった ストレージプールについて書いていきます。

ストレージプール／仮想ストレージプールを使うと、Persistent Volumeを払い出すリソースプールを柔軟に制御できるようになります。  
公式ドキュメントだけだと わかりにくい事もあってか、良く聞かれるため記事化してみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128512/91331fed-691d-3b83-aa27-a8838a15e6e1.png)

## Tridentの ストレージプールとは

ストレージプール(Storage Pool) は、Persistent Volumeを切り出すためのリソースプールです。乱暴な説明ですが、ONTAPの場合、[Aggregate] [^Aggregate] と考えるとだいたい合ってます。

一般的に企業向けのストレージ等では、ディスクの集まりをRAID化して直接使うのではなく、そこからボリュームと呼ばれる論理ディスクを、小さく切り出し、ネットワーク上の様々な機器に割り当てて使います。

FSx for NetApp ONTAP等のストレージOS＝ONTAPでも、まずディスクをまとめてRAID化して [Aggregate] を作り出します。[Aggregate] から必要な分だけ容量を切り出し、FlexVolと呼ばれるボリュームを作りだしてユーザは利用します。Tridentはこのボリュームを作り出して、更にKubernetesクラスタから利用できるようにしてくれます。

このボリュームを作り出すための資源の集まり（リソースプール）を、ストレージプールと呼んでいます。

## ストレージプールは一つじゃない

[Aggregate]は SSDだけ、HDDだけで作る事もできますし、はたまた それらを混ぜてハイブリッドにもできるのですが、ストレージの中に複数の[Aggregate]が存在することも珍しくありません。

[Trident]と実際のストレージシステムを関連づけるために、[バックエンド] というものを設定しますが、１つのストレージの中に複数の[Aggregate]が設定されている場合、１つの[バックエンド]の中に複数の ストレージプールが存在する事になります。

また、大規模環境や、用途の違いでストレージが複数ある場合等、１つの[Trident]に対して[バックエンド]を複数設定することができます。この場合も、ストレージプールは複数存在することになります。

## では、Persistent Volumeを作るときに、どのストレージプールを使うのか？

ここから、ややややこしい話が始まります。

### バックエンド設定の中に設定したユーザアカウントが使える[Aggregate]は使える

まず、ONTAPのストレージシステムで[Aggregate]を誰が使える(ボリュームを作れる)のか？というと、以下のようになります。

- ONTAPクラスタ管理者＝全部使える
- 仮想ストレージ(SVM)管理者＝仮想ストレージに対して許された[Aggregate]だけ使える

このため、バックエンド設定の中に設定するユーザアカウントによって 使える範囲が異なってきます。

### 複数あるストレージプールから、StorageClassの設定で選ぶ事ができる

バックエンド設定で、指定した管理者アカウントにより使えるストレージプールが決まりますが、例えばクラスタ管理者を設定すると、ONTAP側にある全ての[Aggregate]を使ってしまいます。また、バックエンドも複数あるかもしれません。

この場合、StorageClass側の設定で、Tridentが持つストレージプールの使い方を制御する事ができます。
色々柔軟にできるようになっているのですが、主に二種類の制限のかけ方が可能です。

- 具体的にストレージプール名を指定する
- ストレージプールが持つ属性により制限する

#### 具体的にストレージプール名を指定する

具体的にこのストレージプールを使うという設定をStorageClass側に入れる事ができます。
StorageClassのパラメータとして、以下の３つを使う事ができます。

- storagePools
- additionalStoragePools
- excludeStoragePools

まず、ここで重要なのが storagePoolsの設定です（残り２つは後で説明します）。  
この設定に "backend名:pool名" を並べる事で使うストレージプールを限定することが可能です。

たとえば、ontapnas_192.168.1.100という バックエンド設定があったとして、
そこに aggr01 という [Aggregate] があったとします（このとき pool名は aggr01となります）。
このaggr01だけを使って Volumeを作りたい場合は、以下の用にStorageClassを作ります。

```yaml:storage-class-aggr01.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nas-fast
provisioner: csi.trident.netapp.io
parameters:
  storagePools: "ontapnas_192.168.1.100:aggr01"
```

#### ストレージプールが持つ属性により制限する

ストレージプールは先程のように、HDDやSSDから構成されたり、暗号化やSnapshotが使える・使えないといったサービスレベルに影響する属性を持ちます。

StorageClass側で、具体的に[Aggregate]を指定するのではなく、「ブロック・ストレージのプールで」、「NFSストレージのプールで」、「SSDのプールで」「暗号化されたプールで」といった様に属性で指定する事が可能です。大規模環境で[Aggregate]が多く存在するような場合に一々名前で指定するのではなく要件を満たす物を[Trident]に自動的に選択してもらうやり方です。

例えば、ブロック・ストレージだけを払い出したい場合、backendTypeという属性を指定する事が可能です。

```yaml:storage-class-san.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: san
provisioner: csi.trident.netapp.io
allowVolumeExpansion: true
parameters:
  backendType: "ontap-san"
```

その他にも色々な属性を指定する事ができますので、詳細は[マニュアル](https://docs.netapp.com/us-en/trident/trident-reference/objects.html#storage-pool-selection-attributes)を参照してください。

ただし、属性によってはプールの選択ではなく、プロビジョニングされるボリュームの種類が変化するだけの場合もあるので注意してください。Thin provisioning/Thick provisioning等は 作られるボリュームが変化するだけでプールの選択には影響を与えません。

### StorageClassの設定による、ストレージプール選択には流れがある

ここまでの説明は同時に適用することが可能です。Tridentは以下の流れでプールを選択します。

1. 設定されたバックエンドで使える、全てのプールの中から、  
   StorageClassの属性にあうストレージプールだけを選び出す
1. 次に、storagePools 設定がある場合、  
   設定されて**いない**プールを除外する
1. 次に、additionalStoragePools設定がある場合、  
   設定されたプールを追加する
1. 次に、excludeStoragePools設定がある場合、  
   設定されたプールを除外する

こうして利用する候補のプールを絞り込むわけです。  
※ 上記以外に PersistentVolumeClaimで指定されたサイズのボリュームが空き容量に収まらない場合はプールから除外されます。
※ 実際の実装とは、流れが少し違う可能性がありますが、考え方はこれで良い。はずです。

### 複数のプール候補があったらどうするの？

上記の工程を経ても、最終的にStorageClassに合致する複数のプールが候補に残った場合、[Trident]はランダムにプールを選択することになります。この場合、確率的に容量消費がストレージプール間で平準化される事になります。

## まとめ

最後にまとめです。

- Tridentは複数のストレージプールを管理する事ができる
- StorageClassの設定によって、ストレージプールが選ばれる
- StorageClassにストレージプールの名前等でフィルターしたり、プールの属性を指定できる

となります。大規模な環境にならない限り、あまり意識する事が無い点ではあります。ただ、逆に大規模環境ではこれらの柔軟性が生きてくる事になるかと思います[^1]。

今回説明した以外に、Virtual Storage Poolといった機能もあるのですが、そこについては[次回]にしたいと思います。

[次回]: https://qiita.com/yasuoohno/items/a2d5ccb67d71a6d83a46
[Trident]: https://docs.netapp.com/us-en/trident/index.html
[Aggregate]: https://kb-ja.netapp.com/Advice_and_Troubleshooting/Data_Storage_Software/ONTAP_OS/What_is_an_aggregate
[バックエンド]: https://docs.netapp.com/us-en/trident/trident-use/backends.html
[プールの選ばれ方]: https://docs.netapp.com/us-en/trident/trident-reference/objects.html#storage-pool-selection-attributes
[プールの選ばれ方 FAQ]: https://docs.netapp.com/us-en/trident/faq.html#how-does-astra-trident-select-a-specific-backend
[特定のプールを使わせたくない FAQ]: https://docs.netapp.com/us-en/trident/faq.html#how-do-i-ensure-that-astra-trident-will-not-provision-from-a-specific-backend
[複数のバックエンドが候補に残ったら FAQ]: https://docs.netapp.com/us-en/trident/faq.html#if-there-are-multiple-backends-of-the-same-kind-how-does-astra-trident-select-which-backend-to-use

[^Trident]: Astra Trident。Kubernetesの CSI Driverとして知られています。コンテナ環境で データを永続化するためのボリュームをプロビジョニングします。
[^Aggregate]: DISKを束ねたRAIDを更に束ねた物です。ユーザは [Aggregate]を直接使うのではなく、[Aggregate]の一部を Volumeとして切り出して使います。
[^1]: 完全に余談ですが、Tridentで実現する Topology Aware Provisioningは、PodのTopology属性と合致したStorage Poolを選択しているだけと考える事もできます。