Trending keywords: security, cloud, container,

Kubernetes StatefulSetとは? 概要と作成方法

SHARE:

本番環境でのKubernetesの使用にあたっては、コンテナ化したアプリケーションをデプロイするためのオプションが多数用意されています。

その 1 つが Kubernetes StatefulSet で、アプリケーションコンテナが停止して終了するときにデータを持続させることができます。この対象には、データベースや他のデータストア、およびステートフルアプリケーションが含まれます。

この記事では、まず StatefulSet の概要を説明したうえで、作成・更新・削除方法を解説。混合されがちなDeploymentDaemonSet、および ReplicaSet StatefulSet を体系的に比較することで、それぞれが向いている場面を紹介します。Kind を使用して、このチュートリアルの目的に沿ったサンプルクラスタを作成します。

関 連 記 事

Kubernetesとは?Kubernetesセキュリティ
の基礎
Kubernetesアーキテクチャの
設計方法
AWSのEKS
(Elastic Kubernetes Service)
Kubernetesの
クラスターとは?
 
Kubernetes のノードとは?
KubernetesのPodとは?KubernetesのHelmとは?クラウドセキュリティと
ランタイムインサイト

Kubernetes StatefulSet とは

Kubernetes StatefulSet は、ステートフルアプリケーション管理に使われるワークロードAPIのことです。それぞれが一意の状態要件を含む、Pod セットを表現。専用のボリューム、一意のホスト名レコード、および特定のデプロイ順序のニーズを規定しています。

StatefulSetの主な意図は、アプリケーションが障害により再起動する場合に、ファイルシステム内にデータを保存してそれらに再接続できるアプリケーションを、開発者がデプロイできるようにすることです。MySQL、PostgreSQL、Redis などのデータベース、nginx や Apache などの HTTP サーバー、および Kafka や Zookeeper などの永続ブローカーが該当します。

StatefulSet をデプロイすると、K8s は各レプリカに独自の状態(ボリューム)を割り当て、デプロイと更新の順序を保証します。たとえば、特定の StatefulSet に 3 つのレプリカを指定した場合、StatefulSet はそれらを順番にデプロイし、それぞれに独自の PVC を割り当てます。StatefulSet を削除またはスケールすると、最初にデプロイされたときと同じ順序で削除またはスケールされ、PVC は削除されないため、データの安全性が保証されます。

StatefulSetを使う場面

StatefulSet は、特定の Pod 要件がある場面で使うことをお勧めします。前提として、ステートフルアプリケーションとステートレスアプリケーションの違いを認識しなくてはなりません。

ステートフルアプリケーションでは、状態がファイルシステム内で保持されます。主な役割は、状態がどのようにアクセスされるかを管理することです。例として、ファイルシステムを使って情報を内部に保存するデータベースシステムおよびアプリケーションが含まれます。

ステートレスアプリケーションは、将来使用できる、または再起動後に持続できるクライアントデータを保持しません。例えば、ソフトウェアエージェント、Web アプリケーション、Lambda 関数です。

どのアプリケーションがステートフルかを識別した後に、StatefulSet 内の各レプリカ用に特定のデプロイ戦略を作成することをお勧めします。

各レプリカは 0 ~ N の順に作成され、N ~ 0 の反対の順序で削除されます。これにより、たとえば、最初の Pod をプライマリに、その他をレプリカ Pod に設定可能です。

プライマリ Pod はクライアントからのリクエストの読み書きを処理し、他の Pod は最初の Pod と同期してデータを複製できます。StatefulSet をスケールアップすることで新しい Pod を導入すると、K8s は新しい PVC をその Pod 用に予約します。

StatefulSetの作成方法

このデモでは、次の StatefulSet マニフェストを使用します。

stateful-set.yml

---
apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-www
spec:
  storageClassName: standard
  accessModes:
    - ReadWriteOnce
  capacity:
    storage: 1Gi
  hostPath:
    path: /www/
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
  labels:
    app: nginx
spec:
  serviceName: "nginx"
  selector:
    matchLabels:
      app: nginx
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.21.6
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi
      storageClassName: standardCode language: JavaScript (javascript)

ここで注目したいのは以下の内容です。

  • Service spec ではヘッドレスサービスを定義します(clusterIP:  None)。K8s IP アドレスを割り当てない、トラフィックを転送しないことを意味します。代わりに、DNS サーバーはサービスの IP ではなく各 Pod の IP を返します(クライアントはこれを使用して Pod に接続できます)。
  • volumeClaimTemplates 用に PersistentVolume をプロビジョニングする必要があります。そうしない場合は、Pending 状態でブロックされます。
  • StatefulSet spec は、PVC の作成に使用するテンプレートを定義する、特別な volumeClaimTemplates フィールドを使用します。この例の各レプリカには一意の PVC が必要になります。

上記の仕様を適用した後に、状態をチェックします。

❯ kubectl describe statefulsets
Name:               web
Namespace:          default
CreationTimestamp:  Tue, 08 Mar 2022 13:12:38 +0000
Selector:           app=nginx
Labels:             app=nginx
Annotations:        <none>
Replicas:           3 desired | 3 total
Update Strategy:    RollingUpdate
  Partition:        0
Pods Status:        3 Running / 0 Waiting / 0 Succeeded / 0 Failed
…
Events:
  Type    Reason            Age   From                    Message
  ----    ------            ----  ----                    -------
  Normal  SuccessfulCreate  11m   statefulset-controller  create Pod web-0 in StatefulSet web successful
  Normal  SuccessfulCreate  11m   statefulset-controller  create Pod web-1 in StatefulSet web successful
  Normal  SuccessfulCreate  11m   statefulset-controller  create Pod web-2 in StatefulSet web successfulCode language: JavaScript (javascript)

StatefulSet を更新するためにさまざまな方法があります。最も簡単な方法は、次のコマンドを使用して、レプリカの数をスケールアップまたはスケールダウンすることです。

❯ kubectl scale statefulset web --replicas 4
statefulset.apps/web scaled
❯ kubectl get pods -l app
NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          4h1m
web-1   1/1     Running   0          4h1m
web-2   1/1     Running   0          4h1m
web-3   1/1     Running   0          6sCode language: JavaScript (javascript)

StatefulSet 0 にスケールダウンすると、操作の順序を監視できます。最後の Pod、最後から 2 つ目の Pod、とスケールされていきます。

❯ kubectl scale statefulset web --replicas 0
❯ kubectl get pods -l app -w
NAME    READY   STATUS        RESTARTS   AGE
web-0   1/1     Running       0          4h4m
web-1   1/1     Running       0          4h4m
web-2   1/1     Running       0          4h4m
web-3   0/1     Terminating   0          3m15s
web-2   1/1     Terminating   0          4h4m
web-2   0/1     Terminating   0          4h4m
web-1   1/1     Terminating   0          4h4m
web-1   0/1     Terminating   0          4h4m
web-0   1/1     Terminating   0          4h4m
web-0   0/1     Terminating   0          4h4mCode language: JavaScript (javascript)

K8s では、updateStrategy spec フィールドを使用して、更新戦略の動作をカスタマイズできます。persistentVolumeClaimRetentionPolicy spec フィールドを使用して、PVC 保持の動作をカスタマイズできます。

replicastemplate、または updateStrategy 以外のフィールドを変更することで既存の StatefulSet spec を更新しようとすると、操作が失敗します。

❯ kubectl apply -f stateful-set.yml
service/nginx unchanged
The StatefulSet "web" is invalid: spec: Forbidden: updates to statefulset spec for fields other than 'replicas', 'template', and 'updateStrategy' are forbiddenCode language: PHP (php)

StatefulSet を削除しても、そこにバインドされていた PVC はデフォルトでは削除されません。これにより、データの安定性が保証されます。

この場合、次のように個別に再クレームする必要があります。

❯ kubectl get statefulsets
NAME   READY   AGE
web    3/3     24m
❯ kubectl delete statefulsets web
statefulset.apps "web" deleted
❯ kubectl get pvc
NAME        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
www-web-0   Bound    pv-www                                     1Gi        RWO            standard       24m
www-web-1   Bound    pvc-35ceb9b1-74e6-42e3-a74b-bd8548249562   1Gi        RWO            standard       24m
www-web-2   Bound    pvc-b2b45bed-d2f2-4293-a419-8616f736b12b   1Gi        RWO            standard       24mCode language: JavaScript (javascript)

spec は再適用できます。同じ Pod が順番にされ、対応する PVC が割り当てられます。

❯ kubectl apply -f stateful-set.yml
service/nginx unchanged
persistentvolume/pv-www unchanged
statefulset.apps/web createdCode language: JavaScript (javascript)

次のコマンドを使用して、この StatefulSet が割り当てられた Pod を検査できます。

❯ kubectl get pods -l app
NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          3h55m
web-1   1/1     Running   0          3h55m
web-2   1/1     Running   0          3h55mCode language: JavaScript (javascript)

他にも、StatefulSet ではなく Deployment を使用すべき場合があります。

StatefulSet と Deployment の違い

StatefulSet を使用する主な理由は、ステートフルアプリケーションを提供することです。そうでない場合は、Deployment を使用することをお勧めします。

Deployment を開始して PVC を指定すると、その PVC はすべての Pod レプリカで共有されます(ボリュームが読み取り専用の場合)。StatefulSet では、各 Pod に独自の PVC が割り当てられる形です。

Deployment をスケールアップまたはスケールダウンしても、K8s は順序を考慮しません。すべてを一度にトリガーします。しかし、StatefulSet では順序が重要であり、K8s はスケールアップまたはスケールダウンの際に、安定性を保証するためにその順序を保持します。

StatefulSet DaemonSet 違い

DaemonSet は、K8s がクラスタ内の各ノードの Pod に割り当てる、一意の種類のリソースです。たとえば、3 つのノードがある場合、3 つの DaemonSet を、各ノードに 1 つずつ スケジュールします。StatefulSet では、NodeAffinity spec フィールドを指定しない場合は、デフォルトではこの動作になりません。Pod を処理するのに十分なリソースがある場合は、ノードごとにより多くの Pod をスケジュールできます。

ログまたはアプリのモニターおよびサイドカーなど、パラレルに使用するサービスでは、StatefulSet ではなく DaemonSet を使用することをお勧めします。これらのサービスは通常、イントロスペクションやモニタリングを容易にする長期間の非クリティカルなアプリと見なされています。

StatefulSet ReplicaSet 違い

ReplicaSet はシンプルな複製された Pod を表現し、Deployment によく似ています。StatefulSet Pod テンプレートを使用するように、ReplicaSet Pod テンプレートを使用します。

ただし、ReplicaSet では、K8s はローリングアップデートを自動的に処理しません。Pod を新しいバージョンに更新するには、別の ReplicaSet を作成して、1 つずつスケールアップする必要があります。ほとんどのユースケースでは、自動ロールアウトを提供する Deployment を使用することをお勧めします。

ReplicaSet には Deployment と多くの共通点がありますが、ステートレスアプリケーションで使用することを検討してください。

まとめ

この記事では、K8s StatefulSet の詳しいチュートリアルと実際の使用方法をご紹介しました。

コンテンツに関心を持たれた方は、Sysdig から今後公開される、K8s、クラウドセキュリティ、オープンソーステクノロジに関連するチュートリアルをブログでチェックしてください