从 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 快照功能。对于 Standard 集群,您还必须创建或更新节点池,以在 GKE Sandbox 中运行。Autopilot 集群默认支持 GKE Sandbox。

如需在集群上启用 Pod 快照,请根据您要使用的 GKE 运行模式完成以下步骤之一:

Autopilot

  • 如需在新集群上启用 Pod 快照,请运行以下命令:

      gcloud container clusters create-auto CLUSTER_NAME \
          --enable-pod-snapshots \
          --location=CONTROL_PLANE_LOCATION \
          --cluster-version=CLUSTER_VERSION
    

    替换以下内容:

    • CLUSTER_NAME:您的集群的名称。
    • CONTROL_PLANE_LOCATION:集群控制平面的位置
    • CLUSTER_VERSION:新集群的版本,必须为 1.35.3-gke.1234000 或更高版本。
  • 如需在现有集群上启用 Pod 快照,请完成以下步骤:

    1. 将集群升级到 1.35.3-gke.1234000 版或更高版本:

        gcloud container clusters upgrade CLUSTER_NAME \
            --cluster-version=CLUSTER_VERSION \
            --location=CONTROL_PLANE_LOCATION
      

      替换以下内容:

      • CLUSTER_NAME:您的集群的名称。
      • CONTROL_PLANE_LOCATION:集群控制平面的位置
      • CLUSTER_VERSION:新集群的版本,必须为 1.35.3-gke.1234000 或更高版本。
    2. 在集群上启用 Pod 快照:

        gcloud container clusters update CLUSTER_NAME \
            --enable-pod-snapshots \
            --location=CONTROL_PLANE_LOCATION
      

Pod 快照不支持 E2 机器类型。在 Autopilot 中,GKE 可能会默认使用 E2 节点。为确保工作负载在兼容的硬件上运行,您应使用自定义 ComputeClass 来优先考虑兼容的机器系列。

如需创建和使用自定义 ComputeClass,请完成以下步骤:

  1. 将以下清单保存为 non-e2-class.yaml

      apiVersion: cloud.google.com/v1
      kind: ComputeClass
      metadata:
        name: non-e2-class
      spec:
        priorities:
        - machineFamily: n2
        - machineFamily: c3
        activeMigration:
          optimizeRulePriority: false
        whenUnsatisfiable: DoNotScaleUp
    
  2. 应用清单:

      kubectl apply -f non-e2-class.yaml
    
  3. 在 Pod 规范中,使用 cloud.google.com/compute-class 节点选择器引用 ComputeClass:

      spec:
        nodeSelector:
          cloud.google.com/compute-class: non-e2-class
        ...
    

标准

  • 如需在新集群上启用 Pod 快照,请运行以下命令:

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

    替换以下内容:

    • CLUSTER_NAME:您的集群的名称。
    • CLUSTER_VERSION:新集群的版本,必须为 1.35.3-gke.1234000 或更高版本。
    • PROJECT_ID:您的项目 ID。
    • CONTROL_PLANE_LOCATION:集群控制平面的位置
  • 如需在现有集群上启用 Pod 快照,请完成以下步骤:

    1. 将集群升级到 1.35.3-gke.1234000 版或更高版本:

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

      替换以下内容:

      • CLUSTER_NAME:您的集群的名称。
      • NODEPOOL_VERSION:节点池的名称。
      • CLUSTER_VERSION:要将新集群更新到的版本,必须为 1.35.3-gke.1234000 或更高版本。
      • CONTROL_PLANE_LOCATION:集群控制平面的位置
    2. 在集群上启用 Pod 快照:

      gcloud beta container clusters update CLUSTER_NAME \
         --enable-pod-snapshots \
         --location=CONTROL_PLANE_LOCATION
      

      替换以下内容:

      • PROJECT_ID 替换为您的项目 ID。
      • CONTROL_PLANE_LOCATION:集群控制平面的位置

如需在 Standard 集群上以 GKE Sandbox 模式运行 Pod,请创建或更新启用了 gVisor 的节点池。如需更新节点池,请使用 --sandbox type=gvisor 标志。如需创建启用 gVisor 的节点池,请运行以下命令:

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

执行以下变量替换操作:

  • NODE_POOL_NAME:新节点池的名称。
  • NODE_VERSION:用于节点池的版本。
  • MACHINE_TYPE:用于节点的机器类型
  • CONTROL_PLANE_LOCATION:集群控制平面的位置

如需详细了解如何使用 gVisor,请参阅使用 GKE Sandbox 隔离工作负载

存储快照

Pod 快照存储在 Cloud Storage 存储桶中,其中包含内存和(可选)GPU 状态。Pod 快照需要 Workload Identity Federation for GKE 来启用并使用 Pod 的服务账号向 Cloud Storage 进行身份验证。

Pod 快照要求存储桶具有以下配置:

  • 分层命名空间:必须启用,才能实现更高的每秒读写查询次数。分层命名空间还要求启用统一存储桶级访问权限
  • 软删除:由于 Pod 快照使用并行复合上传,因此您应停用软删除等数据保护功能。如果保持启用状态,临时对象的删除操作可能会大幅增加您的存储空间费用。
  • 位置:Cloud Storage 存储桶位置必须与 GKE 集群位置相同,因为如果跨不同区域传输快照,性能可能会受到影响。

创建 Cloud Storage 存储桶

如需创建必需的存储桶和权限,请完成以下步骤:

  1. 创建 Cloud Storage 存储分区。 以下命令会创建一个具有所需配置的存储桶:

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

    替换以下内容:

    • BUCKET_NAME:存储桶的名称。
    • LOCATION:存储桶的位置。

    如需查看存储桶创建的选项的完整列表,请参阅 buckets create 选项

授予工作负载访问 Cloud Storage 存储桶的权限

默认情况下,GKE 没有访问 Cloud Storage 的权限。 如需读取和写入快照文件,您必须向工作负载 Pod 使用的 Kubernetes 服务账号 (KSA) 授予 IAM 权限。除了授予个别权限之外,您还可以改为授予短期令牌

  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。

使用短期有效的令牌启用多租户

除了向各个 KSA 授予权限之外,您还可以使用有效期短且范围受限的令牌来启用多租户。这种方法有助于避免与手动 IAM 绑定相关的传播延迟。 您无需向每个 KSA 授予权限,只需向 GKE 节点服务账号授予快照存储桶的 roles/storage.admin 角色一次即可。然后,节点服务账号会根据需要为特定路径创建短期有效的令牌。

启用含 Pod 快照的令牌需要 GKE 1.35.3-gke.1234000 版或更高版本。

如需启用多租户,请完成以下步骤:

  1. 如需向节点服务账号授予访问相应存储桶的权限,请运行以下命令:

    gcloud storage buckets add-iam-policy-binding "gs://BUCKET_NAME" \
        --member="serviceAccount:service-PROJECT_NUMBER@gcp-sa-gkenode.iam.gserviceaccount.com" \
        --role="roles/storage.admin"
    
  2. 为快照配置存储空间时,将 tokenSource 字段的值设置为 federatedP4SA

授予控制器访问 Cloud Storage 存储桶的权限

为了允许 Pod 快照控制器删除 Cloud Storage 存储桶区内的快照,需要向 GKE 服务代理授予 Storage Object User 权限。

  1. 授予 roles/storage.objectUser 角色:

    gcloud projects add-iam-policy-binding "PROJECT_ID" \
      --member="serviceAccount:service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com" \
      --role="roles/storage.objectUser" \
      --condition="expression=resource.name.startsWith(\"projects/_/buckets/BUCKET_NAME\"),title=restrict_to_bucket,description=Restricts access to one bucket only"
    

    替换以下内容:

    • PROJECT_NUMBER:您的项目编号。
    • PROJECT_ID:您的项目 ID。
    • BUCKET_NAME:存储桶的名称。

(可选)为 Cloud Storage 存储桶创建托管式文件夹

创建文件夹可让您隔离互不信任的 Pod 的快照权限,这在多租户使用情形中非常有用。如需设置受管理的文件夹,请完成以下步骤:

  1. 创建仅包含 Pod 快照所需权限的自定义 IAM 角色:

    gcloud iam roles create podSnapshotGcsReadWriter \
        --project="PROJECT_ID" \
        --permissions="storage.objects.get,storage.objects.create,storage.objects.delete,storage.folders.create"
    
  2. 向目标命名空间中的所有 KSA 授予 roles/storage.bucketViewer 角色。此角色允许 KSA 读取存储桶元数据,但不授予对存储桶中对象的读取或写入权限。

    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. 向 KSA 授予受管文件夹的自定义 podSnapshotGcsReadWriter 角色:

      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_NAME 内的 FOLDER_PATH/ 路径中。将以下清单保存为 example-pod-snapshot-storage-config

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

    替换以下内容:

    • BUCKET_NAME:Cloud Storage 存储桶的名称。
    • FOLDER_PATH:Cloud Storage 受管文件夹的路径。
    • TOKEN_SOURCE:用于访问的身份提供方。使用 podKSA(默认)或 federatedP4SA 实现多租户。
  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/v1
    kind: PodSnapshotPolicy
    metadata:
      name: example-pod-snapshot-policy
      namespace: NAMESPACE
    spec:
      storageConfigName: example-pod-snapshot-storage-config
      selector:
        matchLabels:
          app: my-app
      triggerConfig:
        type: TRIGGER_TYPE
        postCheckpoint: resume
    

    TRIGGER_TYPE 替换为触发器的类型。支持的值为 workload(对于基于工作负载的触发器)或 manual(对于按需快照)。

    如需查看您可以配置的所有字段的完整列表,请参阅 PodSnapshotPolicy 自定义资源定义 (CRD) 文档

  2. 应用清单:

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

配置其他 Pod 快照政策

您可以在 PodSnapshotPolicy 中配置其他政策,例如:

  • 自动清理:如需自动清理旧的 Pod 快照资源,请使用 spec.retentionConfig 字段配置保留政策。您可以使用 lastAccessTimeout 字段(例如 7d)指定时长,之后系统会删除快照。

  • 整理快照:您可以按逻辑方式对快照进行分组,以区分在类似环境但在不同情境下拍摄的快照。例如,在多租户场景中,所有用户的基本 Pod 可能相同,您可以按用户或群组隔离快照。如需隔离快照,请使用 snapshotGroupingRules 字段在政策中指定分组标签。

以下示例展示了如何在 PodSnapshotPolicy 中同时配置保留设置和分组设置。您可以单独设置以下设置:

# ... other fields omitted
spec:
  retentionConfig:
    lastAccessTimeout: 7d
  snapshotGroupingRules:
    groupByLabelValue:
      labels: ["tenant", "environment"]
      groupRetentionPolicy:
        maxSnapshotCountPerGroup: 5

如需查看您可以配置的所有字段的完整列表,请参阅 PodSnapshotPolicy CRD 文档

优化快照大小

当触发 Pod 快照时,gVisor 会捕获所有容器的完整状态,包括:

  • 应用状态,例如内存和寄存器
  • 对根文件系统和 tmpfs(包括 emptyDir 卷)的更改
  • 内核状态,例如打开的文件描述符、线程和套接字

快照的大小由以下因素决定。较大的快照需要更长时间才能保存和恢复。为了优化性能,在触发快照之前,您应该清理从快照恢复 Pod 后不需要的任何应用状态或文件。

优化快照大小对于大语言模型 (LLM) 等工作负载尤为重要。LLM 服务器通常会将模型权重下载到本地存储空间(rootfstmpfs),然后再将其加载到 GPU 中。拍摄快照时,系统会保存 GPU 状态和模型权重文件。在这种情况下,如果模型为 100 GB,则生成的快照约为 200 GB(100 GB 的模型文件,加上 100 GB 的 GPU 状态)。将模型权重加载到 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 资源。

  1. 以下示例会为名为 my-pod 的 Pod 触发快照。将以下清单保存为 example-manual-trigger.yaml

    apiVersion: podsnapshot.gke.io/v1
    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.podsnapshot.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

问题排查

以下部分包含相关信息,可帮助您排查 Pod 快照的常见问题。

PVC 的检查点后突变风险

如果您的 pod 使用 Persistent Volume Claim (PVC),则在“检查点和恢复”工作流期间会存在重大风险。如果您将工作负载配置为在检查点后立即恢复(使用 postCheckpoint: resume 字段),则应用会保持活跃状态,并且可以在检查点后修改 PVC。

  • 安全关停问题:在检查点和恢复周期之后,当您删除 Pod 时,Kubernetes 会通过向容器中的主进程发送 SIGTERM 信号来启动安全关停序列。许多应用在安全关停期间会实现正常关机逻辑,在此期间,它们可能会触发清理例程,删除或更新 PVC 上的临时文件。
  • 恢复失败:如果这些更改是在拍摄 Pod 快照后在 PVC 上发生的,恢复过程将预期 PVC 状态与检查点时刻的状态完全一致,从而可能导致恢复失败或数据不一致。
  • 建议的缓解措施:如果工作负载必须使用 PVC,请不要在检查点后恢复工作负载。在 PodSnapshotPolicy 中使用配置 postCheckpoint: stop。此配置有助于确保进程在检查点阶段完成后没有机会执行辅助写入或状态更改。

ConfigMap 装载和目录屏蔽

将配置数据集成到容器中时,装载方法可能会影响快照的完整性。

如果使用标准卷挂载来挂载 ConfigMap,Kubernetes 会将整个目标目录视为外部挂载。由于在创建快照期间会跳过外部装载,因此整个目录都会从快照中排除。

在以下示例中,/etc/my-app/ 目录中的任何更改都不会捕获到快照中,因为整个目录都是外部装载:

apiVersion: v1
kind: ConfigMap
metadata:
  name: my-config
data:
  config.json: |
    {
      "mode": "local"
    }
---
apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  runtimeClassName: gvisor
  containers:
    - name: my-app-container
      image: my-app-image
      volumeMounts:
        - mountPath: /etc/my-app
          name: config-volume
  volumes:
    - name: config-volume
      configMap:
        name: my-config

如需解决此问题,请使用 subPathsubPath 有助于确保仅将特定配置文件视为外部装载。此配置以确切的文件为目标,这使得父目录中的其余文件和结构保留在容器的本地文件系统中,并在检查点创建过程中得到正确捕获。

以下示例展示了使用 subPathvolumeMounts 配置:

      volumeMounts:
        - mountPath: /etc/my-app/config.json
          name: config-volume
          subPath: config.json

隐式匿名卷

某些容器映像会在其元数据中定义卷(通过 Dockerfile 中的 VOLUME 指令)。即使您的 Pod 规范未定义卷,Kubernetes 也会自动为基本映像中定义为卷的任何路径创建匿名卷。例如,alpine/git 映像将 /git 定义为隐式卷。

这些匿名卷会被视为外部装载,并且与 PVC 一样,不会进行检查点设置。我们建议您检查基本映像,确保关键数据未存储在这些隐式卷中。

后续步骤