💥

GKE上のpodのストレージが満杯になったときの対応

2024/12/18に公開

Google Kubernetes Engine(GKE)で動かしている pod のストレージが満杯になってしまった際に、今まではコンソールも接続できないために諦めていました。
しかし、調べてみると Persistent Volume(PV)を利用している場合にはいくつかの方法でデータを救出する手段が残されていたため、今回はその方法についてまとめた投稿になります。

前提の話

今回データを救出する pod の基本的な情報になります。

  • pod は Stateful Set で動いている
    • そのまま yaml を書き換えてもストレージサイズが変更できない
  • pod は高々 1 つしか動いていない
  • ストレージは PV を使用している
    • ここが重要で、揮発性のストレージだとダメです

また、想定しているシチュエーションとしては以下のような状況です。

  • ストレージが満杯になり、再起動を繰り返している。
    • 特に、安定した起動ができない
  • コンテナに接続してシェルを起動できない。
    • 再起動を繰り返している or 接続に必要なファイルを生成できないなどの理由による

特に、今回は RDBMS に投入するデータ量が大きすぎてストレージ容量を圧迫したために問題が発生しました。

使用する情報

ここから先のコマンドなどの紹介では、以下の情報を使用しますので、あらかじめ用意しておきます。
Persistent Volume Claim(PVC)は Persistent Volume を要求する設定のことを指し、元は yaml ファイルに記述されています。

  • 問題が発生している pod の属する名前空間
    • yaml ファイルでmetadata.namespaceで定義しているもの
    • ここから先では[namespace]と表記します
  • 問題が発生している pod の名前
    • yaml ファイルでmetadata.nameで定義しているもの
    • ここから先では[pod_name]と表記します
  • 問題が発生している pod が利用している PVC の名前
    • 別途調べる必要があるため、以下のコマンドを実行してNameを得ます
    • ここから先では[pvc_name]と表記します
$ kubectl describe pvc -n [namespace]
Name:          [pvc_name]
Namespace:     [namespace]
StorageClass:  standard-wffc
Status:        Bound
~~~ 中略 ~~~
Capacity:      10Gi
Access Modes:  RWO
VolumeMode:    Filesystem

まずは pod を停止する

利用しているボリュームが PV であれば、pod 自体を停止しただけでは永続ボリュームのためにデータが消失することはありません。
この後の作業のために、あらかじめボリュームをマウントしている pod を停止させておきます。

$ kubectl scale statefulset [pod_name] --replicas=0 -n [namespace]
statefulset.apps/[pod_name] scaled

この先の救助方法には大きく 2 つに分かれると考えていて、具体的には以下のような方法があります。

  • 別の pod で問題のストレージをマウントして、そこで救助活動を行う
    • 単純にファイルを移動させるだけで済む場合にはこちらの方が便利です
    • 生成した画像ファイルが多すぎてパンクしてしまった場合などが該当します
  • 直接使用している PVC の設定を書き換え、ストレージ容量を拡張する
    • データベースのレコードが増えすぎた場合など、ファイルの単純な移動だけでは片付かない場合に便利です

今回はせっかくなので両方について具体的に説明します。

別の pod で PV をマウントする

新たな pod をセットアップするため、以下のような yaml ファイルを作成します。

rescue.yml
apiVersion: v1
kind: Pod
metadata:
  name: pvc-rescue
  namespace: [namespace]
spec:
  containers:
    - name: pvc-rescue
      image: ubuntu
      command: ['/bin/bash', '-c', '--']
      args: ['while true; do sleep 30; done;']
      volumeMounts:
        - name: rescue-data
          mountPath: /mnt/rescue-volume # 必要に応じて変更
  volumes:
    - name: rescue-data
      persistentVolumeClaim:
        claimName: [pvc_name]

コマンドで GKE 上に反映させ、pod が起動したのを確認してから救出作業を開始します。

kubectl apply -f ./rescue.yml

# ローカルのディレクトリ`~/local-rescue-dir`にコピーするコマンド(バックアップ的意味を込めて)
kubectl cp [namespace]/pvc-rescue:/mnt/rescue-volume ~/local-rescue-dir
# 直接シェルを接続して作業する(削除など)
kubectl exec -n [namespace] [pvc-rescueのpod名] -c [pvc-rescueのコンテナ名] -it bash

これにより、安定した別の pod を経由してファイルを操作できます。
なお、作業が完了したら pod は削除しておきましょう。(課金対象となるため)

設定を変更して PV を拡張する

PV の容量を根本的に拡張することにより解決を図るものです。以下のコマンドで直接設定を編集することができます。なお、エディタは vim のようです。
yaml のフォーマットで記述された設定を編集できるので、status.capacity.storageを今回の場合は10Giから20Giに変更しました。

kubectl edit pvc [pvc_name] -n [namespace]

問題の pod を元に戻す

ストレージに余裕を持たせたあとには、pod を元に戻してあげる必要があります。
最初のコマンドと同じ要領で、replica 数を元に戻します。
(状況に応じて数字が異なる場合もあるので、適宜読み替えてください。)

$ kubectl scale statefulset [pod_name] --replicas=1 -n [namespace]
statefulset.apps/[pod_name] scaled

まとめ

今まではストレージが満杯になると操作困難性からデータの救出を諦めてしまっていました。
今回分かった方法を使えば、条件さえ満たしていれば柔軟にデータの救出ができるため、今後は活用していきたいです。
(それはそうと、ストレージが満杯にならないようにそもそも対策しましょう、という話ではありますが...。)

Discussion