透過 Filestore 部署有狀態的工作負載

本教學課程說明如何使用永久磁碟區 (PV)永久磁碟區要求 (PVC),在 Google Kubernetes Engine (GKE) 上部署簡單的讀取端/寫入端有狀態工作負載。請參閱本教學課程,瞭解如何使用 Google Cloud 的受管理網路檔案系統 Filestore,設計可擴充的系統。

背景

Pod 本質上是暫時性的,也就是說,GKE 會在 Pod 遭到刪除、逐出或重新排程時,清除 Pod 中儲存的狀態和值。

應用程式運算子可能需要維護有狀態的工作負載。這類工作負載的範例包括處理 WordPress 文章的應用程式、訊息應用程式,以及處理機器學習作業的應用程式。

在 GKE 上使用 Filestore 時,您可以執行下列作業:

  • 部署可擴充的有狀態工作負載。
  • 讓多個 Pod 將 ReadWriteMany 設為 accessMode,以便多個 Pod 同時讀取及寫入同一個儲存空間。
  • 設定 GKE,同時將磁碟區掛接到多個 Pod。
  • 在移除 Pod 時保留儲存空間。
  • 讓 Pods 共用資料,輕鬆擴大規模。

使用 CSI 透過 Filestore 設定代管檔案儲存空間

GKE 可在叢集中自動部署及管理 Kubernetes Filestore CSI 驅動程式。使用 Filestore CSI,您就能動態建立或刪除 Filestore 執行個體,並透過 StorageClassDeployment 在 Kubernetes 工作負載中使用這些執行個體。

您可以建立 PVC,動態佈建 Filestore 執行個體和 PV,藉此建立新的 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
  • volumeBindingMode 設為 Immediate,系統會立即開始佈建磁碟區。
  • tier 設為 standard,加快 Filestore 執行個體建立時間。 如需高可用性的 NFS 儲存空間、資料備份快照、跨多個可用區的資料複製功能,以及其他企業級功能,請改為將 tier 設為 enterprise。 注意:如果未設定 StorageClass 中的 reclaimPolicy,系統會將動態建立的 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

如果將 volumeBindingMode 設為 Immediate,系統會立即開始佈建磁碟區。

  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 的 STATUS 已設為 Bound

      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 存取磁碟區

下列 pvc.yaml 資訊清單會參照 Filestore CSI 驅動程式的 StorageClass,名稱為 filestore-sc

如要讓多個 Pod 讀取及寫入磁碟區,請將 accessMode 設為 ReadWriteMany

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。本教學課程使用 Kubernetes 部署建立 Pod。Deployment 是 Kubernetes API 物件,可讓您執行多個 Pod 副本,並將這些副本分散到叢集中的節點。

建立讀取者 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 的映像檔是 Alpine Linux 的自訂映像檔,用於公用程式和生產應用程式。其中包含一個指令碼 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
    

將讀取者工作負載公開至 Service 負載平衡器以存取

如要從叢集外部公開發布工作負載,請建立類型為 LoadBalancer 的 Service。這種類型的 Service 會建立外部負載平衡器,並指派可透過網際網路存取的 IP 位址。

  1. 建立名為 reader-lbLoadBalancer 類型服務:

    kubectl create -f loadbalancer.yaml
    
  2. 監控部署作業,確認 GKE 為 reader-lb 服務指派 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 鍵,終止監看程序。

  4. 使用網路瀏覽器前往指派給負載平衡器的 EXTERNAL-IP。網頁每 30 秒會重新整理一次。 當寫入者越多且頻率越低,網頁就會顯示更多項目。

如要進一步瞭解負載平衡器服務,請參閱 loadbalancer.yaml

擴大寫入者數量

由於 PV accessMode 已設為 ReadWriteMany,因此 GKE 可以擴充 Pod 數量,讓更多寫入者 Pod 寫入這個共用磁碟區 (或讓更多讀取者讀取)。

  1. writer 擴充至五個備用資源:

    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

此時,您已設定及擴充叢集,支援五個具狀態的寫入者 Pod。多個寫入器 Pod 同時寫入同一個檔案。讀取者 Pod 也可以輕鬆擴充。

選用:從 Writer 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