Filestore を使用してステートフル ワークロードをデプロイする

このチュートリアルでは、Google Kubernetes Engine(GKE)上で、永続ボリューム(PV)および永続ボリューム要求(PVC)を使用して、簡単な読み取り/書き込みのステートフル・ワークロードをデプロイする方法について説明します。このチュートリアルに沿って、Google Cloud のマネージド ネットワーク ファイルシステムである Filestore を使用し、スケーラビリティの設計方法を学んでください。

背景

本来、Pod はエフェメラルです。つまり、GKE は、Pod が削除、強制排除、または再スケジュールされると、Pod に保存されている状態と値を破棄します。

アプリケーション オペレータとしてステートフル ワークロードを維持したい場合があります。このようなワークロードの例には、WordPress の記事を処理するアプリ、メッセージ アプリ、ML オペレーションを処理するアプリなどがあります。

GKE で Filestore を使用すると、次の操作を行えます。

  • スケーラブルなステートフル ワークロードをデプロイする。
  • 複数の Pod が同じストレージに対して同時に読み書きできるように、複数の Pod で ReadWriteManyaccessMode として使用できるるようにする。
  • 同時に複数の Pod へ Volume をマウントするように GKE を設定する。
  • Pod が削除されてもストレージを保持する。
  • Pod がデータを共有し、簡単にスケールできるようにする。

CSI を使用して Filestore でマネージド ファイル ストレージを構成する

GKE では、クラスタに Kubernetes Filestore CSI ドライバを自動でデプロイして管理できます。Filestore CSI を使用すると、Filestore インスタンスを動的に作成または削除でき、さらに StorageClassDeployment と一緒に Kubernetes ワークロードで使用できます。

Filestore インスタンスと PV を動的にプロビジョニングする PVC を作成することで新しい Filestore インスタンス作成することも、Kubernetes ワークロードに事前にプロビジョニングされた Filestore インスタンスにアクセスすることも可能です。

新しいインスタンス

ストレージ クラスを作成する

apiVersion: storage.k8s.io/v1 kind: StorageClass metadata:   name: filestore-sc provisioner: filestore.csi.storage.gke.io volumeBindingMode: Immediate allowVolumeExpansion: true parameters:   tier: standard   network: default
  • volumeBindingModeImmediate に設定されていると、Volume のプロビジョニングをすぐに開始できます。
  • Filestore インスタンスの作成時間を短縮するため、tierstandard に設定されています。高可用性のある NFS ストレージ、データ バックアップ用のスナップショット、複数のゾーンにわたるデータ レプリケーション、その他のエンタープライズ レベルの機能が必要な場合は、代わりに tierenterprise に設定します。注: StorageClassreclaimPolicy が設定されていない場合、動的に作成された PV の再利用ポリシーのデフォルトは Delete になります。
  1. StorageClass リソースを作成します。

    kubectl create -f filestore-storageclass.yaml 
  2. ストレージ クラスが作成されていることを確認する

    kubectl get sc 

    出力は次のようになります。

    NAME                     PROVISIONER                    RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE filestore-sc             filestore.csi.storage.gke.io   Delete          Immediate              true                   94m 

事前プロビジョニングされたインスタンス

ストレージ クラスを作成する

apiVersion: storage.k8s.io/v1 kind: StorageClass metadata:   name: filestore-sc provisioner: filestore.csi.storage.gke.io volumeBindingMode: Immediate allowVolumeExpansion: true

volumeBindingModeImmediate に設定されると、Volume のプロビジョニングをすぐに開始できます。

  1. StorageClass リソースを作成します。

      kubectl create -f preprov-storageclass.yaml 
  2. ストレージ クラスが作成されていることを確認する

      kubectl get sc 

    出力は次のようになります。

      NAME                     PROVISIONER                    RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE   filestore-sc             filestore.csi.storage.gke.io   Delete          Immediate              true                   94m 

Filestore インスタンス用の永続ボリュームを作成する

apiVersion: v1 kind: PersistentVolume metadata:   name: fileserver   annotations:     pv.kubernetes.io/provisioned-by: filestore.csi.storage.gke.io spec:   storageClassName: filestore-sc   capacity:     storage: 1Ti   accessModes:     - ReadWriteMany   persistentVolumeReclaimPolicy: Delete   volumeMode: Filesystem   csi:     driver: filestore.csi.storage.gke.io     # Modify this to use the zone, filestore instance and share name.     volumeHandle: "modeInstance/<LOCATION>/<INSTANCE_NAME>/<FILE_SHARE_NAME>"     volumeAttributes:       ip: <IP_ADDRESS> # Modify this to Pre-provisioned Filestore instance IP       volume: <FILE_SHARE_NAME> # Modify this to Pre-provisioned Filestore instance share name
  1. 既存の Filestore インスタンスの準備ができていることを確認します。

      gcloud filestore instances list 

    出力は次のようになります。ここで、STATE 値は READY です。

      INSTANCE_NAME: stateful-filestore   LOCATION: us-central1-a   TIER: ENTERPRISE   CAPACITY_GB: 1024   FILE_SHARE_NAME: statefulpath   IP_ADDRESS: 10.109.38.98   STATE: READY   CREATE_TIME: 2022-04-05T18:58:28 

    Filestore インスタンスの INSTANCE_NAMELOCATIONFILE_SHARE_NAMEIP_ADDRESS をメモします。

  2. Filestore インスタンスのコンソール変数を設定します。

      INSTANCE_NAME=INSTANCE_NAME   LOCATION=LOCATION   FILE_SHARE_NAME=FILE_SHARE_NAME   IP_ADDRESS=IP_ADDRESS 
  3. プレースホルダ変数を上記で取得したコンソール変数に置き換えて、preprov-pv.yaml ファイルにします。

      sed "s/<INSTANCE_NAME>/$INSTANCE_NAME/" preprov-pv.yaml > changed.yaml && mv changed.yaml preprov-pv.yaml   sed "s/<LOCATION>/$LOCATION/" preprov-pv.yaml > changed.yaml && mv changed.yaml preprov-pv.yaml   sed "s/<FILE_SHARE_NAME>/$FILE_SHARE_NAME/" preprov-pv.yaml > changed.yaml && mv changed.yaml preprov-pv.yaml   sed "s/<IP_ADDRESS>/$IP_ADDRESS/" preprov-pv.yaml > changed.yaml && mv changed.yaml preprov-pv.yaml 
  4. PV を作成します。

      kubectl apply -f preprov-pv.yaml 
  5. PV の STATUSBound に設定されていることを確認します。

      kubectl get pv 

    出力は次のようになります。

      NAME        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                STORAGECLASS    REASON   AGE   fileserver  1Ti        RWX            Delete           Bound    default/fileserver   filestore-sc             46m 

PersistentVolumeClaim を使用して Volume にアクセスする

次の pvc.yaml マニフェストでは、filestore-sc という名前の Filestore CSI ドライバの StorageClass を参照しています。

複数の Pod での Volume の読み取り / 書き込みを可能にするため、accessModeReadWriteMany に設定します。

kind: PersistentVolumeClaim apiVersion: v1 metadata:   name: fileserver spec:   accessModes:   - ReadWriteMany   storageClassName: filestore-sc   resources:     requests:       storage: 1Ti
  1. PVC をデプロイします。

    kubectl create -f pvc.yaml 
  2. PVC が作成されていることを確認します。

    kubectl get pvc 

    出力は次のようになります。

    NAME         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS        AGE fileserver   Bound    pvc-aadc7546-78dd-4f12-a909-7f02aaedf0c3   1Ti        RWX            filestore-sc        92m 
  3. 新しく作成された Filestore インスタンスの準備ができていることを確認します。

    gcloud filestore instances list 

    出力は次のようになります。

    INSTANCE_NAME: pvc-5bc55493-9e58-4ca5-8cd2-0739e0a7b68c LOCATION: northamerica-northeast2-a TIER: STANDARD CAPACITY_GB: 1024 FILE_SHARE_NAME: vol1 IP_ADDRESS: 10.29.174.90 STATE: READY CREATE_TIME: 2022-06-24T18:29:19 

読み取り Pod と書き込み Pod を作成する

このセクションでは、読み取り Pod と書き込み Pod を作成します。このチュートリアルでは、Kubernetes Deployment を使用して Pod を作成します。Deployment は、クラスタ内のノードに分散された Pod の複数のレプリカを実行できる Kubernetes API オブジェクトです。

読み取り Pod を作成する

読み取り Pod は、書き込み Pod が書き込んでいるファイルを読み取ります。読み取り Pod は、どの書き込み Pod レプリカが、いつファイルに書き込んだかを確認します。

apiVersion: apps/v1 kind: Deployment metadata:   name: reader spec:   replicas: 1   selector:     matchLabels:       app: reader   template:     metadata:       labels:         app: reader     spec:       containers:       - name: nginx         image: nginx:stable-alpine         ports:         - containerPort: 80         volumeMounts:         - name: fileserver           mountPath: /usr/share/nginx/html # the shared directory            readOnly: true       volumes:       - name: fileserver         persistentVolumeClaim:           claimName: fileserver

読み取り Pod は、すべての Pod 間で共有されるパス /usr/share/nginx/html から読み取ります。

  1. 読み取り Pod をデプロイします。

    kubectl apply -f reader-fs.yaml 
  2. Pod のリストをクエリして、読み取りレプリカが実行されていることを確認します。

    kubectl get pods 

    出力は次のようになります。

    NAME                      READY   STATUS    RESTARTS   AGE reader-66b8fff8fd-jb9p4   1/1     Running   0          3m30s 

書き込み Pod を作成する

書き込み Pod は、他の書き込み Pod や読み取り Pod がアクセスできる共有ファイルに定期的に書き込みます。書き込み Pod は、ホスト名を共有ファイルに書き込むことで、自身の存在を記録します。

書き込み Pod に使用されるイメージは、ユーティリティや本番環境アプリケーションに使用される Alpine Linux のカスタム イメージです。これには、最新の書き込み Pod のメタデータを取得して、すべての一意の書き込み Pod と合計書き込み数をカウントするスクリプト indexInfo.html が含まれます。

apiVersion: apps/v1 kind: Deployment metadata:   name: writer spec:   replicas: 2 # start with 2 replicas   selector:     matchLabels:       app: writer   template:     metadata:       labels:         app: writer     spec:       containers:       - name: content         image: us-docker.pkg.dev/google-samples/containers/gke/stateful-workload:latest         volumeMounts:         - name: fileserver           mountPath: /html # the shared directory         command: ["/bin/sh", "-c"]         args:         - cp /htmlTemp/indexInfo.html /html/index.html;           while true; do           echo "<b> Date :</b> <text>$(date)</text> <b> Writer :</b> <text2> ${HOSTNAME} </text2> <br>  " >> /html/indexData.html;           sleep 30;             done       volumes:       - name: fileserver         persistentVolumeClaim:           claimName: fileserver

このチュートリアルでは、書き込み Pod が 30 秒ごとにパス /html/index.html に書き込みます。sleep の数値を変更すると、書き込みの頻度が変わります。

  1. 書き込み Pod をデプロイします。

    kubectl apply -f writer-fs.yaml 
  2. Pod のリストをクエリして、書き込み Pod が実行されていることを確認します。

    kubectl get pods 

    出力は次のようになります。

    NAME                      READY   STATUS    RESTARTS   AGE reader-66b8fff8fd-jb9p4   1/1     Running   0          3m30s writer-855565fbc6-8gh2k   1/1     Running   0          2m31s writer-855565fbc6-lls4r   1/1     Running   0          2m31s 

読み取り Pod を Service Load Balancer に公開してアクセスする

ワークロードをクラスタ外部に公開するには、LoadBalancer タイプの Service を作成します。このタイプの Service は、インターネット経由で到達可能な IP アドレスを持つ外部ロードバランサを作成します。

  1. LoadBalancer タイプの Service を reader-lb という名前で作成します。

    kubectl create -f loadbalancer.yaml 
  2. Deployment を watch して、GKE が reader-lb Service に EXTERNAL-IP を割り当てていることを確認します。

    kubectl get svc --watch 

    Service の準備が整うと、EXTERNAL-IP 列にロードバランサのパブリック IP アドレスが表示されます。

      NAME         TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)        AGE   kubernetes   ClusterIP      10.8.128.1    <none>          443/TCP        2d21h   reader-lb    LoadBalancer   10.8.131.79   34.71.232.122   80:32672/TCP   2d20h 
  3. Ctrl+C キーを押して watch プロセスを終了します。

  4. ウェブブラウザで、ロードバランサに割り当てられた EXTERNAL-IP に移動します。このページは 30 秒ごとに更新されます。書き込み Pod が多く、更新間隔が短いほど、表示されるエントリは多くなります。

ロードバランサ Service の詳細を確認するには、loadbalancer.yaml をご覧ください。

書き込みをスケールアップする

PV の accessModeReadWriteMany に設定されているため、GKE は、より多くの書き込み Pod がこの共有ボリュームに書き込めるように(あるいは、より多くの読み取り Pod が読み取れるように)、Pod の数をスケールアップできます。

  1. writer を 5 つのレプリカにスケールアップします。

    kubectl scale deployment writer --replicas=5 

    出力は次のようになります。

    deployment.extensions/writer scaled 
  2. 実行中のレプリカの数を確認します。

    kubectl get pods 

    出力は次のようになります。

    NAME                      READY   STATUS    RESTARTS   AGE reader-66b8fff8fd-jb9p4   1/1     Running   0          11m writer-855565fbc6-8dfkj   1/1     Running   0          4m writer-855565fbc6-8gh2k   1/1     Running   0          10m writer-855565fbc6-gv5rs   1/1     Running   0          4m writer-855565fbc6-lls4r   1/1     Running   0          10m writer-855565fbc6-tqwxc   1/1     Running   0          4m 
  3. ウェブブラウザで、ロードバランサに割り当てられた EXTERNAL-IP に再度移動します。

この時点で、5 つのステートフル書き込み Pod をサポートするようにクラスタを構成してスケールしました。複数の書き込み Pod は、同じファイルに同時に書き込みを行います。読み取り Pod のスケールアップも簡単です。

省略可: 書き込み Pod からデータにアクセスする

このセクションでは、コマンドライン インターフェースを使用して読み取り Pod や書き込み Pod にアクセスする方法について説明します。書き込み Pod が書き込み、読み取り Pod が読み取る対象の共有コンポーネントを確認できます。

  1. 書き込み Pod 名を取得します。

    kubectl get pods 

    出力は次のようになります。

    NAME                      READY   STATUS    RESTARTS   AGE writer-5465d65b46-7hxv4   1/1     Running   0          20d 

    書き込み Pod のホスト名をメモします(例: writer-5465d65b46-7hxv4)。

  2. 次のコマンドを実行して、書き込み Pod にアクセスします。

    kubectl exec -it WRITER_HOSTNAME -- /bin/sh 
  3. indexData.html ファイルの共有コンポーネントを確認します。

    cd /html cat indexData.html 
  4. indexData.html ファイルを消去します。

    echo '' > indexData.html 

    EXTERNAL-IP アドレスをホストするウェブブラウザを更新して、変更を確認します。

  5. 環境を終了します。

    exit