LoginSignup
1
0

VolumeをReadWriteOnceからReadWriteOncePodへ移行する

Last updated at Posted at 2024-01-18

手元のクラスタにReadWriteOnceのPVがあったので、これをReadWriteOncePodに変更したので、その時に調査した内容を紹介します。

ReadWriteOncePodはKubernetes1.22でAlpha機能ととして登場し、1.27からBetaとなり、最新の1.29でGAした機能です。

基本的な動作については以下の記事が詳しいです。

さて、今回はすでにデプロイしてしまっているPVについて、1つのPodからしか利用していないのでReadWriteOncePodに変更することをやってみました。

なぜ実施するのか?

ReadWriteOnceに設定したVolumeは同じNodeに配置された他のPodからもマウントすることが出来ますが、多くの場合そのようなマウントができることは不要です。

セキュリティ文脈における最小権限の原則からも、不要なことは出来ないようにしておくことが望ましいです。

PVをeditする

まず変更実施すべきはPVです。
実体として1つのPodしかVolumeをマウントしていないケースにおいては単純にPVをeditしてAccessModeReadWriteOncePodに変更することで、これを実現できます。

すでに複数のPodがマウントしているPVをReadWriteOncePodに変更したらどうなる?

ちょっと気になったのでやってみたところ、変更することができ、妙な状況となりました。

この状態は、矛盾を抱えており、例えば、そのPodの1つを再生成しようとすると、Volumeがマウントできなくて失敗します。

このような状況にならないように、PVのaccessModesを変更する際は、1つのPodのみが該当のPVをマウントしていることを確認することが大切です。

PVCはどうなる?

PVをeditしたときPVCはどうなるのかが気になって調べてみました。
結果としてはPVCのspecのaccessModesはそのままReadWriteOnceで、statusのaccessModeReadWriteOncePodとなりました。

apiVersion: v1
kind: PersistentVolumeClaim
...
spec:
  accessModes:
  - ReadWriteOnce  # ← ここと
...
status:
  accessModes:
  - ReadWriteOncePod  # ← ここ
  phase: Bound
...

この状態で、PVはReadWriteOncePodとなっているので、他のPodからはマウントできない状態となっており、機能としては意図した状態になっているといえばそうです。

また、kubectl get pvcの結果はstatusを表示しているので、一見すると問題はなさそうに見えます。

kubectl get pvc
NAME  STATUS   VOLUME       CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pvc   Bound    pvc-xxxxxx   3Gi        RWOP           sc-xxxxxxxx    XdYh

しかし、このようなちょっとイレギュラーな状態は、Kubernetesのコーナーケースに当たるため、なにか今後の機能変更時にバグを引き当てたりしそうなので、なるべく避けたいという気持ちもあります。

PVCも修正したい

PVCのspecのaccessModesは後から変更することが出来ないので、ここを変更するためには、PVCを一度削除して作り直す必要があります。

しかし、PVのReclaimPolicyDeleteになっている場合は、PVCを削除することで対応するPVが一緒に削除されてしまうので作業には注意が必要です。

前節で説明したようにPVをeditしてReadWriteOncePodにしておけば、PVCのspecがReadWriteOnceでも、別のPodからはマウントできなくなるので、PVCはそのままにしておく、というのも一つの手かなと思いました。

一方でこの方法は、Kubernetesのマニフェストをリポジトリなどで管理している場合、そのマニフェストを流用して別のシステムを構築する際に、PVがReadWriteOnceで作られてしまうという問題があります。

かといって、PVCのマニフェストだけを修正すると、今度は構成変更を反映するためにそのマニフェストをapplyする際に変更できないエラーとなってしまい、これも不便です。

ということで、以降はPVCを修正する方法を見ていきます。

StatefulSetを使いPVCを作っている場合

StatefulSetのvolumeClaimTemplatesを使ってPVCを作っている場合は、管理しているマニフェストはStatefulSetのものなので、まず修正すべきはStatefulSetです。

StatefulSetのvolumeClaimTemplatesは後から変更できないので、StatefulSetの作り直しが必要です。

StatefulSetを消してもPVCは残るので、StatefulSetを消して、accessModesReadWriteOncePodに変更したStatefulSetをデプロイすることで、管理しているマニフェストと実環境の矛盾を解消できます。

さて、StatefulSetのみを変更してデプロイし直しができればこれで十分でしょうか?
この際、PVCは以前のStatefulSetの作ったものが引き続き利用されるので、PVCのspecのaccessModesReadWriteOnceのままという状況になります。
実体としてのPVはReadWriteOncePodに変更済みなので、実質的な問題はなさそうです。

しかし、やはりPVとPVC、StatefulSetのvolumeClaimTemplatesのaccessModeが異なることは、ややこしいので、後に紹介する方法でPVCも作り直すのが良いと考えます。

謎のPending

この作業をやっている時に、StatefulSetのYAMLに妙なフィールドがあることに気づきました。
.spec.volumeClaimTemplates.statusというフィールドです。

以下のように何故か、specの中なのにstatusというフィールドが有り、ずっとPendingという値になっています。

この件は一応 https://github.com/kubernetes/kubernetes/issues/65706 でバグ報告されていたようですが、特に対応されずCloseされています。

他のリソースの様子をみても問題はないので、Pendingであることを気にする必要はなさそうです。

$ kubectl get statefulset -n hedgedoc -o yaml
apiVersion: v1
items:
- apiVersion: apps/v1
  kind: StatefulSet
...
spec:
...
    volumeClaimTemplates:
    - apiVersion: v1
      kind: PersistentVolumeClaim
      metadata:
        creationTimestamp: null
        name: test-ss
      spec:
        accessModes:
        - ReadWriteOnce
        resources:
          requests:
            storage: 3Gi
        storageClassName: test-ss
        volumeMode: Filesystem
      status:
        phase: Pending # <---- これ
...
  status:

PVCを作り直す

PVの内容が消えて良い場合は単純にPVCを消せばOKですが、一般的にPVの内容は保持したいと思うので、その前提で手順を紹介します。

該当PVのpersistentVolumeReclaimPolicyを変更して、PVCと連動して削除されないようにする。

kubectl patch pv <PVの名前> -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'

この手順では事前にPVCを利用しているPodはすべて削除する必要があります。

PVCを削除

kubectl delete pvc <PVCの名前>

PVがRelease状態になるので、再び利用できるようにする

kubectl patch pv <PVの名前> -p '{"spec":{"claimRef": null}}'

(これ以降に次のPVC作成の手順を実施するまでの間に、何処か別の仕組みでPVCが作られると、このPVがBindされてしまう事があるので注意)

accessModesReadWriteOncePodに変更したPVCを作成

StatefulSetでPVCを作る場合は、volumeClaimTemplatesを変更すると読み替えてください。

この際.spec.volumeNameで紐づけしたいPVの名前を指定することで、意図通りのPVに紐付けることが出来ます。
(一方で.spec.volumeNameはあとから編集できないフィールドなので、これをマニフェストファイルに記載して、リポジトリで管理するような場合は、このフィールドの記載がこのクラスタに特化した内容になってしまう点に注意が必要です。)

# 一例です
kubectl apply -f pvc.yaml

これで、PVもPVCもReadWriteOncePodを設定できました。

PVのpersistentVolumeReclaimPolicyをもとに戻す

kubectl patch pv <PVの名前> -p '{"spec":{"persistentVolumeReclaimPolicy":"Delete"}}

まとめ

新しく使えるようになったReadWriteOncePodを既存のVolumeに適用する方法を紹介しました。
PV周りは、ちょっと手順を間違えるとデータが消えてしまったりするので、慎重な作業が必要です。

不要なPodからのマウントを防ぐことは、特にKubernetesクラスタを他のチームと共用している場合などに非常に有効な設定です。手順はちょっと面倒ですが、早めに対応するのが良いでしょう。

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0