LoginSignup
8
5

More than 3 years have passed since last update.

【KubernetesのPersistentVolume】その3- StatefulSet

Last updated at Posted at 2019-06-30

目次

StatefulSetとは

DBなどのステートフルなアプリケーションのためのリソース。
つまり、Podを再度作成しても、同じPod名、host名で作成される。

Pod起動、停止、削除時の挙動

  • 新たにPodが起動されるたびに、以下のように末尾に連番で番号が付与されていく。
    • {Pod name}-0, {Pod name}-1, {Pod name}-2・・・
  • Pod起動時は、ナンバリングが小さいものから起動する
  • Pod削除時は、ナンバリングが大きいものから停止、削除される

Podのスケーリング時

Podのスケーリング時には、StatefulSetのPodが全てReadyになっている必要がある。

$ sudo kubectl get sts
NAME                  READY   AGE
sample-statefuleset   2/2     26m

Podのローリングアップデート

Podの停止、削除と同様、番号の大きなPodから実施される。

Volumeについて

  • Podが起動すると、前回と同じPersistentVolumeClaimsが使用される
  • Podが削除されても、使用していたPersistentVolumeClaimsは削除されない

担保されること

  • Stable, unique network identifiers.(固定のネットワーク識別子)
  • Stable, persistent storage.(固定の永続ストレージ)
  • Ordered, graceful deployment and scaling.(順番を担保したデプロイとスケーリング)
  • Ordered, automated rolling updates.(順番を担保した削除と終了)

参照:Using StatefulSets

Node、Podの障害時の挙動について

StatefulSetではPodのSTATUSがUnknownになってもPodを自動起動しない。
どういうことなのか、まずはkubleteによるPodの監視方法について理解する必要がある。

kubeletによるPodの監視方法について

各Nodeのkubeletが、masterに定期的にPodの状態を報告することでPodの状況を監視している。
つまり、Nodeの障害などでkubeletが落ちると、masterはPodの状態が確認できなくなる。
Deploymentなどでは、このようなNodeの障害が起きた場合、別のNodeに新たなPodを自動起動することでリカバリをする。

しかし、kubeletが落ちているが、Podは落ちていないという状況もあり得る。
この状況で別Nodeに新たにPodを起動すると、Podの2重起動という状況になる。
Volumeをマウントしている場合、複数のPodからの書き込みが発生することになる。
この状況は、アプリケーションによってはデータが壊れる可能性がある。

StatefulSetでkubeletに障害が起きた場合の挙動

StatefulSetではこれを防ぐために、kubeletが落ちても新たにPodの自動起動をしない。
言い換えると、Podを手動で削除しない限り、新たなPodは起動されない。

Podを自動で起動してほしい場合

Deploymentなど、StatefulSet以外のリソースを使う必要がある。

以下の記事がわかりやすい。
参考:KubernetesのStatefulSetを疑ってみたが濡れ衣だった

ハンズオン

StatefulSetの定義

以下の例ではNFSにmountしている。NFSにmountする方法は以下を参照。
参考:【KubernetesのPersistentVolume】その2- Dynamic Provisionerを使ってNFSサーバーをPodにmountする

statefulset.yaml
kind: StatefulSet
apiVersion: apps/v1beta1
metadata:
  name: sample-statefuleset
spec:
  serviceName: statefuleset-service
  replicas: 2
  # これを定義することでRollingUpdateされる
  updateStrategy:
    # RollingUpdate or OnDelete。Default: RollingUpdate
    # OnDeleteだとPodは自動的に更新されず、手動でPodを削除すると、自動的に新しいPodが起動される。
    type: RollingUpdate
    ##############################################################
    # partitionを設定すると、指定した番号以上のPodのみが更新される。
    # 以下の例だと、{Pod名}-1以上のPodが更新され、{Pod名}-0は更新されない。
    ##############################################################
    #rollingUpdate:
    #  partition: 1
  # Podの定義
  template:
    metadata:
      labels:
        app: sample-statefuleset
    spec:
      containers:
      - name: sample-container
        image: gcr.io/google-samples/hello-app:1.0
        volumeMounts:
        - name: sample-pvc
          mountPath: /var/data
  # 以下のTemplateでPersistentVolumeClaimを作成する
  volumeClaimTemplates:
  - metadata:
      name: sample-pvc
    spec:
      resources:
        requests:
          storage: 1Gi
      accessModes:
      - ReadWriteOnce
      # storageClassNameを省略するとHostPathでホストOS上にmountされる
      storageClassName: nfs

作成

$ sudo kubectl apply -f statefulset.yaml

確認

Podが2つ起動している。

$ sudo kubectl get pod
sample-statefuleset-0                     1/1     Running   0          25s
sample-statefuleset-1                     1/1     Running   0          16s

statefulsetが作成されている。

$ sudo kubectl get statefulset
NAME                  READY   AGE
sample-statefuleset   2/2     96s

PersistentVolumeClaimが作成されている。

$ sudo kubectl get pvc
sample-pvc-sample-statefuleset-0   Bound    pvc-092e4166-cc92-460b-b9b7-5361dffdebe5   1Gi        RWO            nfs            4m
sample-pvc-sample-statefuleset-1   Bound    pvc-6ae2f4ca-ce4d-4a67-8c0b-a9673d63002f   1Gi        RWO            nfs            3m55s

NFSのPersistentVolumeが作成されている。

$ sudo kubectl get pv
pvc-092e4166-cc92-460b-b9b7-5361dffdebe5   1Gi        RWO            Retain           Bound    default/sample-pvc-sample-statefuleset-0   nfs                     4m12s
pvc-6ae2f4ca-ce4d-4a67-8c0b-a9673d63002f   1Gi        RWO            Retain           Bound    default/sample-pvc-sample-statefuleset-1   nfs                     4m7s

Podを削除してもmount領域が変わっていないか確認

Podを削除して再度Podを起動しても、同じ領域がmountされることを確認する。

Pod削除前に確認

NFSサーバーのmount領域を確認。以下のディレクトリが作成されていることを確認。

$ ls -1 /var/share/nfs
default-sample-pvc-sample-statefuleset-0-pvc-092e4166-cc92-460b-b9b7-5361dffdebe5
default-sample-pvc-sample-statefuleset-1-pvc-6ae2f4ca-ce4d-4a67-8c0b-a9673d63002f

sample-statefuleset-0用のテストファイルを作成しておく。

$ touch /var/share/nfs/default-sample-pvc-sample-statefuleset-0-pvc-092e4166-cc92-460b-b9b7-5361dffdebe5/sample001.txt

sample-statefuleset-1用のテストファイルを作成しておく。

$ touch /var/share/nfs/default-sample-pvc-sample-statefuleset-1-pvc-6ae2f4ca-ce4d-4a67-8c0b-a9673d63002f/sample002.txt

作業前にPodから参照できることを確認

sample-statefuleset-0用のテストファイルが見えることを確認。

$ sudo kubectl exec -it sample-statefuleset-0 ls /var/data
sample001.txt

sample-statefuleset-1用のテストファイルが見えることを確認。

$ sudo kubectl exec -it sample-statefuleset-1 ls /var/data
sample002.txt

Podを削除

$ sudo kubectl delete -f statefulset.yaml
statefulset.apps "sample-statefuleset" deleted

Podを再作成

$ sudo kubectl apply -f statefulset.yaml
statefulset.apps/sample-statefuleset created

作業後のNFSのmount領域を確認

NFSサーバーのmount領域を確認。Pod削除前のディレクトリが残っていることを確認。
新たにディレクトリが生成されていないことを確認。

[NFSサーバー]$ ls -1 /var/share/nfs
default-sample-pvc-sample-statefuleset-0-pvc-092e4166-cc92-460b-b9b7-5361dffdebe5
default-sample-pvc-sample-statefuleset-1-pvc-6ae2f4ca-ce4d-4a67-8c0b-a9673d63002f

sample-statefuleset-0用のテストファイルがあることを確認

[NFSサーバー]$ ls -1 /var/share/nfs/default-sample-pvc-sample-statefuleset-0-pvc-092e4166-cc92-460b-b9b7-5361dffdebe5
sample001.txt

sample-statefuleset-1用のテストファイルがあることを確認

[NFSサーバー]$ ls -1 /var/share/nfs/default-sample-pvc-sample-statefuleset-1-pvc-6ae2f4ca-ce4d-4a67-8c0b-a9673d63002f
sample002.txt

作業後もPodから参照できることを確認

sample-statefuleset-0用のテストファイルが見えることを確認。

$ sudo kubectl exec -it sample-statefuleset-0 ls /var/data
sample001.txt

sample-statefuleset-1用のテストファイルが見えることを確認。

$ sudo kubectl exec -it sample-statefuleset-1 ls /var/data
sample002.txt

Rolling Update

Rolling Updateをしてみる。

Podのイメージを更新

Podのコンテナイメージのversionを変更してapplyする。
参考:KubernetesでPodをローリングアップデートをする

statefulset.yaml
kind: StatefulSet
apiVersion: apps/v1beta1
metadata:
  name: sample-statefuleset
spec:
  # 省略
  template:
    # 省略
    spec:
      containers:
      - name: sample-container
-       image: gcr.io/google-samples/hello-app:1.0
+       image: gcr.io/google-samples/hello-app:2.0
        volumeMounts:
        - name: sample-pvc
          mountPath: /var/data
  # 省略

Rolling Update実行

$ sudo kubectl apply -f statefulset.yaml
statefulset.apps/sample-statefuleset configured

Rolling Update開始

状況を確認。
ナンバリングが大きいものからアップデートされていくことが分かる。

$ sudo kubectl get pod -w
NAME                                      READY   STATUS    RESTARTS   AGE
# 旧Pod
sample-statefuleset-0                     1/1     Running   0          73m
sample-statefuleset-1                     1/1     Running   0          73m
sample-statefuleset-2                     1/1     Running   0          61m
# 旧Pod2が破棄される。(ナンバリングが大きいものから破棄される)
sample-statefuleset-2                     1/1     Terminating   0          78m
sample-statefuleset-2                     0/1     Terminating   0          78m
sample-statefuleset-2                     0/1     Terminating   0          78m
sample-statefuleset-2                     0/1     Terminating   0          78m
sample-statefuleset-2                     0/1     Pending       0          0s
sample-statefuleset-2                     0/1     Pending       0          0s
sample-statefuleset-2                     0/1     ContainerCreating   0          0s
# 新Pod2が旧Podと同じ名前で起動した。
sample-statefuleset-2                     1/1     Running             0          4s
# 旧Pod1が破棄される。
sample-statefuleset-1                     1/1     Terminating         0          90m
sample-statefuleset-1                     0/1     Terminating         0          90m
sample-statefuleset-1                     0/1     Terminating         0          90m
sample-statefuleset-1                     0/1     Terminating         0          90m
sample-statefuleset-1                     0/1     Pending             0          0s
sample-statefuleset-1                     0/1     Pending             0          0s
sample-statefuleset-1                     0/1     ContainerCreating   0          0s
# 新Pod1が旧Podと同じ名前で起動した。
sample-statefuleset-1                     1/1     Running             0          4s
# 旧Pod0が破棄される。
sample-statefuleset-0                     1/1     Terminating         0          91m
sample-statefuleset-0                     0/1     Terminating         0          91m
sample-statefuleset-0                     0/1     Terminating         0          91m
sample-statefuleset-0                     0/1     Terminating         0          91m
sample-statefuleset-0                     0/1     Pending             0          0s
sample-statefuleset-0                     0/1     Pending             0          0s
sample-statefuleset-0                     0/1     ContainerCreating   0          0s
# 新Pod0が旧Podと同じ名前で起動した。
sample-statefuleset-0                     1/1     Running             0          5s

参考

8
5
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
8
5