[01] [k8s]オンプレで動的プロビジョニングを実践してみる (NFS環境)


# 概要

Kubernetes (k8s) の動的プロビジョニングの動作確認のために、
次を実践して、下表の通り 1マスタ・1ノードのオンプレ上に NFS を構築した.
・[[01] オンプレでの動的プロビジョニング用 NFS サーバの構築手順メモ (サーバ側)](https://qiita.com/robozushi10/items/d0ac81161b576104e1ca)
・[[02] オンプレでの動的プロビジョニング用 NFS サーバの構築手順メモ (クライアント側)](https://qiita.com/robozushi10/items/2059127eb7dcafe8a52d)


本記事では **オンプレ上で k8s を使って動的プロビジョニングを実践したときの手順** を記す.

|No|用途|ノード名|形態|IP|OS|NIC|備考|
|:--|:--|:--|:--|:--|:--|:--|:--|
|1|k8sマスタ|PC1|物理ホスト|192.168.10.115|Ubuntu18.04|eno1|NFSサーバである.<br/>/export/nfs を公開している.|
|2|k8sノード|node01|物理ホスト|192.168.10.84|Ubuntu18.04|eno1|NFSクライアントにする|


# 参考にしたサイトおよび書籍

|URL|備考|
|:--|:--|
|https://www.server-world.info/query?os=Ubuntu_20.04&p=nfs&f=1||
|[15Stepで習得 Dockerから入るKubernetes](http://www.ric.co.jp/book/contents/book_1161.html)|K8s だけでなく、Ansible, Vagrant, GlusterFS のことなども学べる.|
|https://github.com/takara9/vagrant-k8s|[『15Stepで習得 Dockerから入るKubernetes』](http://www.ric.co.jp/book/contents/book_1161.html)の著者が公開されている GitHub.<br/>Vagrant や Ansible コードを公開してくださっている.|
|https://github.com/takara9/vagrant-kubernetes|同上|
|https://github.com/takara9/codes_for_lessons|同上|
|https://nextpublishing.jp/book/12197.html|『解体kubeadm　フェーズから読み解くKubernetesクラスタ構築ツールの全貌』を参考にして 1マスタ・1ノードを構築した.|
|http://netstars.co.jp/kubestarblog/kubestarblog5/k8s/||
|https://qiita.com/ysakashita/items/cbfa1403fcd83121a397||
|https://qiita.com/teruq/items/17609eecc29b70e2cbe7||
|https://kamrul.dev/setup-dynamic-nfs-provisioning-in-kubernetes-with-helm-3/|


# 環境

## 物理ホストおよび仮想PC

```bash
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.4 LTS"
```

# 手順

## 1. 事前準備

### 1-1. K8s マスタとノードが稼働していること

下表の No 1 と No 2 が共に稼働していること.

|No|用途|ノード名|形態|IP|OS|NIC|備考|
|:--|:--|:--|:--|:--|:--|:--|:--|
|1|k8sマスタ|PC1|物理ホスト|192.168.10.115|Ubuntu18.04|eno1|NFSサーバ にする.<br/>/export/nfs を公開している.|
|2|k8sノード|node01|物理ホスト|192.168.10.84|Ubuntu18.04|eno1|NFSクライアントにする|


### 1-2. NFS サーバと、NFS クライアントの準備を済ませておくこと

下記 2つを済ませておくこと.

・[[01] オンプレでの動的プロビジョニング用 NFS サーバの構築手順メモ (サーバ側)](https://qiita.com/robozushi10/items/d0ac81161b576104e1ca)
・[[02] オンプレでの動的プロビジョニング用 NFS サーバの構築手順メモ (クライアント側)](https://qiita.com/robozushi10/items/2059127eb7dcafe8a52d)

### 1-3. Helm をインストールしておくこと

下表 No 1 上に Helm をインストールしておくこと.
このとき使用した Helm バージョンは v3.5.4 であった.

|No|用途|ノード名|形態|IP|OS|NIC|備考|
|:--|:--|:--|:--|:--|:--|:--|:--|
|1|k8sマスタ|PC1|物理ホスト|192.168.10.115|Ubuntu18.04|eno1|NFSサーバ にする.<br/>/export/nfs を公開している.|


## 2. Helm を使って「NFS Client Provisioner」をインストールする

Helm を使う理由は、Helm を使わなければ動的プロビジョニングに成功しなかったためである.[^1]

```bash
## NFSサーバの IP (192.168.10.115) と公開ディレクトリ (/export/nfs) を指定する
$ helm install nfs-subdir-external-provisioner \
      nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
      --set nfs.server=192.168.10.115 \
      --set nfs.path=/export/nfs
```

## 3. PVC を作成する

### 3-1. マニフェスト「my-pvc.yml」を作成する

```yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-provisioner
  annotations:
    # StorageClass の名称を指定
    volume.beta.kubernetes.io/storage-class: nfs-client
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      # リクエストするボリュームサイズ
      storage: 5Gi
```

### 3-2. マニフェスト「my-pvc.yml」を使って PVC を作成する

```bash
$ kubectl apply -f my-pvc.yml 
persistentvolumeclaim/my-provisioner created
```

### 3-3. PVC が作成できたことを確認する

下記🛑である.

```bash
$ kubectl get sc,pv,pvc,po -o wide
NAME                                     PROVISIONER                                     RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
storageclass.storage.k8s.io/nfs-client   cluster.local/nfs-subdir-external-provisioner   Delete          Immediate           true                   58s
 
NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                    STORAGECLASS   REASON   AGE   VOLUMEMODE
persistentvolume/pvc-29a230a3-e1ab-4ccb-8607-ef7eda122888   5Gi        RWO            Delete           Bound    default/my-provisioner   nfs-client              3s    Filesystem
 
NAME                                   STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE   VOLUMEMODE
persistentvolumeclaim/my-provisioner🛑 Bound    pvc-29a230a3-e1ab-4ccb-8607-ef7eda122888   5Gi        RWO            nfs-client     3s    Filesystem
 
NAME                                                  READY   STATUS        RESTARTS   AGE    IP             NODE      NOMINATED NODE   READINESS GATES
pod/nfs-subdir-external-provisioner-fdb665bd5-vwd7d   1/1     Running       0          58s    10.244.1.174   node01    <none>           <none>
```

## 4. NFS サーバ側から PV の動作確認をする

下表 No 1 の物理PC (NFSサーバ) から、上記 3 で作成した PV に "ファイル" を書き込んでみる.

|No|用途|形態|IP|OS|NIC|備考|
|:--|:--|:--|:--|:--|:--|:--|
|1|k8sマスタ|物理ホスト|192.168.10.115|Ubuntu18.04|eno1|NFSサーバ にする.<br/>/export/nfs を公開している.|

### 4-1. PV が作成されていることを確認する

```bash
$ ls -dl /export/nfs/default-my-provisioner-pvc-29a230a3-e1ab-4ccb-8607-ef7eda122888/
drwxrwxrwx 2 root root 4096  6月 13 22:29 /export/nfs/default-my-provisioner-pvc-29a230a3-e1ab-4ccb-8607-ef7eda122888//
```

### 4-2. PV にデータを作成する

現在日時を書き込んだファイル「NOW」を作成してみる.

```bash
$ date >> /export/nfs/default-my-provisioner-pvc-29a230a3-e1ab-4ccb-8607-ef7eda122888/NOW

$ cat /export/nfs/default-my-provisioner-pvc-29a230a3-e1ab-4ccb-8607-ef7eda122888/NOW
2021年  6月 13日 日曜日 22:40:13 JST
```


## 5. NFSクライアント側で稼働させた Pod から PV にアクセスする

### 5-1. Nginx を稼働させるためのマニフェスト my-pod.yml を作成する

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: my-nginx
spec:
  containers:
    - name: my-nginx
      image: nginx
      ports:
        - containerPort: 80
          name: web
      volumeMounts:
      - mountPath: /usr/share/nginx/html
        name: nginx-pvc
  volumes:
    - name: nginx-pvc
      persistentVolumeClaim:
        # 作成した PVC 名
        claimName: my-provisioner
```

### 5-2. Nginx を稼働させる

ノード `node01`、すなわち下表 No 2 上に Pod を立てる.

|No|用途|形態|IP|OS|NIC|備考|
|:--|:--|:--|:--|:--|:--|:--|
|2|k8sノード|node01|物理ホスト|192.168.10.84|Ubuntu18.04|eno1|NFSクライアントにする.<br/>/export/nfs を公開している.|

```bash
$ kubectl apply -f my-pod.yml 
pod/my-nginx created

## Nginx が稼働した
$ kubectl get pod my-nginx -o wide
NAME       READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATES
my-nginx   1/1     Running   0          11s   10.244.1.175   node01   <none>           <none>
```

#### 5-3. Pod「my-nginx」にログインして、PV にアクセスする

```bash
## Pod「my-nginx」にログインする
$ kubectl exec -it pod/my-nginx -- bash

## PV にアクセスする
root@my-nginx:/# ls -l /usr/share/nginx/html/
total 4
-rw-r--r-- 1 1000 1000 43 Jun 13 13:40 NOW
 
## 手順 4 にて、物理ホスト側で作成した NOW であることが確認できた
root@my-nginx:/# cat /usr/share/nginx/html/NOW
2021年  6月 13日 日曜日 22:40:13 JST
 
## Pod「my-nginx」の中で NOW を更新する
root@my-nginx:/# date >> /usr/share/nginx/html/NOW

## 「Sun Jun 13 13:43:38 UTC 2021」の一行が追加された
root@my-nginx:/# cat /usr/share/nginx/html/NOW
2021年  6月 13日 日曜日 22:40:13 JST
Sun Jun 13 13:43:38 UTC 2021
```

#### 5-4. NFSサーバ側からファイル「NOW」が更新されたことを確認する

下表 No 1 の物理PC での操作である.

|No|用途|ノード名|形態|IP|OS|NIC|備考|
|:--|:--|:--|:--|:--|:--|:--|:--|
|1|k8sマスタ|PC1|物理ホスト|192.168.10.115|Ubuntu18.04|eno1|NFSサーバ にする.<br/>/export/nfs を公開している.|

```bash
$ cat /export/nfs/default-my-provisioner-pvc-29a230a3-e1ab-4ccb-8607-ef7eda122888/NOW
2021年  6月 13日 日曜日 22:40:13 JST
Sun Jun 13 13:43:38 UTC 2021
```

### 6. 別の Pod からも上記 PV にアクセスできることを確認する

No 2 の物理PC での操作である.

|No|用途|形態|IP|OS|NIC|備考|
|:--|:--|:--|:--|:--|:--|:--|
|2|k8sノード|node01|物理ホスト|192.168.10.84|Ubuntu18.04|eno1|NFSクライアントにする|


#### 6-1. もう1個追加で Pod「my-nginx2」を稼働させる

##### my-pod2.yml を作成する

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: my-nginx2  #!
spec:
  containers:
    - name: my-nginx2 #!
      image: nginx
      ports:
        - containerPort: 80
          name: web
      volumeMounts:
      - mountPath: /usr/share/nginx/html
        name: nginx-pvc
  volumes:
    - name: nginx-pvc
      persistentVolumeClaim:
        # 作成した PVC 名
        claimName: my-provisioner
```

#### 6-2. Pod「my-nginx2」を稼働させる

下記🛑である.

```bash
$ kubectl apply -f my-pod2.yml
 
$ kubectl get pod -o wide
NAME                                              READY   STATUS        RESTARTS   AGE     IP             NODE      NOMINATED NODE   READINESS GATES
my-nginx                                          1/1     Running       0          5m47s   10.244.1.175   node01    <none>           <none>
my-nginx2🛑                                       1/1     Running       0          9s      10.244.1.176   node01    <none>           <none>
```

#### 6-3. Pod「my-nginx2」にログインして、ファイル「NOW」が更新されたことを確認する

```bash
## Pod「my-nginx」にログインする
$ kubectl exec -it pod/my-nginx2 -- bash

## PV にアクセスする
root@my-nginx2:/# ls -l /usr/share/nginx/html/

以下略
```

　

以上.

[^1]: なぜ、Helm を使わない場合に失敗する原因は特定できていないが、RBAC 周りが原因だと推測している