はじめに
このページはKubernetes v1.23でアルファ機能となったAuto remove PVCs created by StatefulSet
に関するまとめになります。
Kubernetes 1.23: SIG-Apps の変更内容
を確認する中で、面白いなと思ったので記事にしてみました。
Auto remove PVCs created by StatefulSetについて
Auto remove PVCs created by StatefulSet
はStatefulSet削除にvolumeClaimTemplates
で作成されてPVCを削除する機能になります。
機能追加の背景
StatefulSetではvolumeClaimTemplates
を使用することにPersistentVolumeClaim(PVC)が作成され、Storage ClassがPVCを元にPersistentVolume(PV)を作成することにより、利用者はPVCとPVのリソースを明示的に作成することなくVolumeを使用することができます。
利用者は以下の例示するようなyamlを作成する必要がなくなったことがvolumeClaimTemplates
のメリットになります。
- PersistentVolumeClaim(PVC)の例
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: myclaim
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 8Gi
storageClassName: slow
selector:
matchLabels:
release: "stable"
matchExpressions:
- {key: environment, operator: In, values: [dev]}
- PersistentVolume(PV)の例
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0003
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: slow
mountOptions:
- hard
- nfsvers=4.1
nfs:
path: /tmp
server: 172.17.0.2
StatefulSetを削除した際にvolumeClaimTemplates
によって作成されたPVCは削除されないため、利用者は必要に応じてPVCを手動で削除する必要があります。
これはPodのライフサイクルとデータのライフサイクルが異なるために、データの削除については意図してStatefulSetから分離されているためです。あくまでStatefulSetはPodのライフサイクルを管理する機能であって、データのライフサイクルを管理するためのものではないことに気をつけてください。
ただ、こちらのissueにあるようにStatefulSetを削除した際にvolumeClaimTemplates
によって作成されたPVCが削除されて欲しいという声も多かったため、機能として追加されることになりました。
機能の利用方法
以下のようにStatefulSetのspec
にpersistentVolumeClaimRetentionPolicy
が追加されており、Delete
を指定することで該当機能が有効になります。
apiVersion: apps/v1
kind: StatefulSet
:
spec:
persistentVolumeClaimRetentionPolicy:
whenDeleted: Retain # デフォルトは`Retain`
whenScaled: Delete # デフォルトは`Retain`
:
-
whenDeleted
StatefulSetが削除された時にDelete
の場合は、PVCを削除する機能になります。 -
whenScaled
StatefulSetのレプリカ数が減った時にDelete
の場合は、PVCを削除する機能になります。
実際の動作結果
- クラスタの作成
今回の例ではminikubeを使用します。
$ minikube start --kubernetes-version v1.23.0 --feature-gates=StatefulSetAutoDeletePVC=true
アルファ機能なので、feature-gatesのStatefulSetAutoDeletePVC
を有効化する必要があります。
- Manifestの作成
以下のようにpersistentVolumeClaimRetentionPolicy
でDelete
を設定したManifestを用意します。
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx
serviceName: "nginx"
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: k8s.gcr.io/nginx-slim:0.8
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
persistentVolumeClaimRetentionPolicy:
whenDeleted: Delete
whenScaled: Delete
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "standard"
resources:
requests:
storage: 1G
- Manifestの適用
$ kubectl apply -f StatefulSet.yaml
statefulset.apps/web created
$ kubectl get sts,po,pvc,pv
NAME READY AGE
statefulset.apps/web 3/3 44s
NAME READY STATUS RESTARTS AGE
pod/web-0 1/1 Running 0 44s
pod/web-1 1/1 Running 0 32s
pod/web-2 1/1 Running 0 29s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/www-web-0 Bound pvc-81240f89-c62e-4536-be78-3d27f292a770 1Gi RWO standard 44s
persistentvolumeclaim/www-web-1 Bound pvc-e3221c3d-cf3e-4c0f-8ce6-96d20d126876 1Gi RWO standard 32s
persistentvolumeclaim/www-web-2 Bound pvc-200dc5d9-dd8d-4037-b3bb-fc1a13eb34e5 1Gi RWO standard 29s
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pvc-200dc5d9-dd8d-4037-b3bb-fc1a13eb34e5 1Gi RWO Delete Bound default/www-web-2 standard 29s
persistentvolume/pvc-81240f89-c62e-4536-be78-3d27f292a770 1Gi RWO Delete Bound default/www-web-0 standard 39s
persistentvolume/pvc-e3221c3d-cf3e-4c0f-8ce6-96d20d126876 1Gi RWO Delete Bound default/www-web-1 standard 32s
StatefulSetではvolumeClaimTemplates
とStorage Classの機能により、PVまで作成されていることが確認できます。
- Manifestの削除
$ k delete -f StatefulSet.yaml
statefulset.apps "web" deleted
$ kubectl get sts,po,pvc,pv
No resources found
StatefulSetではvolumeClaimTemplates
で作成されたPVCがStatefulSetの削除後に自動で削除されることが確認できます。
ここで一点気をつけて欲しいのが、PVが削除されたのはあくまでPVのReclaim Policy
に基づいたものであり、 Auto remove PVCs created by StatefulSet
とは直接関係ないということです。
whenDeleted
とwhenScaled
の使い分け
whenDeleted
とwhenScaled
に対して、Retain
とDelete
が設定できるため、Auto remove PVCs created by StatefulSet
では4つのパターンが存在します。それぞれの使い分け方について説明します。
-
whenDeleted
=Retain
&whenScaled
=Retain
(未指定時の動作)
k8s v1.22以前と同じ動作になります。StatefulSetからデータのライフサイクルが分離されているため、StatefulSetの削除によりPVCが削除されることはありません。 -
whenDeleted
=Delete
&whenScaled
=Retain
StatefulSet削除時にPVCが削除されますが、レプリカ数が減少した時にPVCが削除されることはありません。再度スケールする際に、PVの作成コストが減らせるというメリットがあります。 -
whenDeleted
=Delete
&whenScaled
=Delete
StatefulSet削除時とレプリカ数が減少した時にPVCを削除します。そのためPod数以上にPVCが作成されることがありません。Podの削除以降に、該当のデータを使用する必要がない場合に使用します。 -
whenDeleted
=Retain
&whenScaled
=Delete
StatefulSet削除にPVCは削除せず、レプリカ数が減少した時にPVCを削除します。これはスケールアップ時のデータについては保持する必要がないが、起動時のデータは保持しておきたい場合などに使います。最低限3個のPVは必要だが、それ以降にスケールアップしたときに作成されたPVは不要な場合などに有用です。
ただし、最低3個のPVを保持したい場合でも、whenScaled
は有効化されてるのでレプリカ数が1になればPVCも1個になります。HPAと併用する場合はminReplicasを3にするなど、この機能とは別のところでレプリカ数に対するガードをかけないとPVが消える可能性がある点に注意してください。
気をつける点
Auto remove PVCs created by StatefulSet
はStatefulSetに対してデータのライフサイクルに関する権限の譲渡する機能になります。そのため、StatefulSetの削除による誤ったデータ削除のリスクがあることに気をつけてください。
個人的には以下の3つくらいのパターンは起こっても不思議はないなと思っています。
-
Manifest更新時に削除してしまう。
手動で作業時にapply
を使う場面で、一度きれいにしておきたくてdelete
をする。商用環境でやることはなかなかないと思いますが、テスト中くらいなら普通にやるケースはある気がしてます。 -
kubectl apply --prune
で誤って削除してしまう
prune
の機能は非常に便利なんですが、誤った利用による事故も多いのでこれはこの機能限らず気をつけてほうがいいと思います。個人的には商用環境での手動でのprune
の利用は禁止してもいいんじゃないかなくらいに、使いたくないです。 -
CDツールによる意図しない
delete
の実行
通常はapplyを使用してると思うのですが、force sync
みたいな機能では中でdelete
実装されてるケースもあるのかなという不安があります。Deploymentの場合は意図せずdelete
が走っても一時的にPodがなくなるだけなんですが、今回の機能を利用しているとデータが削除される可能性があるので大変心配してます。この機能を有効化する際には必ずお使いのCDツールの挙動を把握するようにしてください。
所感
データを誤って削除するリスクは怖いものの、便利な機能かなと思います。手元でテストした後にPVCを手動で消すのは正直、めんどくさいのでこの機能があるとありがたいです。
参考
Auto remove PVCs created by StatefulSet
に関連する情報は以下を参考にしました。