自動プロビジョニングできるKubernetesのNFSストレージクラスの作成

# はじめに
皆さんはKubernetesにNFSサーバーをストレージとして使いたいときはありませんか？そんなとき，いざNFSサーバーを作ってみてもいちいちPVを作るのはめんどくさいですよね．PVCだけ作れば勝手にPVを作って欲しいですよね！

そんな人のためにNFSの自動プロビジョニングしてくれるストレージクラスを作成します！

# 構築環境
全てUbuntu 22.04.1 LTSで実行しています．IPアドレスは例として出しています．各自のサーバーのアドレスに合わせて書き換えてみて下さい．
- Kubernetesクラスター
    - 192.168.100.50
    - 192.168.100.51
    - 192.168.100.52
- NFSサーバー
    - 192.168.100.233

## 環境確認

- NFSのアドレス
    - 192.168.100.233
- NFSのパス
    - /home/cdsl

NFSのアドレスはNFSサーバーでhostnameコマンドを実行して下さい．

```shell
$ hostname -I
192.168.100.233
```

NFSサーバーの/etc/exportsを確認して下さい．この/home/cdslがNFSのパスになります．

```config:/etc/exports
# /etc/exports: the access control list for filesystems which may be exported
#               to NFS clients.  See exports(5).
#
# Example for NFSv2 and NFSv3:
# /srv/homes       hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
#
# Example for NFSv4:
# /srv/nfs4        gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
# /srv/nfs4/homes  gss/krb5i(rw,sync,no_subtree_check)
#

# General export for /home/cdsl
/home/cdsl 192.168.100.50/24(rw,sync,no_subtree_check,no_root_squash)
/home/cdsl 192.168.100.51/24(rw,sync,no_subtree_check,no_root_squash)
/home/cdsl 192.168.100.52/24(rw,sync,no_subtree_check,no_root_squash)
```

# NFSのストレージを作成するshellscript


```shell:nfs-client.sh
#!/bin/bash
set -eux
NFS_SERVER_IP=192.168.100.233
NFS_PATH=/home/cdsl


# command install
sudo apt-get update
# curlがインストールされているか確認
if ! command -v curl &> /dev/null
then
    echo "curlがインストールされていません。インストールします。"
    sudo apt-get install -y curl
else
    echo "curlは既にインストールされています。"
fi
# gnupg (実際には gpg コマンド) がインストールされているか確認
if ! command -v gpg &> /dev/null; then
    echo "gnupgがインストールされていません。インストールします。"
    sudo apt-get install -y gnupg
else
    echo "gnupgは既にインストールされています。"
fi
# dpkgがインストールされているか確認
if ! command -v dpkg &> /dev/null
then
    echo "dpkgがインストールされていません。インストールします。"
    sudo apt-get install -y dpkg
else
    echo "dpkgは既にインストールされています。"
fi

# helm install
# https://helm.sh/ja/docs/intro/install/
# helmが既にインストールされているか確認
if ! command -v helm &> /dev/null; then
    echo "helmがインストールされていません。インストールします。"
    # helmのインストールコマンド
    curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null
    echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
    sudo apt-get update
    sudo apt-get install helm
else
    echo "helmは既にインストールされています。"
fi

# nfs-subdir-external-provisioner install
if ! helm list -A | grep -q nfs-client-provisioner; then
    echo "NFS External Provisioner がインストールされていません。インストールします。"
    helm repo update
    helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
    helm install nfs-client-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
      --set nfs.server=${NFS_SERVER_IP} \
      --set nfs.path=${NFS_PATH} \
      --set storageClass.name=nfs-client
else
    echo "NFS External Provisioner は既にインストールされています。"
fi
```

nfs-client.shを実行します．
```shell
$ ./nfs-client.sh
+ NFS_SERVER_IP=192.168.100.233
+ NFS_PATH=/home/cdsl
+ sudo apt-get update
[sudo] password for ono:
Hit:1 https://artifacts.elastic.co/packages/8.x/apt stable InRelease
Ign:2 https://repo.stns.jp/jammy stns InRelease
Hit:3 https://packages.treasuredata.com/4/ubuntu/focal focal InRelease
Hit:4 https://baltocdn.com/helm/stable/debian all InRelease
Hit:5 http://jp.archive.ubuntu.com/ubuntu jammy InRelease
Hit:6 http://jp.archive.ubuntu.com/ubuntu jammy-updates InRelease
Hit:7 http://jp.archive.ubuntu.com/ubuntu jammy-backports InRelease
Ign:2 https://repo.stns.jp/jammy stns InRelease
Hit:8 http://jp.archive.ubuntu.com/ubuntu jammy-security InRelease
Ign:2 https://repo.stns.jp/jammy stns InRelease
Err:2 https://repo.stns.jp/jammy stns InRelease
  500  Internal Server Error [IP: 157.7.190.242 443]
Reading package lists... Done
W: Failed to fetch https://repo.stns.jp/jammy/dists/stns/InRelease  500  Internal Server Error [IP: 157.7.190.242 443]
W: Some index files failed to download. They have been ignored, or old ones used instead.
+ command -v curl
+ echo curlは既にインストールされています。
curlは既にインストールされています。
+ command -v gpg
+ echo gnupgは既にインストールされています。
gnupgは既にインストールされています。
+ command -v dpkg
+ echo dpkgは既にインストールされています。
dpkgは既にインストールされています。
+ command -v helm
+ echo helmは既にインストールされています。
helmは既にインストールされています。
+ helm list -A
+ grep -q nfs-client-provisioner
+ echo 'NFS External Provisioner がインストールされていません。インストールします。'
NFS External Provisioner がインストールされていません。インストールします。
+ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "elastic" chart repository
...Successfully got an update from the "nfs-subdir-external-provisioner" chart repository
Update Complete. ⎈Happy Helming!⎈
+ helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
"nfs-subdir-external-provisioner" already exists with the same configuration, skipping
+ helm install nfs-client-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner --set nfs.server=192.168.201.5 --set nfs.path=/home/cdsl --set storageClass.name=nfs-client
NAME: nfs-client-provisioner
LAST DEPLOYED: Mon Mar 25 08:54:51 2024
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
```

ストレージクラスを確認します．
```shell
$ kubectl get sc
NAME            PROVISIONER                                                            RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
local-storage   kubernetes.io/no-provisioner                                           Delete          WaitForFirstConsumer   false                  32d
nfs-client      cluster.local/nfs-client-provisioner-nfs-subdir-external-provisioner   Delete          Immediate              true                   10m
```

nfs-clientが出来ていますね！

```shell
$ kubectl get pods -n default | grep nfs-client-provisioner
nfs-client-provisioner-nfs-subdir-external-provisioner-64f64d88   1/1     Running   0          17m
```

ちゃんとRunning状態になっています．

これでPVCのyamlファイルのstorageClassNameにnfs-clientを指定すればPVが勝手に作られます！