【Kubernetes】StatefulSetでPodごとにログを保存する方法|volumeClaimTemplatesとreclaimPolicyの動作を検証

kubenetesロゴ

KubernetesでStatefulSetを使うと、「Podごとに専用のボリューム」を持たせることができます。

ただし、スケール操作(3→2→3など)を行うと、ログが消えるケースがあるため注意が必要です。

この記事では、以下の内容を実際の検証手順とともに解説します。

  • StatefulSetでPod名を取得してログに書き込む方法
  • volumeClaimTemplatesの仕組み
  • スケールダウン後にログが消える原因
  • reclaimPolicyをRetainに変更する方法
  • スケール後もログを保持する方法

StatefulSetを作成してPodごとにログを書き込む

まずはStatefulSetを作成します。

ファイル名は statefulSet-write-podName.yaml とします。

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: sample-statefulset
spec:
  serviceName: sample-statefulset
  replicas: 3
  selector:
    matchLabels:
      app: sample-app
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
      - name: busybox-container
        image: busybox
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        command:
        - sh
        - -c
        - |
          echo "Starting container in pod $POD_NAME" >> /usr/share/date/log.txt
          while true; do date >> /usr/share/date/log.txt; sleep 180; done
        volumeMounts:
        - name: date-log
          mountPath: /usr/share/date/
  volumeClaimTemplates:
  - metadata:
      name: date-log
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 50Mi

作成します。

kubectl apply -f statefulSet-write-podName.yaml

Podごとのログを確認する

作成されたPodは以下のようになります。

sample-statefulset-0
sample-statefulset-1
sample-statefulset-2

ログを確認します。

kubectl exec -it sample-statefulset-0 -- cat /usr/share/date/log.txt
kubectl exec -it sample-statefulset-1 -- cat /usr/share/date/log.txt
kubectl exec -it sample-statefulset-2 -- cat /usr/share/date/log.txt

それぞれのPodで違うログが保存されていることが確認できます。

StatefulSetは同じボリュームを共有していない

StatefulSet + volumeClaimTemplates を使用すると、Podごとに専用のPVCが自動作成されます。

replicas: 3 の場合は以下のようになります。

sample-statefulset-0 → PVC: date-log-sample-statefulset-0
sample-statefulset-1 → PVC: date-log-sample-statefulset-1
sample-statefulset-2 → PVC: date-log-sample-statefulset-2

つまり、Podごとに別のボリュームを持つ設計になっています。

スケールダウンしてみる(3 → 2)

次にPod数を減らしてみます。

kubectl scale statefulset sample-statefulset --replicas=2

もう一度スケールアップ(2 → 3)

kubectl scale statefulset sample-statefulset --replicas=3

再度 sample-statefulset-2 が作成されます。

ログを確認します。

kubectl exec -it sample-statefulset-2 -- cat /usr/share/date/log.txt

以前のログが消えてる?

以前のログが消えている原因

原因は StorageClassのreclaimPolicyがDeleteになっているためです。

確認してみます。

kubectl get sc

Delete の場合、Pod削除時にPVCとPVも削除されるため、ログも消えてしまいます、、。

StorageClassを変更して、PersistVolumeが残るようにする

既存のStorageClassは直接変更できません。
そのため、コピーして新しく作成します。

下記コマンドを実行してyamlを作成

kubectl get sc standard -o yaml > standard-retain.yaml

名前とreclaimPolicy: Retain を変更

変更前

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"storage.k8s.io/v1","kind":"StorageClass","metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"true"},"labels":{"addonmanager.kubernetes.io/mode":"EnsureExists"},"name":"standard"},"provisioner":"k8s.io/minikube-hostpath"}
    storageclass.kubernetes.io/is-default-class: "true"
  creationTimestamp: "2025-07-18T07:02:00Z"
  labels:
    addonmanager.kubernetes.io/mode: EnsureExists
  name: standard
  resourceVersion: "310"
  uid: b611f5ee-6b0f-4636-a49b-04f716a8f9d4
provisioner: k8s.io/minikube-hostpath
reclaimPolicy: Delete
volumeBindingMode: Immediate

変更後

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"storage.k8s.io/v1","kind":"StorageClass","metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"true"},"labels":{"addonmanager.kubernetes.io/mode":"EnsureExists"},"name":"standard"},"provisioner":"k8s.io/minikube-hostpath"}
    storageclass.kubernetes.io/is-default-class: "true"
  creationTimestamp: "2025-07-18T07:02:00Z"
  labels:
    addonmanager.kubernetes.io/mode: EnsureExists
  name: standard-2
  resourceVersion: "310"
  uid: b611f5ee-6b0f-4636-a49b-04f716a8f9d4
provisioner: k8s.io/minikube-hostpath
reclaimPolicy: Retain
volumeBindingMode: Immediate

作成します。

kubectl apply -f standard-retain.yaml

StatefulSet側もStorageClassを変更する

volumeClaimTemplatesに storageClassName を追加します。

volumeClaimTemplates:
- metadata:
    name: date-log
  spec:
    accessModes:
    - ReadWriteOnce
    resources:
      requests:
        storage: 50Mi
    storageClassName: standard-2

再作成します。

kubectl replace --force -f statefulSet-write-podName.yaml

再度スケールしてログが残るか確認

まずはログを確認

kubectl exec -it sample-statefulset-2 -- cat /usr/share/date/log.txt

次にスケールダウン

kubectl scale statefulset sample-statefulset --replicas=2

もう一度スケールアップ

kubectl scale statefulset sample-statefulset --replicas=3

ログを確認

kubectl exec -it sample-statefulset-2 -- cat /usr/share/date/log.txt

今度はログが消えずに残っていることが確認できます。

まとめ

今回のポイントは以下の4つです。

  • StatefulSetはPodごとに専用PVCを作成する
  • volumeClaimTemplatesを使うと自動でボリュームが作成される
  • reclaimPolicyがDeleteだとスケール時にログが消える
  • Retainに変更するとログを保持できる