NFS(2) Kubernetes内でNFSを使ってみる

この記事は「[RookだらけのAdvent Calender](https://qiita.com/advent-calendar/2019/rook)」21日目の記事です。

昨日はRookのnfs-operatorを使ってKubernetesクラスタ内にNFSサーバを建ててみました。本日はNFSサーバにクライアントとなるPodを接続し、ファイル共有が出来ることを確認していきたいと思います。

# NFSサーバ側の構築状況
前回のRookによるNFS環境構築でKubernetesクラスタ内に以下のようなPodが立ち上がっています。

- rook-nfs-operator
- rook-nfs-provisioner
- **rook-nfs**

このうちの**rook-nfs**がNFSサーバとなり、今回はAmazon EBSのボリュームをマウントしてStatefulSetとして起動しています。そのEBSボリュームがNFSでExportされ、クライアントから利用可能となっています。

ここまでを図に表すと以下のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54853/4eeffa4d-83cf-9238-e8fd-0838c9537db7.png)

[RookのNFSデザインガイド](https://github.com/rook/rook/blob/master/design/nfs/nfs.md)には、`This design uses NFS-Ganesha server and NFS v4.`と記載があり、rook-nfsではNFS-Ganershaを利用していて、Configファイルはコンテナ内の`/nfs-ganesha/config/rook-nfs`になります。

実際にこれを見てみると以下のようになっており、EXPORTの詳細な設定は[こちらのCRD](https://rook.io/docs/rook/v1.2/nfs-crd.html)によって変更可能です。

```shell
EXPORT {
        Export_Id = 10;
        Path = /nfs-default-claim;
        Pseudo = /nfs-default-claim;
        Protocols = 4;
        Transports = TCP;
        Sectype = sys;
        Access_Type = RW;
        Squash = none;
        FSAL {
                Name = VFS;
        }
}
NFS_Core_Param
{
        fsid_device = true;
}
```

# クライアントからの接続確認
では、実際にクライアントから構築したNFSサーバへ接続してみます。
これも公式ドキュメントのQuickstart通りに進めてみましょう。

まず、以下のYAMLをapplyし、rook-nfs-provisionerを利用するStorageClassを作成します。引き続いて、PVCも作成します。

```YAML:sc.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  labels:
    app: rook-nfs
  name: rook-nfs-share1
parameters:
  exportName: share1
  nfsServerName: rook-nfs
  nfsServerNamespace: rook-nfs
provisioner: rook.io/nfs-provisioner
reclaimPolicy: Delete
volumeBindingMode: Immediate
```

```shell:StorageClass,PVCの作成
$ kubectl apply -f cluster/examples/kubernetes/nfs/sc.yaml

$ kubectl apply -f cluster/examples/kubernetes/nfs/pvc.yaml
```

次に上記のPVCを使うDeploymentを2つとサービスを作成します。

1. busybox-rc.yaml：NFSで共有されたindex.htmlのホスト名と時間を更新するPod
2. web-rc.yaml：NGINXのポッド、NFSで共有されたindex.htmlを参照する
3. web-service.yaml：2.のポッドに接続するためのサービス(nfs-web)を作成

```shell:Deployment,Serviceの作成
$ kubectl apply -f cluster/examples/kubernetes/nfs/busybox-rc.yaml

$ kubectl apply -f cluster/examples/kubernetes/nfs/web-rc.yaml

$ kubectl apply -f cluster/examples/kubernetes/nfs/web-service.yaml
```

## ここまでの構成
NFSサーバとそれに接続するクライアントを図にしたものが以下となります。いずれのクライアントもRead/Write可能なのですが、今回の構成ではbusyboxがWrite、webサーバがReadという形でアクセスしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54853/737dcfdd-1ca1-a648-fc45-027c39799af0.png)

## Webサーバアクセスによる確認
上図のnfs-webにService経由でアクセスすると、がindex.htmlの内容が更新されていることが分かります。

```shell
$ curl http://nfs-web/
Mon Dec 23 09:10:00 UTC 2019
nfs-busybox-7d8b9c5769-bqbsh

$ curl http://nfs-web/
Mon Dec 23 09:10:02 UTC 2019
nfs-busybox-7d8b9c5769-8vxd2

$ curl http://nfs-web/
Mon Dec 23 09:10:08 UTC 2019
nfs-busybox-7d8b9c5769-bqbsh
```

# まとめ
さて、今回はRookでKubernetes内に構築したNFSサーバへの接続を試してみました。

VM上にNFSサーバを立てることが出来ない/やりたくないケースや、クラウド上のマネージドなファイルシステム（EFS）が使えないケースがあると思います。そのような際にhostpathやEBSなどのCloud Storageを使って、NFSで動的にプロビジョニングできるというのは一定の利用価値があると思います。

StorageClassの入れ替えで本番時のNFSと開発時のNFSを入れ替えられることから、テスト利用にも最適でしょう。

明日からは再度EdgeFS回が続きます。
よろしくお願いします。