839の日記

業務とは関係ない趣味の話を書くブログです。

replicas: 1のStatefulSetのPersistent Volumeサイズを変更する

まず前提としてPVはリサイズが可能です。
refs: Resizing Persistent Volumes using Kubernetes - Kubernetes

1.11以降のクラスタで利用可能な機能で、事前にstorageclassの定義で allowVolumeExpansion: true を付ける必要があります。

自分が検証した際はサイズの増加は可能で減少は行なえませんでした。 とはいえ運用上最小限の設定にしておいたなら増やすことはあれど減らすケースはほぼないと思われます。 よくある例ではMySQLのStatefulSetを定義しサービスイン後にpvcのサイズを増加したいケースでしょうか。

しかしStatefulSet経由のPVCでPVを作成してしまうとディスクサイズの変更ができません。
例えば以下のようなyamlsts内でpvcを作ったとします。

  volumeClaimTemplates:
    - metadata:
        name: my-pvc
      spec:
        accessModes:
          - ReadWriteOnce
        storageClassName: my-storageclass
        resources:
          requests:
            storage: 1Gi

ストレージを2GBにしたい場合は以下のように変更します。

         storageClassName: my-storageclass
         resources:
           requests:
-            storage: 1Gi
+            storage: 2Gi

これをapplyしようとすると以下のようなメッセージが出て変更できません。

The StatefulSet "example-sts" is invalid: spec: Forbidden: updates to statefulset spec for fields other than 'replicas', 'template', and 'updateStrategy' are forbidden

StatefulSetに設定したstorageのサイズを変更する例を調べると StatefulSet: support resize pvc storage in K8s v1.11 · Issue #68737 · kubernetes/kubernetes · GitHub が出てきます。

polarn commented on 5 Mar 2019 @alwinmarkcf You can delete the statefulset without the pods being deleted, by using kubectl delete sts --cascade=false - you can then apply a new statefulset and the pods will keep living.

ではstsは削除しつつpodを削除しないようにすることで新しいstsをapplyする際にpvcのサイズを変更する方法が提案されています。
ただこれはhelmなどで管理していた場合に色々と煩雑なのであまり取りたい手段ではありませんでした。

issueのコメントで

mlmhl commented on 18 Sep 2018 Maybe a better way is to directly update the request size of according PVC object.

とコメントされていますがこれを実現する形で試行し、自分のユースケースでは問題がありませんでした。 以下のようにstsとpvcでyamlを分けてapplyします。

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: pg-sts
spec:
  replicas: 1
  updateStrategy:
    type: RollingUpdate
  selector:
    matchLabels:
      app: pg
  serviceName: pg-svc
  template:
    metadata:
      labels:
        app: pg
    spec:
      volumes:
      - name: my-pv
        persistentVolumeClaim:
          claimName: my-pvc
      containers:
      - name: pg
        image: "postgres:11.5-alpine"
        ports:
        - containerPort: 5432
        volumeMounts:
        - name: my-pv
          mountPath: /var/lib/postgresql/data
        resources: {}
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
  - ReadWriteOnce
  storageClassName: my-storageclass
  resources:
    requests:
      storage: 1Gi

その場合、変更するのはpvc側だけでsts側は変更せずにstorageのサイズを変更できます。 この方式だとStatefulSetを使いつつPVのサイズが変更できます。

以下のURLでissueにコメントしてみたところ、StatefulSetはreplicasのpod数分pvcを作成してくれるようです。 自分は費用的にケチってreplicas: 1で運用していたので気づきませんでしたが、replicas: 3で0をmaster、その他をread replicaで使うなどといったより本番的なユースケースでは上記手法は有効ではなさそうです。
refs: https://github.com/kubernetes/kubernetes/issues/68737#issuecomment-589934270