Nutanixの外にあるKubernetesからCSI Volume Pluginを使ってNutanixのストレージをPersistent Volumesとして利用する（NFS編）

![スクリーンショット 2020-12-22 18.27.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84474/7522144a-7ff6-875d-f06f-d1ebbe981159.png)

本記事は、Nutanix Advent Calendar 2020の20日目、12月20日分（ただし2日遅れ）としての投稿になります。

**本記事の内容は、この日付時点の情報（Nutanix CSI Plugin 2.2.x系）に基づいています。そのため，今後新しいバージョンが提供された場合に，当該記載と矛盾が生じる場合がありますのでご注意ください。**




# はじめに
アウトプットが出せないうえに進ちょくも出せないエンジニアの @hanakara_milk です、こんばんは。

> この記事の続きとして、なるべく時間を空けないうちに、NutanixのFilesのファイルストレージを利用したPersistent Volumesについても紹介したいと思います。

これが昨年のNutanix Advent Calendar 2019の自分の担当分の結びに書いた言葉ですが、 ほぼ丁度1年後にやっとNutanix CSI Plugin、Files編を書いています。大変申し訳ございません。


さて、昨年に引き続きKubernetesとストレージネタを引っ張ってきました。ここ数年、Kubernetesにおけるステートフルアプリケーションのユースケースが増加傾向にあることと、様々ななCSI実装の拡張やKubernetesのストレージソリューション、エコシステムが登場していることとの間には大きな関連性がある見てよいと思っています。

CSI実装の拡張やストレージエコシステムが増えてきたから、Kubernetesにおけるステートフルアプリケーションのユースケースが増えてきたとも言えますし、Kubernetesにおけるステートフルアプリケーションの要件が増えているからCSI実装の拡張やストレージエコシステムが増えてきたとも言えるかと思います。

その一方で、ステートフルアプリケーションが増えれば増えるほど、データの可用性や耐障害性、運用性などをどうやって担保するのか、そのためにはどのようなアーキテクチャーやインフラストラクチャーが必要なのか考える必要がでてきます。そんな悩みが、昨今のKubernetesのストレージソリューションやエコシステムの急速な進歩を推し進めているのだと思います。

なお、Kubernetesから利用可能なNutanixのストレージについての利点や簡単な概要については、昨年のKubernetes Advent Calendar 2019の2枚目の[15日目](https://qiita.com/hanakara_milk/items/a78f556a8a1df4480e39)をご覧下さい。


# KubernetesからのNutanixストレージ上にあるNFSの利用
あらためまして、今回の投稿は、昨年のNutanix Advent Calendar 2019の[22日目](https://qiita.com/hanakara_milk/items/36a7f38413c0f9f503a9)ではkubeadmでデプロイしたNutanixの外にあるKubernetesから、NutanixのストレージをPersistent Volumesとして、かつブロックストレージで利用することが簡単にできる、と言った内容でしたが、この投稿の冒頭でも触れていますが、その続編的な内容でファイルレベルのストレージ（NFS）編となります。


## Nutanix CSI Volume PluginからNFSを利用するための要件
昨年紹介したブロックストレージをCSI Volume Pluginを使って利用する場合、Nutanix側に特にコレと言った要件はないのですが、ファイルレベルストレージを利用する場合には、少しだけ追加の要件があります。

KubernetesからNutanixストレージをNFSで利用する際には、Nutanix FilesのNFSを利用します。そのため、まずNutanix Filesが必要となります。Nutanix Filesは、Nutanixのストレージをファイルサーバー領域として使える機能で、1TiBまで誰でも無償で利用可能（Nutanix FilesのライセンスはTiB単位）です。

単純にNutanixのストレージ領域をファイルサーバーに提供するだけではなく、Nutanixストレージの従来の高いパフォーマンスと可用性を最大限活かせるよう、基本的に最小3台のNASヘッドとなるファイルサーバー用仮想アプライアンスをNutanix上に起動してNASヘッドクラスターを構成し、ファイルアクセスを分散処理しつつスケールアウト型のファイルサーバーとして機能します。

Nutanix Filesについては、今年のNutanix Advent Calendarにも参加している @masago_Omuomu さんのBlogの中で[特集](https://hanpamonoengineer.blogspot.com/2020/04/nutanix-files.html)を組んで詳しく紹介してくれていますので、そちらをご覧下さい。

##  Nutanix CSI Volume PluginからNFSを利用するための準備
 Nutanix CSI Volume PluginからNFSを利用するための要件であるNutanix Files側には、特にコレと言って特別な設定はないため（正常にNutanix Filesがデプロイされていることが前提ですが）、ここでは、NFSを利用したいKubernetes側の設定について記載していきます。

とは言うものの、Kubernete側の設定は、昨年の[記事](https://qiita.com/hanakara_milk/items/36a7f38413c0f9f503a9#csi-volume-plugin%E3%81%AE%E5%85%A5%E6%89%8B%E3%81%A8%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)とほとんど差はありません。今回も、前回と同様にNutanixの外にある環境にkubeadmで立てたKubernetesにNutanix CSI Volume Pluginをインストールして利用します。

CSIの具体的な導入の手順は、以下のgithubにリンクされているドキュメントからアクセス可能です。
https://github.com/nutanix/csi-plugin

Nutanix CSI driver v2.2.0 documentation
https://portal.nutanix.com/page/documents/details?targetId=CSI-Volume-Driver-v2_2:CSI-Volume-Driver-v2_2

以下の4つのマニフェストをkubectl applyしていきます。

* ntnx-csi-rbac.yaml
* ntnx-csi-provisioner.yaml
* ntnx-csi-node.yaml
* csi-driver.yaml

加えて、secretも作成します。secretは、Nutanixのアドレス、管理者名（基本はadmin）及び管理者名のパスワードをパラメーターとして作成します。secretもサンプルが、上記のGithubから取ってきたcsi-pluginの中に含まれているので、そちらを参考に作成します。

前回の手順と少しだけ変わる部分が、StorageClassの作成です。前回はブロックストレージを利用するためのStorageClassを作成しました。今回はファイルレベルストレージ、NFSを利用するためのStorageClassを作成していきます。


```yaml
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
    name: acs-afs
provisioner: csi.nutanix.com
parameters:
    nfsServer: fs1.ce.local
    nfsPath: nfs
    storageType: NutanixFiles
```

こちらは`nfsServer`の部分と`nfsPath`をNutanix Filesで構成したNFSのサーバー名とNFSシェア名に変更して、applyするだけで問題はありません、もしStorageClass名を変更したい場合は任意のものに変更します。
今回の環境では、Nutanix Community Edition上に展開したNutanix Filesで、NFSのみのファイルサーバーを構成しています。ファイルサーバー名は`fs1`、NFSシェア名は`nfs`としています。一般的なNFSのサーバーのパスとしては、`nfs://fs1.ce.local:/nfs/`となる構成です。

*※ce.localは、今回構成した環境のNutanix Filesやその他のためのドメインです。*

## Nutanix FilesのNFSシェアをKubernetesから利用してみる
次に、今回は時間が押しているためPersistentVolumeClaimからの要求でNFS領域がどのように扱われるかだけ見ていきます。今回の接続環境について確認しておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84474/45580886-d475-c020-ba71-ce26daada41e.png)

今回は操作しているPC上のVirtualBoxに立てたCentOS上に、シングル構成のKubernetesクラスターをkubeadmで構成し、そこからNuatnix Community Edition上のFilesのNFSをNutanix CSI Pluginを介して利用します。

また、Kubernetes上からpersistentVolumeClaim（PVC）で要求されたストレージが、Nutanix FilesのNFSシェアがどのように見えるのかを観察するためのVMをNutanix Community Edition上に1台立てて、`mount`しておきます。以下のとおり、まだNFSにはファイル・フォルダ含めて何もない状態です。

```bash
[root@mon-vm mnt]# mkdir mon-vm
[root@mon-vm mnt]#
[root@mon-vm mnt]# mount -t nfs -o vers=4 fs1.ce.local:/ /mnt/mon-vm/
[root@mon-vm mnt]#
[root@mon-vm mnt]# mount | grep fs1
fs1.ce.local:/ on /mnt/mon-vm type nfs4 (rw,relatime,vers=4.0,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=192.168.137.108,local_lock=none,addr=192.168.137.30)
[root@mon-vm mnt]#
[root@mon-vm mnt]# cd mon-vm/nfs/
[root@mon-vm nfs]# pwd
/mnt/mon-vm/nfs
[root@mon-vm nfs]#
[root@mon-vm nfs]# ls -latr
合計 1
drwxr-xr-x 3 root root 0 12月 21 11:44 ..
drwxrwxrwt 2 root root 2 12月 22 12:37 .
```


さっそく、persistentVolumeClaim（PVC）を作ってNFSシェア内にどのようにpersistentVolume（PV）が要求されるのかを見ていきます。今回は時間の都合上、複雑なことをせずに、ちょっと雑ではありますが、persistentVolume（PV）を利用するサンプルのnginxのDeploymentとpersistentVolumeClaim（PVC）でのストレージの要求だけでみていきます。

初期時点でのstorageclass（SC）、persistentVolumeClaim（PVC）、persistentVolume（PV）、Podの状態をkubectl getしましたが、まだ準備のところで作成したstorageclass（SC）のみが見えている状態です。


```bash
[root@mon-vm AFS]# kubectl get sc,pvc,pv,po
NAME                                  PROVISIONER       RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
storageclass.storage.k8s.io/acs-afs   csi.nutanix.com   Delete          Immediate           false                  24m
[root@mon-vm AFS]#
```

最初にnginxのDeploymentをApplyします。persistentVolume（PV）を要求するnginxのマニフェストは以下のとおり。


```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-with-pv
  labels:
    run: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      run: nginx
  template:
    metadata:
      labels:
        run: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: nfs-share
      volumes:
        - name: nfs-share
          persistentVolumeClaim:
            claimName: afs-claim
```


そうするとpersistentVolume（PV）がまだ作成されていないためPodの作成がPendingになります。


```bash
[root@mon-vm AFS]# kubectl get sc,pvc,pv,po
NAME                                  PROVISIONER       RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
storageclass.storage.k8s.io/acs-afs   csi.nutanix.com   Delete          Immediate           false                  26m

NAME                                READY   STATUS    RESTARTS   AGE
pod/nginx-with-pv-b6cbfc5d7-6fdn8   0/1     Pending   0          8s
pod/nginx-with-pv-b6cbfc5d7-9lwl5   0/1     Pending   0          8s
[root@mon-vm AFS]#
```


このDeploymentで指定されたPodの作成するために必要とされるpersistentVolume（PV）のためのpersistentVolumeClaim（PVC）を作成します。persistentVolume（PV）を要求するpersistentVolumeClaim（PVC）は以下のとおり。


```yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
   name: afs-claim
spec:
   accessModes:
      - ReadWriteMany
   resources:
      requests:
         storage: 30Gi
   storageClassName: acs-afs
```


PersistentVolumeClaim（PVC）によってPersistentVolume（PV）が作成され、Podの作成時に要求していたPersistentVolume（PV）要求が満たされる状態になっため、以下のようにPendingだったPodの作成が動き始めます。


```bash
[root@mon-vm AFS]# kubectl get sc,pvc,pv,po
NAME                                  PROVISIONER       RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
storageclass.storage.k8s.io/acs-afs   csi.nutanix.com   Delete          Immediate           false                  28m

NAME                              STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/afs-claim   Bound    pvc-992c60ac-accf-49bb-8f58-175822243302   30Gi       RWX            acs-afs        54s

NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS   REASON   AGE
persistentvolume/pvc-992c60ac-accf-49bb-8f58-175822243302   30Gi       RWX            Delete           Bound    default/afs-claim   acs-afs                 23s

NAME                                READY   STATUS              RESTARTS   AGE
pod/nginx-with-pv-b6cbfc5d7-6fdn8   0/1     ContainerCreating   0          2m31s
pod/nginx-with-pv-b6cbfc5d7-9lwl5   1/1     Running             0          2m31s
[root@mon-vm AFS]#
```


上記のとおり、作成されたPersistentVolume（PV）は、`persistentvolume/pvc-992c60ac-accf-49bb-8f58-175822243302`となります。では、実際のNFS上での見え方はどうでしょうか。さっそく観察してみます。


```bash
[root@mon-vm nfs]# pwd
/mnt/mon-vm/nfs
[root@mon-vm nfs]#
[root@mon-vm nfs]# ls -ltar
合計 1
drwxr-xr-x 3 root       root       0 12月 21 11:44 ..
drwxr-xr-x 2 4294967294 4294967294 2 12月 22 17:41 pvc-992c60ac-accf-49bb-8f58-175822243302
drwxrwxrwt 3 root       root       3 12月 22 17:41 .
[root@mon-vm nfs]#
```


NFS上に、`pvc-992c60ac-accf-49bb-8f58-175822243302`と言うディレクトリができています。

Deploymentに記載しているとおり、nxingコンテナの`/usr/share/nginx/htmlにfs1.ce.local:/nfs/pvc-992c60ac-accf-49bb-8f58-175822243302`をNFSマウントする形になっています。

*※PersistentVolumeClaim（PVC）では30GiB要求しているが、10GiBしかないのは、Nutanix FilesのNFSシェアが10GiBの容量で作成しているため最大10GiBまでしかとれていない*

実際にコンテナの中に入って`df -h`で確認してみます。

```bash
[root@mon-vm AFS]# kubectl exec nginx-with-pv-b6cbfc5d7-
nginx-with-pv-b6cbfc5d7-6fdn8  nginx-with-pv-b6cbfc5d7-9lwl5
[root@mon-vm AFS]# kubectl exec nginx-with-pv-b6cbfc5d7-6fdn8 -it /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@nginx-with-pv-b6cbfc5d7-6fdn8:/#
root@nginx-with-pv-b6cbfc5d7-6fdn8:/#
root@nginx-with-pv-b6cbfc5d7-6fdn8:/#
root@nginx-with-pv-b6cbfc5d7-6fdn8:/# df -h
Filesystem                                                  Size  Used Avail Use% Mounted on
overlay                                                      14G  4.3G  9.2G  32% /
tmpfs                                                        64M     0   64M   0% /dev
tmpfs                                                       5.9G     0  5.9G   0% /sys/fs/cgroup
/dev/mapper/centos_k8s--nfs-root                             14G  4.3G  9.2G  32% /etc/hosts
shm                                                          64M     0   64M   0% /dev/shm
fs1.ce.local:/nfs/pvc-992c60ac-accf-49bb-8f58-175822243302   10G     0   10G   0% /usr/share/nginx/html
tmpfs                                                       5.9G   12K  5.9G   1% /run/secrets/kubernetes.io/serviceaccount
tmpfs                                                       5.9G     0  5.9G   0% /proc/acpi
tmpfs                                                       5.9G     0  5.9G   0% /proc/scsi
tmpfs                                                       5.9G     0  5.9G   0% /sys/firmware
root@nginx-with-pv-b6cbfc5d7-6fdn8:/#
root@nginx-with-pv-b6cbfc5d7-6fdn8:/# cd /usr/share/nginx/html/
root@nginx-with-pv-b6cbfc5d7-6fdn8:/usr/share/nginx/html# ls
root@nginx-with-pv-b6cbfc5d7-6fdn8:/usr/share/nginx/html#
```

`df -h`で確認したあと、マウントされている`/usr/share/nginx/html/`に移動して`ls`を叩きましたが、こちらのディレクトリには何もファイルがありません。

試しに、観察用のVMからmountして見えているNFS上のPVにサンプルの`index.html`を配置してみます。観察用のVMから見えているPersistentVolume（PV）ですが、こちらのファイルを配置すると、nginxコンテナでマウントされているPersistentVolume（PV）＝`/usr/share/nginx/html/`にファイルが見えるハズです。


```bash
[root@mon-vm pvc-992c60ac-accf-49bb-8f58-175822243302]# vi index.html
[root@mon-vm pvc-992c60ac-accf-49bb-8f58-175822243302]#
[root@mon-vm pvc-992c60ac-accf-49bb-8f58-175822243302]# cat index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <title>NFS PVC 確認用ページ</title>
  </head>
  <body>
    <h1>KubernetesでNFSシェアを利用するためのテストファイル</h1>
    <p>2つのnginxのPodから参照可能なNFSシェアをNutanix FilesのNFSを作成して、Kubeadmで作成したKubernetesクラスターからNutanix CSI PLUGINを通じて利用しています。</p>
  </body>
</html>
[root@mon-vm pvc-992c60ac-accf-49bb-8f58-175822243302]#
```


観察用のVM上で作成された`index.html`ファイルが見えるか、コンテナ内から`ls`で確認します。


```bash
root@nginx-with-pv-b6cbfc5d7-6fdn8:/usr/share/nginx/html# ls
index.html
root@nginx-with-pv-b6cbfc5d7-6fdn8:/usr/share/nginx/html#
```


無事にファイルが見えました。当然ですが、NFSはもともとReadWriteManyで利用可能です。つまり、1つの領域を複数から同時にマウントして参照・利用することが可能です。そのため、観察用のVMでマウントしているNFSに見えている、Kubernetes上のPodで要求したPersistentVolume（PV）は、コンテナからもVMからも同時に同じモノが見える状態になっています。

これでnginxコンテナ内のドキュメントルートに`index.html`が配置されたので、nginxのPodをexposeして外部から参照できるようにします。


```bash
[root@mon-vm AFS]#
[root@mon-vm AFS]# kubectl expose deployment nginx-with-pv --type="NodePort"
service/nginx-with-pv exposed
[root@mon-vm AFS]#
[root@mon-vm AFS]# kubectl get svc nginx-with-pv -o wide
NAME            TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE   SELECTOR
nginx-with-pv   NodePort   10.111.111.156   <none>        80:31009/TCP   17s   run=nginx
```

ブラウザを開いて、この`index.html`がnginxのWebサーバーからきちんと見えるか確認してみます。

![スクリーンショット 2020-12-22 19.14.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84474/025a4324-045b-c5a6-5c5a-42050a67f7eb.png)

無事に見えました。では、今度は、この`index.html`ファイルを観察用VMから消してみます。


```bash
[root@mon-vm pvc-992c60ac-accf-49bb-8f58-175822243302]# pwd
/mnt/mon-vm/nfs/pvc-992c60ac-accf-49bb-8f58-175822243302
[root@mon-vm pvc-992c60ac-accf-49bb-8f58-175822243302]#
[root@mon-vm pvc-992c60ac-accf-49bb-8f58-175822243302]# ls
index.html
[root@mon-vm pvc-992c60ac-accf-49bb-8f58-175822243302]#
[root@mon-vm pvc-992c60ac-accf-49bb-8f58-175822243302]# rm index.html
rm: 通常ファイル `index.html' を削除しますか? y
[root@mon-vm pvc-992c60ac-accf-49bb-8f58-175822243302]#
[root@mon-vm pvc-992c60ac-accf-49bb-8f58-175822243302]# ls
[root@mon-vm pvc-992c60ac-accf-49bb-8f58-175822243302]#
```

ブラウザをリロードすると、当然、`index.html`が消えているため、このようになります。

![スクリーンショット 2020-12-22 18.18.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84474/071e6ea7-f129-c28c-7485-884801624a10.png)

最後にpersistentVolumeClaim（PVC）、persistentVolume（PV）、storageclass（SC）、Pod/Deployment/Serviceを消して、この環境のお掃除をしておきます。

```bash
[root@mon-vm AFS]# kubectl delete deployments.apps nginx-with-pv
deployment.apps "nginx-with-pv" deleted
[root@mon-vm AFS]#
[root@mon-vm AFS]# kubectl delete service nginx-with-pv
service "nginx-with-pv" deleted
[root@mon-vm AFS]#
[root@mon-vm AFS]# kubectl delete pvc afs-claim
persistentvolumeclaim "afs-claim" deleted
[root@mon-vm AFS]#
[root@mon-vm AFS]# kubectl delete pv pvc-992c60ac-accf-49bb-8f58-175822243302
persistentvolume "pvc-992c60ac-accf-49bb-8f58-175822243302" deleted
[root@mon-vm AFS]#
[root@mon-vm AFS]# kubectl delete sc acs-afs
storageclass.storage.k8s.io "acs-afs" deleted

[root@mon-vm AFS]# kubectl get sc,pvc,pv,po,svc
NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   3h54m
[root@mon-vm AFS]# kubectl get sc,pvc,pv,po
No resources found
[root@mon-vm AFS]#
```

# まとめ
Nutanix CSI Pluginは、既にNutanixがある場合や、これからNutanixを導入する場合でも、Kubernetes環境に対して簡単にストレージを提供することが可能です。

ちょっとコンテナとコンテナ、コンテナとVM、コンテナと物理マシンでのファイル共有等がしたいと言った際には、NFSの場合、手軽にファイル共有ができるため、特に個人利用や開発等では重宝するかもしれません（この手の行為は商用環境ではあまりお勧めできませんが…）。

駆け足になりましたが、ショートバージョンでNutanix FilesのNFSをKubernetesから利用した場合の様子を紹介させていただきました。

NutanixのCSI Volume Pluginは、Kubernetesからステートフルなアプリケーションのためのブロックストレージ、そしてファイルレベルストレージの両方を提供できるだけでなく、今回、ご紹介できませんでしたが、ストレージの拡張、LVMボリュームのサポート、ボリュームのクローン、スナップショットとリストア、NFSの動的にプロビジョニング、IPホワイトリストやiSCSI認証など多数の機能があります。

今回は時間の都合で雑にまとめましたが、今後これらの詳細などについても投稿したいと思います。