Kubernetes: Resizing Persistent Volumeの動作検証

# 概要
本検証では、Kubernetes v1.11 からサポートしているResizing Persistent Volumeの動作検証を行います。Resizing Persistent Volumeは、Volumeのサイズが不足してきた場合にデータを保持したままVolumeのサイズを拡張する機能になります。
2019/5時点で本機能をサポートしているVolumeは以下のものになります。

- AWS-EBS
- GCE-PD
- Azure Disk
- Azure File
- Glusterfs
- Cinder
- Portworx
- Ceph RBD
- CSI (Alpha) 

Resizing Persistent Volumeでは、Podを再作成が基本必要となりますが、Podの再作成が不要なOnline File System Expansionもあります。ただし、Online File System ExpansionはAlpha機能となり、[Feature Gates](https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/)を事前に指定する必要があります。

# 動作検証
今回の検証では、基本となるPodの再作成によるサイズ拡張を行います。

## 検証環境
本環境では、Resizing Persistent VolumeをサポートしているGKEを使い検証します。GKEについては[公式ドキュメント](https://cloud.google.com/kubernetes-engine/docs/?hl=ja)を参照ください。

- GCE 1.12.7-gke.10 (Kubernetes 1.12.7)

## StorageClassのデプロイ
最初にStorageClass(SC)をデプロイします。
以下に、SCのManifest(`storageclass.yaml`)を示します。

```storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gold
parameters:
  type: pd-standard
provisioner: kubernetes.io/gce-pd
allowVolumeExpansion: true
reclaimPolicy: Delete
```

Resizing Persistent Volumeを有効にするためには、`allowVolumeExpansion`をtrueに設定します。
SCのManifest(`storageclass.yaml`)をデプロイします。

```
$ kubectl create -f storageclass.yaml 

$ kubectl get sc
NAME                 PROVISIONER            AGE
gold                 kubernetes.io/gce-pd   74m
```

## PVC, Podのデプロイ
次に、Resizing Persistent Volumeを検証に利用するPersistentVolumeClaim(PVC)とPodをデプロイします。
以下に、PVCのManifest(`pvc.yaml`)とPodのMainfest(`pod.yaml`)を示します。

```pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: myclaim
spec:
  accessModes:
  -  ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: gold
```

PVCのManifestでは、`storageClassName`に上記SCの`gold`を指定します。

```pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: ubuntu
spec:
  containers:
  - name: ubuntu
    image: ubuntu:18.10
    command:
      - sleep
      - infinity
    volumeMounts:
    - mountPath: /mnt/data
      name: mydata
  volumes:
    - name: mydata
      persistentVolumeClaim:
        claimName: myclaim
```

作成するPodでは、`persistentVolumeClaim`に上記PVCの`myclaim`を指定します。PVCによって作成されるVolumeを`/mnt/data`にマウントします。
PVCのManifest(`pvc.yaml`)とPodのManifest(`pod.yaml`)をデプロイします。

```
$ kubectl create -f pvc.yaml 
$ kubectl create -f pod.yaml 
```

デプロイしたPod, PVC, PVを確認します。
PersistentVolume(PV)はDynamic ProvisioningによりPVCをデプロイすることで自動生成されます。

```
$ kubectl get pod
NAME     READY   STATUS    RESTARTS   AGE
ubuntu   1/1     Running   0          38s

$ kubectl get pvc
NAME      STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
myclaim   Bound    pvc-bcd4ff63-760a-11e9-8fbd-42010a800209   1Gi        RWO            gold           49s

$ kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   REASON   AGE
pvc-bcd4ff63-760a-11e9-8fbd-42010a800209   1Gi        RWO            Delete           Bound    default/myclaim   gold                    51s
```

1Gi(Giga Bytes)のサイズのPVC, PVが生成されています。

# Resizing
次に、Resizingを試します。
Resizingは、PVCの`.resouces.requests.storage`のサイズを変更することで行います。
kubectl patchコマンドを使いサイズを1Giから5Giに変更します。

```
$ kubectl patch pvc myclaim -p "{\"spec\":{\"resources\":{\"requests\":{\"storage\": \"5Gi\"}}}}"
```

PVCのサイズを変更した後、PVCに関連付け(Bound)されているPVを確認します。

```
$ kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   REASON   AGE
pvc-bcd4ff63-760a-11e9-8fbd-42010a800209   5Gi        RWO            Delete           Bound    default/myclaim   gold                    11m
```

すると、サイズが5Giに拡張されているのがわかります。
この時、PVCを確認するとサイズは変わらず1Giのままとなっています。

```
$ kubectl get pvc
NAME      STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
myclaim   Bound    pvc-bcd4ff63-760a-11e9-8fbd-42010a800209   1Gi        RWO            gold           11m
```

続いてPVCの詳細をkubectl describe コマンドで確認します。

```
$ kubectl describe pvc myclaim
...
Conditions:
  Type                      Status  LastProbeTime                     LastTransitionTime                Reason  Message
  ----                      ------  -----------------                 ------------------                ------  -------
  FileSystemResizePending   True    Mon, 01 Jan 0001 00:00:00 +0000   Tue, 14 May 2019 16:08:23 +0900           Waiting for user to (re-)start a pod to finish file system resize of volume on node.
...
```

すると、ConditionにPodがstartもしくはre-startされるまでサイズ変更を待っているとの状態であることがわかります。
続いて、Podを再作成します。

```
$ kubectl delete -f pod.yaml 
$ kubectl create -f pod.yaml 
```

Pod,PVCを確認します。

```
$ kubectl get pod
NAME     READY   STATUS    RESTARTS   AGE
ubuntu   1/1     Running   0          81s

$ kubectl get pvc
NAME      STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
myclaim   Bound    pvc-bcd4ff63-760a-11e9-8fbd-42010a800209   5Gi        RWO            gold           13m
```

Podの再作成を行うと、PVCのサイズが5Giに変更されているのが確認できます。

# 感想
今回は、Kubernetes 1.11でBetaとなったResizing Persistent Volumeの動作検証を行いました。Kubernetesの下位で使用されているストレージ機器の多くはThin Provisioningを有しているため、あらかじめ巨大なサイズのVolumeを割り当てておき、実際にデータが書き込まれた場合のみ物理デバイス(HDD, SSDなど)を消費するように設定し運用しているケースも多くあるかと思います。予めサイズ予測ができるようケースにおいては、Thin Provisioningで巨大なサイズのVolumeを割り当てておく運用でも十分かもしれません。
一方で、AI/MLなどで利用する学習データの保持用のVolumeなどサイズ予測が難しい場合があります。このような場合においては、Resizing Persistent Volumeは有効な手段のひとつになります。また、パブリッククラウドのKubernetesにてPVC, PVのサイズによって課金が発生する場合においても、格納するデータが小さい使い始めのフェーズから無駄に巨大なサイズのVolumeを割り当てるのはコストの無駄にもつながります。
Kubernetesで運用するアプリケーションやデータの増加傾向に応じて、Thin Provisioningを使い巨大なサイズのVolumeをあらかじめ割り当てるのか、それともResizingを使いVolumeのサイズを徐々に増やしていくのかを決め運用するのが良いのではないでしょうか。

# 参考情報
- [Resizing Persistent Volumes using Kubernetes](https://kubernetes.io/blog/2018/07/12/resizing-persistent-volumes-using-kubernetes/)