はじめに
本検証では、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 でストレージを使ったユースケースが広がるポテンシャルをもっているため、ユースケースの広がりに期待します。