NetApp/Trident: 既存ストレージボリュームのインポート

## はじめに

NetApp/Trident v19.04.0 の大きな新機能として既存のボリュームがインポートできるようになりました。ここでは、この機能を検証します。

- https://github.com/NetApp/trident/blob/v19.04.0/docs/kubernetes/operations/tasks/volumes.rst#importing-a-volume

## 機能概要

v19.04.0 から `ontap-nas`, `ontap-nas-flexgroup`, `solidfire-san`, `aws-cvs` ドライバですでに存在しているストレージボリュームを Kubernetes にインポートできるようになりました。利用ケースとしては次が上げられています。

- アプリケーションをコンテナ化して既存のデータセットを再利用する
- 一時的な (ephemeral) アプリケーションのためのデータセットのクローン利用
- 障害が発生した Kubernetes クラスタの再構築
- ディザスタリカバリ中のアプリケーションデータのマイグレーション

既存のストレージボリュームのインポートは、`tridentctl` コマンドで実行します。

```
$ tridentctl import volume <backendName> <volumeName> -f <path-to-pvc-file>
```

インポートにはストレージボリュームを含むストレージバックエンド名を `<backendName>` として指定し、一意のボリューム名を `<volumeName>` として指定します。

`-f <path-to-pvc-file>` は必須引数で、YAML または JSON 形式で記述された PersistentVolumeClaim (PVC) マニフェストを含むファイルを指定します。このマニフェストファイルは、ボリュームのインポート処理のなかで PVC オブジェクトを作成するために使用されます。次のように少なくとも、オブジェクト名、Namespace、accessModes、ストレージサイズ、storageClassName の各フィールドを含む必要があります。[^storage-size]

[^storage-size]: Trident v19.07.0 からインポートに使用する PVC マニフェストでストレージサイズ（`.spec.resources.requests`) の指定が必須ではなくなりました

```yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my_claim
  namespace: my_namespace
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: my_storage_class
```

ボリュームインポートを実行すると、既存のストレージボリュームが PersistentVolume (PV) として作成され、その PV の ClaimRef として引数で指定した PVC が設定されます。作成した時点では、reclaim policy は `retain` に設定されますが、PVC と PV が正常に割り当てられれば (bind)、その後 StorageClass の reclaim policy と一致するように更新されます。当然ながら reclaim policy が `delete` になっていると PV が削除されるとともに外部ストレージ上のボリュームが削除されることに注意が必要です。しかし `--no-manage` オプションを指定してボリュームをインポートすると、Trident がそのストレージボリュームの PV、PVC に対して追加の操作を実行しないようになります。つまり、PV オブジェクトが作成されたとしてもストレージボリュームが削除されなくなります。ボリュームクローンやボリュームサイズ変更といった操作も実行されなくなることに注意してください。

インポートされたストレージボリュームの PV、PVC はインポートされたことがわかるようにアノテーションが設定されます。このアノテーションは削除してはいけません。

ストレージボリュームのインポート処理のなかでは、そのボリュームが正しくマウントできるかどうかは確認されません。そのため、正しくマウントできないといったインポートの失敗を確認した場合（例えば StorageClass が正しくないなど）、PV の reclaim policy を `retain` に変更したのちに PV を削除しもう一度インポートを実行することで回復できます。Tip として、`--no-manage` オプションを使用してインポートを実行し、マウントできることを確認できたら、一度 PV、PVC を削除したのちに、`--no-manage` オプションを今度は利用せずにインポートするという手順を取ると安全に検証を進められるでしょう。

## 機能検証

ここからは実際にボリュームインポートを実行します。ここでは事前に `tridentctl` と Trident のバージョンを v19.04.1 に更新しています。

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

$ tridentctl import -h
Import an existing resource to Trident

Usage:
  tridentctl import [command]

Available Commands:
  volume      Import an existing volume to Trident

Flags:
  -h, --help   help for import

Global Flags:
  -d, --debug              Debug output
  -n, --namespace string   Namespace of Trident deployment
  -o, --output string      Output format. One of json|yaml|name|wide|ps (default)
  -s, --server string      Address/port of Trident REST interface

Use "tridentctl import [command] --help" for more information about a command.
```

`tridentctl import` コマンドが利用できそうなことを確認しました。また、ここでは `ontapnas` バックエンドを使う `ontap-file` StorageClass (SC) が設定されているとします。

```
$ tridentctl get backend -n trident
+----------+----------------+--------+---------+
|   NAME   | STORAGE DRIVER | STATE  | VOLUMES |
+----------+----------------+--------+---------+
| ontapnas | ontap-nas      | online |       0 |
+----------+----------------+--------+---------+
```

それでは、`sample-nas-volume` という名前のボリュームをインポートしていきます。まずは、インポートに使用する PVC を用意します。

```
$ cat sample-nas-volume-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: sample-nas-volume
  namespace: default
spec:
  storageClassName: ontap-file
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
```

次に用意した PVC のマニフェストファイルを使って `sample-nas-volume` をインポートします。

```
$ tridentctl import volume ontapnas sample-nas-volume -f ./sample-nas-volume-pvc.yaml -n trident
+--------------------------+---------+-----------------+----------+----------+------+
|           NAME           |  SIZE   | STORAGE CLASS   | PROTOCOL | BACKEND  | POOL |
+--------------------------+---------+-----------------+----------+----------+------+
| default-ontap-file-f02a4 | 1.0 GiB | ontap-file      | file     | ontapnas |      |
+--------------------------+---------+-----------------+----------+----------+------+

$ kubectl get pv | grep ontap
default-ontap-file-f02a4            1073741824   RWO            Delete           Bound    default/ontap-file    ontap-file            35s

$ kubectl get pv default-ontap-file-f02a4 -oyaml
apiVersion: v1
kind: PersistentVolume
metadata:
  annotations:
    pv.kubernetes.io/provisioned-by: netapp.io/trident
    trident.netapp.io/notManaged: "false"
    volume.beta.kubernetes.io/storage-class: ontap-file
  creationTimestamp: "2019-06-06T02:51:14Z"
  finalizers:
  - kubernetes.io/pv-protection
  name: default-ontap-file-f02a4
  resourceVersion: "21148985"
  selfLink: /api/v1/persistentvolumes/default-ontap-file-f02a4
  uid: f2ed65a9-8805-11e9-ae99-fa163e526645
spec:
  accessModes:
  - ReadWriteOnce
  capacity:
    storage: "1073741824"
  claimRef:
    name: ontap-file
    namespace: default
    uid: f02a438a-8805-11e9-ae99-fa163e526645
  nfs:
    path: /******_default_ontap_file_dcaf6
    server: xx.xx.xx.xx
  persistentVolumeReclaimPolicy: Delete
  storageClassName: ontap-file
  volumeMode: Filesystem
status:
  phase: Bound
```

正しくインポートできました。

## まとめ

ここでは、2019年4月にリリースされた NetApp/Trident v19.04.0 で導入された既存のボリュームのインポート機能を検証しました。`ontap-san` ドライバのサポートがまだないので、今後に期待しています。