從 Pod 快照還原

Google Kubernetes Engine (GKE) Pod 快照可還原執行中的 Pod 快照,藉此縮短工作負載啟動延遲時間。Pod 快照會儲存整個 Pod 狀態,包括記憶體和對根檔案系統的變更。建立新的副本時,系統會還原快照,而不是從全新狀態初始化 Pod。Pod 隨後會從擷取快照的時間點繼續執行。

本文說明如何為工作負載啟用及設定 GKE Pod 快照。

如要進一步瞭解 Pod 快照的運作方式,請參閱「關於 Pod 快照」。

事前準備

開始之前,請確認你已完成下列工作:

  • 啟用 Google Kubernetes Engine API。
  • 啟用 Google Kubernetes Engine API
  • 如要使用 Google Cloud CLI 執行這項工作,請安裝初始化 gcloud CLI。如果您先前已安裝 gcloud CLI,請執行 gcloud components update 指令,取得最新版本。較舊的 gcloud CLI 版本可能不支援執行本文件中的指令。

啟用 Pod 快照

如要啟用 Pod 快照,請先建立或更新叢集,並啟用 Pod 快照功能。接著,建立或更新節點集區,在 GKE Sandbox 中執行。

  1. 如要在叢集上啟用這項功能,請完成下列任一步驟:

    • 如要在新叢集上啟用 Pod 快照,請執行下列指令:

      gcloud beta container clusters create CLUSTER_NAME \
          --enable-pod-snapshots \
          --cluster-version=CLUSTER_VERSION \
          --workload-pool=PROJECT_ID.svc.id.goog \
          --workload-metadata=GKE_METADATA
      

      更改下列內容:

      • CLUSTER_NAME:叢集名稱。
      • CLUSTER_VERSION:新叢集的版本,必須為 1.34.1-gke.3084001 以上版本。
      • PROJECT_ID:您的專案 ID。
    • 如要在現有叢集上啟用 Pod 快照,請完成下列步驟:

      1. 將叢集更新至 1.34.1-gke.3084001 以上版本:

        gcloud container clusters upgrade CLUSTER_NAME \
            --node-pool=NODEPOOL_NAME \
            --cluster-version=CLUSTER_VERSION
        

        更改下列內容:

        • CLUSTER_NAME:叢集名稱。
        • NODEPOOL_VERSION:節點集區名稱。
        • CLUSTER_VERSION:新叢集的更新版本,必須為 1.34.1-gke.3084001 以上版本。
      2. 在叢集上啟用 Pod 快照:

        gcloud container clusters update CLUSTER_NAME \
           --workload-pool=PROJECT_ID .svc.id.goog" \
           --enable-pod-snapshots
        

        PROJECT_ID 替換為專案 ID。

  2. 在 Standard 叢集上啟用 GKE Sandbox:

    gcloud container node-pools create NODE_POOL_NAME \
      --cluster=CLUSTER_NAME \
      --node-version=NODE_VERSION \
      --machine-type=MACHINE_TYPE \
      --image-type=cos_containerd \
      --sandbox type=gvisor
    

    請替換下列變數:

    • NODE_POOL_NAME:新節點集區的名稱。
    • NODE_VERSION:節點集區使用的版本。
    • MACHINE_TYPE:節點使用的機器類型

    如要進一步瞭解如何使用 gVisor,請參閱「使用 GKE Sandbox 區隔工作負載」。

儲存快照

Pod 快照會儲存在 Cloud Storage bucket 中,其中包含記憶體和 (選用) GPU 狀態。Pod 快照需要 GKE 適用的工作負載身分聯盟,才能啟用及使用 Pod 的服務帳戶向 Cloud Storage 進行驗證。

Pod 快照需要為 bucket 設定下列項目:

  • 階層式命名空間:必須啟用,才能提高每秒讀取和寫入查詢次數。階層命名空間也需要啟用統一 bucket 層級存取權
  • 虛刪除:由於 Pod 快照使用平行複合上傳,因此您應停用虛刪除等資料保護功能。如果啟用這項功能,系統刪除暫時物件時可能會大幅增加儲存空間費用。
  • 位置:Cloud Storage 值區位置必須與 GKE 叢集位於相同位置,因為如果快照在不同區域之間轉移,效能可能會受到影響。

建立 Cloud Storage bucket

如要建立值區和必要權限,請完成下列步驟:

  1. 建立 Cloud Storage bucket。下列指令會建立具有必要設定的值區:

    gcloud storage buckets create "gs://BUCKET_NAME" \
       --uniform-bucket-level-access \
       --enable-hierarchical-namespace \
       --soft-delete-duration=0d \
       --location="LOCATION"
    

    更改下列內容:

    • BUCKET_NAME:bucket 名稱。
    • LOCATION:bucket 的位置。

    如需完整的 bucket 建立選項清單,請參閱 buckets create 選項

授予工作負載存取 Cloud Storage bucket 的權限

根據預設,GKE 沒有存取 Cloud Storage 的權限。如要讀取及寫入快照檔案,您必須將 IAM 權限授予工作負載 Pod 使用的 Kubernetes 服務帳戶 (KSA)。

  1. 取得憑證,以便使用 kubectl 指令與叢集通訊:

    gcloud container clusters get-credentials "CLUSTER_NAME"
    
  2. 針對每個 Pod,完成下列步驟:

    1. 為每個 Pod 建立 KSA:

      kubectl create serviceaccount "KSA_NAME" \
          --namespace "NAMESPACE"
      

      更改下列內容:

      • KSA_NAME:KSA 名稱。
      • NAMESPACE:Pod 的命名空間。
    2. 授予 KSA 存取值區的權限:

      gcloud storage buckets add-iam-policy-binding "gs://BUCKET_NAME" \
          --member="principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog/subject/ns/NAMESPACE/sa/KSA_NAME" \
          --role="roles/storage.bucketViewer"
      
      gcloud storage buckets add-iam-policy-binding "gs://BUCKET_NAME" \
          --member="principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog/subject/ns/NAMESPACE/sa/KSA_NAME" \
          --role="roles/storage.objectUser"
      

      更改下列內容:

      • PROJECT_NUMBER:您的專案編號。
      • PROJECT_ID:您的專案 ID。

(選用) 為 Cloud Storage bucket 建立受管理資料夾

建立資料夾可讓您隔離互不信任的 Pod 快照權限,這在多租戶用途中非常實用。如要設定代管資料夾,請完成下列步驟:

  1. 建立自訂 IAM 角色,僅包含 Pod 快照的必要權限:

    gcloud iam roles create podSnapshotGcsReadWriter \
        --project="PROJECT_ID" \
        --permissions="storage.objects.get,storage.objects.create,storage.objects.delete,storage.folders.create"
    
  2. roles/storage.bucketViewer 角色授予目標命名空間中的所有 KSA。這個角色可讓 KSA 讀取 bucket 中繼資料,但不會授予 bucket 中物件的讀取或寫入權限。

    gcloud storage buckets add-iam-policy-binding "gs://BUCKET_NAME" \
        --member="principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog/namespace/NAMESPACE" \
        --role="roles/storage.bucketViewer"
    

    更改下列內容:

    • PROJECT_NUMBER:您的專案編號。
    • PROJECT_ID:您的專案 ID。
  3. 針對每個需要儲存 Pod 快照的 KSA,完成下列步驟:

    1. 為 KSA 建立受管理的資料夾:

      gcloud storage managed-folders create "gs://BUCKET_NAME/FOLDER_PATH/"
      

      FOLDER_PATH 替換為代管資料夾的路徑,例如 my-app-snapshots

    2. 在受管理資料夾中,將自訂 podSnapshotGcsReadWriter 角色授予 KSA:

      gcloud storage managed-folders add-iam-policy-binding "gs://BUCKET_NAME/FOLDER_PATH/" \
          --member="principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog/subject/ns/NAMESPACE/sa/KSA_NAME" \
          --role="projects/PROJECT_ID/roles/podSnapshotGcsReadWriter"
      

      KSA_NAME 替換為 KSA 名稱。

設定快照儲存空間

如要指定快照檔案的儲存位置,請建立 PodSnapshotStorageConfig 資源。

  1. 以下範例會將 GKE 設定為將 Pod 快照儲存在 Cloud Storage bucket BUCKET_NAME 內的 FOLDER_PATH/ 路徑中。將下列資訊清單儲存為 example-pod-snapshot-storage-config

    apiVersion: podsnapshot.gke.io/v1alpha1
    kind: PodSnapshotStorageConfig
    metadata:
      name: example-pod-snapshot-storage-config
      namespace: NAMESPACE
    spec:
      snapshotStorageConfig:
        gcs:
          bucket: "BUCKET_NAME"
          path: "FOLDER_PATH"
    

    更改下列內容:

    • NAMESPACE:Pod 的命名空間。 預設值為 default
    • BUCKET_NAME:Cloud Storage bucket 的名稱。
    • FOLDER_PATH:Cloud Storage 受管理資料夾的路徑。
  2. 套用資訊清單:

    kubectl apply -f example-pod-snapshot-storage-config.yaml
    

建立快照政策

如要為 Pod 啟用快照,請建立 PodSnapshotPolicy 資源,並使用符合 Pod 標籤的選取器。

  1. 下列範例會建立適用於具有 app: my-app 標籤的 Pod 的政策,並使用 example-pod-snapshot-storage-config 儲存空間設定。將下列資訊清單儲存為 example-pod-snapshot-policy.yaml

    apiVersion: podsnapshot.gke.io/v1alpha1
    kind: PodSnapshotPolicy
    metadata:
      name: example-pod-snapshot-policy
      namespace: NAMESPACE
    spec:
      storageConfigName: example-pod-snapshot-storage-config
      selector:
        matchLabels:
          app: my-app
      triggerConfig:
        type: workload
        postCheckpoint: resume
    
  2. 套用資訊清單:

    kubectl apply -f example-pod-snapshot-policy.yaml --namespace NAMESPACE
    

最佳化快照大小

觸發 Pod 快照時,gVisor 會擷取所有容器的完整狀態,包括:

  • 應用程式狀態,例如記憶體和暫存器
  • 根檔案系統和 tmpfs 的變更 (包括 emptyDir 磁碟區)
  • 核心狀態,例如開啟的檔案描述元、執行緒和通訊端

快照大小取決於下列因素。快照越大,儲存和還原所需的時間就越長。為提升效能,觸發快照前,您應清除從快照還原 Pod 後不需要的任何應用程式狀態或檔案。

對於大型語言模型 (LLM) 等工作負載,最佳化快照大小尤其重要。LLM 伺服器通常會先將模型權重下載到本機儲存空間 (rootfstmpfs),再載入 GPU。擷取快照時,系統會儲存 GPU 狀態和模型權重檔案。在這種情況下,如果模型為 100 GB,產生的快照大約為 200 GB (100 GB 的模型檔案,加上代表 GPU 狀態的 100 GB)。將模型權重載入 GPU 後,應用程式通常不需要檔案系統中的檔案即可執行。在觸發快照前刪除這些模型檔案,可將快照大小縮減一半,並以大幅降低的延遲時間還原應用程式。

觸發快照

應用程式準備就緒時,您可以從工作負載內觸發快照,也可以手動觸發特定 Pod 的隨選快照。

從工作負載觸發快照

如要從應用程式程式碼中觸發快照,請將應用程式設定為在準備好建立快照時傳送信號。如要發出就緒信號,請將 1 寫入 /proc/gvisor/checkpoint 檔案,例如 echo 1 > /proc/gvisor/checkpoint.。寫入作業會以非同步方式啟動快照程序,並立即傳回。從相同檔案描述元讀取資料時,讀取程序會遭到封鎖,直到快照和還原作業完成,且工作負載準備好繼續執行為止。

實際用量會因應用程式而異,但下列範例顯示 Python 應用程式的快照觸發程序。如要從這個範例工作負載觸發快照,請完成下列步驟:

  1. 將下列資訊清單儲存為 my-app.yaml

    apiVersion: v1
    kind: Pod
    metadata:
      name: my-app
      namespace: NAMESPACE
      labels:
        app: my-app
    spec:
      serviceAccountName: KSA_NAME
      runtimeClassName: gvisor
      containers:
      - name: my-container
        image: python:3.10-slim
        command: ["python3", "-c"]
        args:
          - |
            import time
            def trigger_snapshot():
              try:
                with open("/proc/gvisor/checkpoint", "r+") as f:
                  f.write("1")
                  res = f.read().rstrip()
                  print(f"GKE Pod Snapshot: {res}")
              except FileNotFoundError:
                print("GKE Pod Snapshot file does not exist -- Pod Snapshots is disabled")
                return
              except OSError as e:
                return e
            i = 0
            while True:
              print(f"Count: {i}", flush=True)
              if (i == 20): #simulate the application being ready to snapshot at 20th count
                trigger_snapshot()
              i += 1
              time.sleep(1)
        resources:
          limits:
            cpu: "500m"
            memory: "512Mi"
          requests:
            cpu: "250m"
            memory: "256Mi"
    
  2. 部署應用程式:

    kubectl apply -f my-app.yaml
    

手動觸發快照

如要手動觸發特定 Pod 的隨選快照,請建立 PodSnapshotManualTrigger 資源。手動觸發快照功能適用於 GKE 1.34.1-gke.3556000 以上版本。

  1. 以下範例會觸發名為 my-pod 的 Pod 快照。將下列資訊清單儲存為 example-manual-trigger.yaml

    apiVersion: podsnapshot.gke.io/v1alpha1
    kind: PodSnapshotManualTrigger
    metadata:
      name: example-manual-trigger
      namespace: NAMESPACE
    spec:
      targetPod: my-pod
    
  2. 套用資訊清單:

    kubectl apply -f example-manual-trigger.yaml --namespace NAMESPACE
    

如要確認快照是否已成功觸發,請檢查 PodSnapshotManualTrigger 資源的 status 欄位:

kubectl get podsnapshotmanualtriggers.podsnapshot.gke.io example-manual-trigger -n NAMESPACE -o yaml

status 欄位會指出觸發快照是否成功。

驗證快照

如要確認是否已拍攝快照,請查看 GKEPodSnapshotting 事件的事件記錄:

kubectl get events -o \
custom-columns=NAME:involvedObject.name,CREATIONTIME:.metadata.creationTimestamp,REASON:.reason,MESSAGE:.message \
--namespace NAMESPACE \
--field-selector involvedObject.name=POD_NAME,reason=GKEPodSnapshotting

POD_NAME 換成 Pod 的名稱,例如 my-appmy-pod

輸出結果會與下列內容相似:

NAME                                    CREATIONTIME           REASON               MESSAGE
default/5b449f9c7c-bd7pc                2025-11-05T16:25:11Z   GKEPodSnapshotting   Successfully checkpointed the pod to PodSnapshot

管理快照

建立 Pod 快照時,系統會建立 PodSnapshot CRD 資源,儲存當時的 Pod 狀態。這項資源的 status 欄位會指出快照作業是否成功,以及快照是否可用於還原。

如要查看命名空間中的所有 PodSnapshot 資源,請執行下列指令:

kubectl get podsnapshots.gke.io --namespace NAMESPACE

輸出結果會與下列內容相似:

NAME                                   STATUS                  POLICY           AGE
de334898-1e7a-4cdb-9f2e-7cc2181c29e4   AllSnapshotsAvailable   example-policy   47h

從快照還原工作負載

如要從最新快照還原工作負載,您可以在建立快照後刪除現有 Pod,然後重新部署 Pod。或者,您也可以部署規格相同的新 Pod。GKE 會自動從相符的快照還原 Pod。

下列步驟說明如何刪除並重新部署 Pod,從相符的快照還原 Pod:

  1. 刪除 Pod:

    kubectl delete -f POD_NAME.yaml
    

    POD_NAME 替換為 Pod 名稱,例如 my-app

  2. 重新套用 Pod:

    kubectl apply -f POD_NAME.yaml
    
  3. 查看記錄,確認快照還原作業:

    kubectl logs my-app --namespace NAMESPACE
    

    輸出內容取決於應用程式的設定方式。在範例應用程式中,記錄檔會顯示還原作業發生的時間。GKE Pod Snapshot: restore

從特定快照還原

根據預設,GKE 會從與 Pod 相符的最新PodSnapshot 資源還原工作負載。系統擷取快照時,GKE 會自動為 PodSnapshot 資源產生專屬名稱 (UUID),您可以執行 kubectl get podsnapshots.gke.io --namespace NAMESPACE 查看。

如要從較舊或特定的 PodSnapshot 資源還原工作負載,請將 podsnapshot.gke.io/ps-name 註解新增至工作負載 Pod 規格,並指定要用於還原工作負載的 PodSnapshot 資源名稱:

apiVersion: v1
kind: Pod
metadata:
  name: my-app
  namespace: NAMESPACE
  labels:
    app: my-app
  annotations:
    podsnapshot.gke.io/ps-name: "POD_SNAPSHOT_NAME"
spec:
  serviceAccountName: KSA_NAME
  runtimeClassName: gvisor
  containers:
  ...

POD_SNAPSHOT_NAME 替換為要還原的快照名稱。您可以執行 kubectl get podsnapshots.gke.io --namespace NAMESPACE 指令來取得快照名稱。

如要讓 GKE 使用指定的快照進行還原,PodSnapshot 資源狀態條件必須為 Ready,且與 Pod 位於相同命名空間。如果 PodSnapshot 不是 Ready,或不存在於與 Pod 相同的命名空間中,工作負載會執行冷啟動,而不是從快照還原。

停用快照

移除 PodSnapshotPolicy CRD 會導致 Pod 無法建立快照和還原。資源刪除作業不會影響正在執行的 Pod。不過,如果在儲存或還原 Pod 時刪除政策,Pod 可能會進入失敗狀態。

如要針對受政策控管的新 Pod 停用快照和還原功能,請執行下列指令刪除 PodSnapshotPolicy

kubectl delete podsnapshotpolicies.podsnapshot.gke.io SNAPSHOT_POLICY --namespace=NAMESPACE

SNAPSHOT_POLICY 替換為要刪除的 PodSnapshotPolicy 名稱,例如 example-pod-snapshot-policy

您也可以刪除特定PodSnapshot資源,這樣一來,系統就不會再從該特定快照還原 Pod。刪除 PodSnapshot 資源也會移除儲存在 Cloud Storage 中的檔案。

如要避免特定快照用於日後的還原作業,請執行下列指令,刪除 PodSnapshot 物件:

kubectl delete podsnapshots.podsnapshot.gke.io POD_SNAPSHOT_NAME --namespace=NAMESPACE

POD_SNAPSHOT_NAME 替換為要刪除的快照名稱,例如 example-podsnapshot

後續步驟