はじめに
本検証では、CSI を使った Ephemeral Volume として Kubernetes v1.16 で Beta となったCSI Ephemeral Volume と、Kubernetes v1.21 で Beta となった Generic Ephemeral Volume について検証を行い、その違いを示します。
Ephemeral Volume とは
Ephemeral とは「儚い、短命な」という意味です。これに対して Persistent は「永続的な」という意味です。つまり、Ephemeral Volume とはデータの永続化を目的としたものでなく、一時的なデータの保存を目的としたボリュームになります。
Kubernetes においては、Pod のライフタイムに従い、Podと共に作成/削除されるボリュームを指します。
Kubernetes では、以下の種類のEphemeral Volumeをサポートしています(こちらを参考)。
- emptyDir
- kubelet のベースディレクトリ又はRAM(メモリ)から空の領域をPodへボリュームとして割り当てます
 - データはkubeletが稼働しているノード上に格納されます
 
 - configMap, downwardAPI, secret
- KubernetesのリソースをPodへボリュームとして割り当てます
 
 - CSI Ephemeral Volume (※)
- 特定のCSI Driver を通じ作成されるボリュームをPodへ割り当てます
 - データはCSI Driverのターゲットとなるストレージに格納されます
 
 - Generic Ephemeral Volume
- 通常のPVC/PVの仕組み(Dynamic Provisionig)を使い作成されるボリュームをPodへ割り当てます
 - データはCSI Driverのターゲットとなるストレージに格納されます
 
 
上記に示すように、CSI Ephemeral Volume と Generic Ephemeral Volume は、emptyDir と異なり、ノードのメディアやRAM上の保存するのではなく、CSI Driverのターゲットとなるストレージに保存されます。
そのため、ノードのメディア(SSD/HDD)やRAMの容量を超えるサイズのデータを保存できます。
CSI Ephemeral Volume と Generic Ephemeral Volume の違いについては、以下の動作検証を通じ紹介します。
※ CSI Ephemeral Volumeは、以前 CSI Inline Volume と呼ばれていたこともあり、各種 CSI Driver のドキュメントでは Inline Volume と記載されていることがあります。
動作検証
CSI Ephemeral Volume と Generic Ephemeral Volume の動作検証を行います。
検証環境
- minikube v1.19.0
- Kubernetes v1.21.0
 
 - CSI Driver: csi-driver-host-path
 
動作検証
事前準備 (csi-driver-host-path のセットアップ)
minikubeを使いKubernetes v1.21.0を--feature-gates=CSIVolumeHealth=true  を指定し立ち上げます。
$ minikube start --vm-driver=virtualbox --kubernetes-version=1.21.0 
minikubeによりKubernetes v1.21.0が起動したことを確認します。
次に、Volume Health Monitorに対応しているcsi-driver-host-pathをセットアップします。
$ git clone git@github.com:kubernetes-csi/csi-driver-host-path.git
$ cd csi-driver-host-path/
$ deploy/kubernetes-latest/deploy.sh
...
error: unable to recognize "/Users/ysakashi/code/golang/src/github.com/kubernetes-csi/csi-driver-host-path/deploy/kubernetes-latest/snapshotter/csi-hostpath-snapshotclass.yaml": no matches for kind "VolumenapshotClass" in version "snapshot.storage.k8s.io/v1"
VolumenapshotClassでエラーが出ますが、今回はVolumenapshot関連のリソースをデプロイしていないため、無視します。
csi-driver-host-pathのPodが起動していることを確認します。
$ kubectl get pod 
NAME                   READY   STATUS    RESTARTS   AGE
csi-hostpathplugin-0   8/8     Running   0          30m
...
次に、StorageClassをセットアップします。
$ kubectl apply -f examples/csi-storageclass.yaml 
storageclass.storage.k8s.io/csi-hostpath-sc created 
$ kubectl get sc
NAME                 PROVISIONER                RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
csi-hostpath-sc      hostpath.csi.k8s.io        Delete          Immediate           true                   32m
standard (default)   k8s.io/minikube-hostpath   Delete          Immediate           false                  46m
CSI Ephemeral Volume の動作検証
まず、CSI Ephemeral Volume の動作検証を行います。
CSI Ephemeral Volume は、これをサポートしている CSI Driver でしか利用できません。
既に使われている CSI Driver がサポートしているかは、csidrivers リソースの Mode を確認してください。
$ kubectl get csidrivers.storage.k8s.io 
NAME                  ATTACHREQUIRED   PODINFOONMOUNT   STORAGECAPACITY   TOKENREQUESTS   REQUIRESREPUBLISH   MODES                  AGE
hostpath.csi.k8s.io   true             true             false             <unset>         false               Persistent,Ephemeral   49m
Mode にEphemeralがない(Persistentのみの)CSI Driver は CSI Ephemeral Volume は利用できません。
また、Kubernetes CSI Developer Document/Drivers に記載の表の"Persistence (Beyond Pod Lifetime)" の列でも Ephemeral をサポートしているか否かを確認できます。
以下に CSI Ephemeral Volume を使ったManifest(inline.yaml)を示します。
- inline.yaml
 
kind: Pod
apiVersion: v1
metadata:
  name: my-csi-app
spec:
  containers:
    - name: my-frontend
      image: busybox
      volumeMounts:
      - mountPath: "/data"
        name: my-csi-inline-vol
      command: [ "sleep", "1000000" ]
  volumes:
    - name: my-csi-inline-vol
      csi:
        driver: hostpath.csi.k8s.io
spec.volumes.csi.driver に CSI Driver 名を記載します。
これにより、Pod の作成/削除時に、指定された CSI Driver へ Volume の作成/削除のリクエストが飛びます。
inline.yaml をデプロイします。
$ kubectl apply -f inline.yaml 
pod/my-csi-app created
$ kubectl get pod,pvc,pv
NAME                       READY   STATUS    RESTARTS   AGE
...
pod/my-csi-app             1/1     Running   0          28s
csi-driver-host-path の CSI Ephemeral Volume では、PVC/PV は作成されません。
kubectl describe コマンドで確認します。
$ kubectl describe pod my-csi-app 
...
Volume:
  my-csi-inline-vol:
    Type:              CSI (a Container Storage Interface (CSI) volume source)
    Driver:            hostpath.csi.k8s.io
    FSType:            
    ReadOnly:          false
    VolumeAttributes:  <none>
...
上記のように、my-csi-inline-vol として Type: CSI の Volume がマウントされているのが確認できます。
Pod のコンテナに入り確認すると /data にマウントされているのがわかります。
$ kubectl exec -ti my-csi-app -- mount |grep '/data'
tmpfs on /data type tmpfs (rw,relatime,size=5357132k)
csi-driver-host-path では、tmpfs を割り当てる実装となっていますが、外部ストレージを利用する CSI Driver の場合は、外部ストレージ上に Volume が作成されコンテナにマウントされます。
Pod を削除します。
$ kubectl delete pod my-csi-app 
pod "my-csi-app" deleted
Pod の削除と共に、Volume も削除されます。
csi-driver-host-path では mock device で実際に Volume が削除されたかを確認出来ないため、ここでは割愛します。
Generic Ephemeral Volume の動作検証
次に、Generic Ephemeral Volume の動作検証を行います。
Generic Ephemeral Volume は Dynamic Provisioningをサポートしている CSI Driver で利用できます。
言い換えると、Generic Ephemeral Volume は、CSI Ephemeral Volumeとは異なり、csidrivers リソースの Mode が PersistentのみのCSI Driver でも利用できます。
また、Kubernetes CSI Developer Document/Drivers の "Dynamic Provisioning" の列でも確認できます。
以下に、Generic Ephemeral Volume を使ったManifest(generic.yaml)を示します。
- generic.yaml
 
kind: Pod
apiVersion: v1
metadata:
  name: my-app
spec:
  containers:
    - name: my-frontend
      image: busybox
      volumeMounts:
      - mountPath: "/data"
        name: generic-volume
      command: [ "sleep", "1000000" ]
  volumes:
    - name: generic-volume
      ephemeral:
        volumeClaimTemplate:
          spec:
            accessModes: [ "ReadWriteOnce" ]
            storageClassName: csi-hostpath-sc
            resources:
              requests:
                storage: 1Gi
spec.volumes.ephemeral.volumeClaimTemplate に、PVC のテンプレートとなる内容を記載します。これにより Pod の作成/削除時に、volumeClaimTemplate に従い PVC が作成/削除されます。
generic.yaml をデプロイします。
$ kubectl apply -f generic.yaml 
pod/my-app created
$ kubectl get pod,pvc,pv
NAME                       READY   STATUS    RESTARTS   AGE
...
pod/my-app                 1/1     Running   0          16s
NAME                                          STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS      AGE
persistentvolumeclaim/my-app-generic-volume   Bound    pvc-57a8431b-9afd-4c53-addc-34615c95e03d   1Gi        RWO            csi-hostpath-sc   16s
NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                           STORAGECLASS      REASON   AGE
persistentvolume/pvc-57a8431b-9afd-4c53-addc-34615c95e03d   1Gi        RWO            Delete           Bound    default/my-app-generic-volume   csi-hostpath-sc            16s
Podの作成と共にPVCが作成され、Dynamic Provisioning により PVC に Bound される PV が自動生成後、Pod にマウントされます。
この PVC/PV、Podへのマウントの処理は、通常のPersistent Volume と同じです。
次に、Pod を削除します。
$ kubectl delete pod my-app 
pod "my-app" deleted
$ kubectl get pvc,pv
No resources found
Pod が削除されると、併せて PVC/PV も削除されます。
通常のPersistent Volume だと、Podが削除されてもPVC/PV は削除されませんが、Generic Ephemeral Volume では Pod の削除と連動し削除されます。
感想
今回は永続ボリューム(Persistent Volume)ではなく、短命なボリューム(Ephemeral Volume) について、動作検証を行いました。
検証により動作はわかったものの、次の2点が気になる人も多いのではないでしょうか。
- CSI Ephemeral Volume, Generic Ephemeral Volume のユースケース
 - CSI Ephemeral Volume と Generic Ephemeral Volume のどちらを使うべきか?
 
1点目のユースケースを考えるにあたり、ポイントはノードのリソースを使う emptyDir よりも大きなデータを扱うシーンではないでしょうか。
さらに、Ephemeral Volumeのため、Podのライフサイクルに併せて使われる一時的なデータの保存領域が必要なユースケースが対象となります。
一例としては、以下のようなユースケースにマッチするのではないでしょうか
- 画像処理や音声処理のように、中間データを出力するアプリケーション
- 入力データと最終的な出力データは永続ボリュームに保存するが、処理中にのみ利用する中間データの格納場所としてEphemeral Volumeを活用
 
 
その他のユースケースとしては、Ephemeral Volume に格納するデータは小さいが、1台のノードに多数のPodを詰め込みたい場合も活用できます。
emptyDir はノードのリソース(メディアやRAM)を使うため、これらのリソースがネックになりノードあたりに配置できるPod数が少なくなってしまうことがあります。
このような場合に CSI Ephemeral Volume や Generic Ephemeral Volumeは有効な回避方法のひとつではないでしょうか。
2点目のCSI Ephemeral Volume と Generic Ephemeral Volume のどちらを使うべきかについては、特段の理由が無い限りは、Kubernetes v1.21でBetaとなった Generic Ephemeral Volume を利用するのが、個人的なお勧めです。理由としては以下です。
- CSI Ephemeral VolumeをサポートしているCSI Driver は限定的(数が少ない)
 - CSI Ephemeral Volumeの仕様はCSI Driver毎に独自仕様(今回の動作検証では利用しなかったspec.volumes.csi.volumeAttributesで指定)
 - Generic Ephemeral Volumeの方が後発であり、今後CSI Driverをサポートするベンダーは
PersistentとEphemeralを区別せず楽に実装できるGeneric Ephemeral Volumeを選択すると予測 - Generic Ephemeral Volumeは、永続ボリューム(
Persistent)でサポートしている機能(Volume ExpansionやVolume Snapshotなど)が利用可能 
CSI を使った Ephemeral Volume は、ステートフルアプリケーション以外でもKubernetes でストレージを使ったユースケースが広がるポテンシャルをもっているため、ユースケースの広がりに期待します。