Restablece a partir de una instantánea de Pod

Las instantáneas de Pods de Google Kubernetes Engine (GKE) ayudan a mejorar la latencia de inicio de la carga de trabajo, ya que restablecen instantáneas de los Pods en ejecución. Una instantánea de Pod guarda todo el estado del Pod, incluida la memoria y los cambios en el sistema de archivos raíz. Cuando se crean réplicas nuevas, en lugar de inicializar el Pod desde un estado nuevo, se restablece la instantánea. Luego, el Pod reanuda la ejecución desde el punto en el que se tomó la instantánea.

En este documento, se explica cómo habilitar y configurar las instantáneas de Pods de GKE para tus cargas de trabajo.

Para obtener más información sobre cómo funcionan las instantáneas de Pod, consulta Acerca de las instantáneas de Pod.

Antes de comenzar

Antes de comenzar, asegúrate de haber realizado las siguientes tareas:

  • Habilita la API de Google Kubernetes Engine.
  • Habilitar la API de Google Kubernetes Engine
  • Si deseas usar Google Cloud CLI para esta tarea, instala y, luego, inicializa gcloud CLI. Si ya instalaste gcloud CLI, ejecuta el comando gcloud components update para obtener la versión más reciente. Es posible que las versiones anteriores de gcloud CLI no admitan la ejecución de los comandos que se describen en este documento.

Habilita las instantáneas de Pod

Para habilitar las instantáneas de Pods, primero crea o actualiza un clúster con la función de instantáneas de Pods habilitada. Luego, crea o actualiza un grupo de nodos para que se ejecute en GKE Sandbox.

  1. Para habilitar la función en un clúster, completa uno de los siguientes pasos:

    • Para habilitar las instantáneas de Pods en un clúster nuevo, ejecuta el siguiente comando:

      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
      

      Reemplaza lo siguiente:

      • CLUSTER_NAME: El nombre de tu clúster.
      • CLUSTER_VERSION: Es la versión del clúster nuevo, que debe ser 1.34.1-gke.3084001 o posterior.
      • PROJECT_ID: el ID de tu proyecto
    • Para habilitar las instantáneas de Pods en un clúster existente, completa los siguientes pasos:

      1. Actualiza el clúster a la versión 1.34.1-gke.3084001 o posterior:

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

        Reemplaza lo siguiente:

        • CLUSTER_NAME: El nombre de tu clúster.
        • NODEPOOL_VERSION: Es el nombre de tu grupo de nodos.
        • CLUSTER_VERSION: Es la versión a la que se actualizará tu clúster nuevo, que debe ser 1.34.1-gke.3084001 o posterior.
      2. Habilita las instantáneas de Pods en tu clúster:

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

        Reemplaza PROJECT_ID con el ID del proyecto.

  2. Habilita GKE Sandbox en tu clúster estándar:

    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
    

    Reemplaza las siguientes variables:

    • NODE_POOL_NAME: es el nombre de tu grupo de nodos nuevo.
    • NODE_VERSION: Es la versión que se usará para el grupo de nodos.
    • MACHINE_TYPE: Es el tipo de máquina que se usará para los nodos.

    Para obtener más información sobre el uso de gVisor, consulta Aísla tus cargas de trabajo con GKE Sandbox.

Almacena instantáneas

Las instantáneas de Pod se almacenan en un bucket de Cloud Storage, que contiene la memoria y el estado de la GPU (opcional). Las instantáneas de Pod requieren la federación de identidades para cargas de trabajo de GKE para habilitar y usar la cuenta de servicio del Pod para autenticarse en Cloud Storage.

Las instantáneas de Pod requieren la siguiente configuración para el bucket:

  • Espacios de nombres jerárquicos: Deben estar habilitados para permitir una mayor cantidad de consultas de lectura y escritura por segundo. Los espacios de nombres jerárquicos también requieren que se habilite el acceso uniforme a nivel de bucket.
  • Eliminación no definitiva: Debido a que las instantáneas de Pod usan cargas compuestas paralelas, debes inhabilitar las funciones de protección de datos, como la eliminación no definitiva. Si se deja habilitada, la eliminación de los objetos temporales puede aumentar significativamente tu factura de almacenamiento.
  • Ubicación: La ubicación del bucket de Cloud Storage debe ser la misma que la del clúster de GKE, ya que el rendimiento podría verse afectado si las instantáneas se transfieren entre diferentes regiones.

Crea un bucket de Cloud Storage

Para crear el bucket y los permisos necesarios, completa los siguientes pasos:

  1. Crear un bucket de Cloud Storage El siguiente comando crea un bucket con la configuración requerida:

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

    Reemplaza lo siguiente:

    • BUCKET_NAME: Es el nombre de tu bucket.
    • LOCATION: Es la ubicación de tu bucket.

    Para obtener una lista completa de las opciones de creación de bucket, consulta Opciones de buckets create.

Otorga permiso a las cargas de trabajo para acceder al bucket de Cloud Storage

De forma predeterminada, GKE no tiene permisos para acceder a Cloud Storage. Para leer y escribir archivos de instantáneas, debes otorgar permisos de IAM a la cuenta de servicio de Kubernetes (KSA) que usan tus Pods de cargas de trabajo.

  1. Obtén credenciales para que puedas comunicarte con tu clúster con los comandos de kubectl:

    gcloud container clusters get-credentials "CLUSTER_NAME"
    
  2. Para cada Pod, completa los siguientes pasos:

    1. Crea una KSA para cada Pod:

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

      Reemplaza lo siguiente:

      • KSA_NAME: Es el nombre de tu KSA.
      • NAMESPACE: Es el espacio de nombres de tus Pods.
    2. Otorga permiso a la KSA para acceder al bucket:

      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"
      

      Reemplaza lo siguiente:

      • PROJECT_NUMBER: Es el número de tu proyecto.
      • PROJECT_ID: el ID de tu proyecto

(Opcional) Crea carpetas administradas para el bucket de Cloud Storage

La creación de carpetas te permite aislar los permisos para las instantáneas de los Pods que no son de confianza mutua, lo que resulta útil en casos de uso de múltiples inquilinos. Para configurar carpetas administradas, completa los siguientes pasos:

  1. Crea un rol personalizado de IAM que solo contenga los permisos necesarios para las instantáneas de Pod:

    gcloud iam roles create podSnapshotGcsReadWriter \
        --project="PROJECT_ID" \
        --permissions="storage.objects.get,storage.objects.create,storage.objects.delete,storage.folders.create"
    
  2. Otorga el rol de roles/storage.bucketViewer a todos los KSA en el espacio de nombres de destino. Este rol permite que los KSA lean los metadatos del bucket, pero no otorga permisos de lectura ni escritura para los objetos del 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"
    

    Reemplaza lo siguiente:

    • PROJECT_NUMBER: Es el número de tu proyecto.
    • PROJECT_ID: el ID de tu proyecto
  3. Para cada KSA que necesite almacenar instantáneas de Pod, completa los siguientes pasos:

    1. Crea una carpeta administrada para la KSA:

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

      Reemplaza FOLDER_PATH por la ruta de acceso a la carpeta administrada, por ejemplo, my-app-snapshots.

    2. Otorga al KSA el rol personalizado podSnapshotGcsReadWriter en la carpeta administrada:

      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"
      

      Reemplaza KSA_NAME por el nombre de la KSA.

Configura el almacenamiento para las instantáneas

Para especificar dónde almacenar los archivos de instantáneas, crea un recurso PodSnapshotStorageConfig.

  1. En el siguiente ejemplo, se configura GKE para almacenar instantáneas de Pods en la ruta de acceso FOLDER_PATH/ dentro del bucket de Cloud Storage BUCKET_NAME. Guarda el siguiente manifiesto como 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"
    

    Reemplaza lo siguiente:

    • NAMESPACE: Es el espacio de nombres de tus Pods. El valor predeterminado es default.
    • BUCKET_NAME: Es el nombre de tu bucket de Cloud Storage.
    • FOLDER_PATH: Es la ruta de acceso a la carpeta administrada de Cloud Storage.
  2. Aplica el manifiesto

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

Crea una política de instantáneas

Para habilitar las instantáneas de un Pod, crea un recurso PodSnapshotPolicy con un selector que coincida con las etiquetas del Pod.

  1. En el siguiente ejemplo, se crea una política que se aplica a los Pods con la etiqueta app: my-app y usa la configuración de almacenamiento example-pod-snapshot-storage-config. Guarda el siguiente manifiesto como 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. Aplica el manifiesto

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

Optimiza el tamaño de la instantánea

Cuando se activa una instantánea de Pod, gVisor captura todo el estado de todos los contenedores, lo que incluye lo siguiente:

  • Estado de la aplicación, como la memoria y los registros
  • Cambios en el sistema de archivos raíz y tmpfs (incluidos los volúmenes emptyDir)
  • Estado del kernel, como descriptores de archivos, subprocesos y sockets abiertos

El tamaño de la instantánea se determina en función de estos factores. Las instantáneas más grandes tardan más en guardarse y restablecerse. Para optimizar el rendimiento, antes de activar una instantánea, debes limpiar cualquier estado o archivo de la aplicación que no se requiera después de que se restablezca el Pod a partir de la instantánea.

Optimizar el tamaño de la instantánea es especialmente importante para cargas de trabajo como los modelos de lenguaje grandes (LLM). Los servidores de LLM suelen descargar los pesos del modelo en el almacenamiento local (rootfs o tmpfs) antes de cargarlos en la GPU. Cuando se toma una instantánea, se guardan tanto el estado de la GPU como los archivos de pesos del modelo. En este caso, si el modelo es de 100 GB, la instantánea resultante será de aproximadamente 200 GB (100 GB de archivos del modelo y 100 GB que representan el estado de la GPU). Después de que los pesos del modelo se cargan en la GPU, a menudo no se necesitan los archivos del sistema de archivos para que se ejecute la aplicación. Si borras estos archivos del modelo antes de activar la instantánea, puedes reducir su tamaño a la mitad y restablecer la aplicación con una latencia significativamente menor.

Cómo activar una instantánea

Puedes activar una instantánea desde una carga de trabajo cuando la aplicación esté lista o puedes activar manualmente una instantánea on demand para un Pod específico.

Cómo activar una instantánea desde una carga de trabajo

Para activar una instantánea desde el código de tu aplicación, configúrala para que envíe un indicador cuando esté lista para tomar una instantánea. Para indicar que está listo, escribe 1 en el archivo /proc/gvisor/checkpoint, por ejemplo, echo 1 > /proc/gvisor/checkpoint.. La operación de escritura inicia el proceso de instantánea de forma asíncrona y muestra los resultados de inmediato. La lectura del mismo descriptor de archivo bloqueará el proceso de lectura hasta que se completen la instantánea y el restablecimiento, y la carga de trabajo esté lista para reanudarse.

El uso exacto variará según tu aplicación, pero el siguiente ejemplo muestra un activador de instantáneas para una aplicación de Python. Para activar una instantánea desde esta carga de trabajo de ejemplo, completa los siguientes pasos:

  1. Guarda el siguiente manifiesto como 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. Implementa la aplicación:

    kubectl apply -f my-app.yaml
    

Cómo activar una instantánea de forma manual

Para activar manualmente una instantánea según demanda para un Pod específico, crea un recurso PodSnapshotManualTrigger. La activación manual de una instantánea está disponible en las versiones 1.34.1-gke.3556000 y posteriores de GKE.

  1. En el siguiente ejemplo, se activa una instantánea para un Pod llamado my-pod. Guarda el siguiente manifiesto como example-manual-trigger.yaml:

    apiVersion: podsnapshot.gke.io/v1alpha1
    kind: PodSnapshotManualTrigger
    metadata:
      name: example-manual-trigger
      namespace: NAMESPACE
    spec:
      targetPod: my-pod
    
  2. Aplica el manifiesto

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

Para confirmar si la instantánea se activó correctamente, verifica el campo status del recurso PodSnapshotManualTrigger:

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

El campo status indica si se activó la instantánea correctamente o si falló.

Verifica las instantáneas

Para confirmar que se tomó una instantánea, revisa el historial de eventos en busca de eventos 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

Reemplaza POD_NAME por el nombre del Pod, por ejemplo, my-app o my-pod.

El resultado se ve de la manera siguiente:

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

Administra instantáneas

Cuando creas una instantánea de Pod, se crea un recurso de CRD PodSnapshot para almacenar el estado del Pod en ese momento. El campo status de este recurso indica si la operación de instantánea se realizó correctamente y si la instantánea está disponible para restablecimientos.

Para ver todos los recursos de PodSnapshot en un espacio de nombres, ejecuta el siguiente comando:

kubectl get podsnapshots.gke.io --namespace NAMESPACE

El resultado se ve de la manera siguiente:

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

Restablece una carga de trabajo a partir de una instantánea

Para restablecer tu carga de trabajo a partir de la instantánea más reciente, puedes borrar el Pod existente después de tomar una instantánea y, luego, volver a implementar el Pod. Como alternativa, puedes implementar un Pod nuevo con una especificación idéntica. GKE restablece automáticamente el Pod a partir de la instantánea coincidente.

En los siguientes pasos, se muestra cómo se restablece un Pod a partir de una instantánea coincidente borrando y volviendo a implementar el Pod:

  1. Borra el Pod:

    kubectl delete -f POD_NAME.yaml
    

    Reemplaza POD_NAME por el nombre de tu Pod, por ejemplo, my-app.

  2. Vuelve a aplicar el Pod:

    kubectl apply -f POD_NAME.yaml
    
  3. Consulta los registros para confirmar el restablecimiento de la instantánea:

    kubectl logs my-app --namespace NAMESPACE
    

    El resultado depende de cómo hayas configurado tu aplicación. En la aplicación de ejemplo, los registros muestran GKE Pod Snapshot: restore cuando se produce una operación de restablecimiento.

Restablece a partir de una instantánea específica

De forma predeterminada, GKE restablece las cargas de trabajo desde el recurso PodSnapshot más reciente que coincide con el Pod. Cuando se toma una instantánea, GKE genera automáticamente un nombre único (UUID) para el recurso PodSnapshot, que puedes ver ejecutando kubectl get podsnapshots.gke.io --namespace NAMESPACE.

Para restablecer una carga de trabajo desde un recurso PodSnapshot anterior o específico, agrega la anotación podsnapshot.gke.io/ps-name a la especificación del Pod de la carga de trabajo y especifica el nombre del recurso PodSnapshot que se usará para restablecer la carga de trabajo:

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:
  ...

Reemplaza POD_SNAPSHOT_NAME por el nombre de la instantánea desde la que deseas restablecer. Puedes obtener los nombres de las instantáneas ejecutando el comando kubectl get podsnapshots.gke.io --namespace NAMESPACE.

Para que GKE use la instantánea especificada para la restauración, la condición de estado del recurso PodSnapshot debe ser Ready y existir en el mismo espacio de nombres que el Pod. Si PodSnapshot no es Ready o no existe en el mismo espacio de nombres que el Pod, la carga de trabajo realiza un inicio en frío en lugar de restablecerse desde una instantánea.

Cómo inhabilitar las instantáneas

Si quitas la CRD PodSnapshotPolicy, se impide que se creen instantáneas de los Pods y que se restablezcan. La eliminación del recurso no afecta a los Pods en ejecución. Sin embargo, si borras la política mientras se guarda o restablece un Pod, es posible que este entre en un estado de error.

Para inhabilitar la creación y el restablecimiento de instantáneas para los Pods nuevos regidos por una política, borra el PodSnapshotPolicy ejecutando el siguiente comando:

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

Reemplaza SNAPSHOT_POLICY por el nombre del PodSnapshotPolicy que deseas borrar, por ejemplo, example-pod-snapshot-policy.

También puedes borrar un recurso PodSnapshot específico para que los Pods ya no se restablezcan desde esa instantánea específica. Borrar el recurso PodSnapshot también quita los archivos almacenados en Cloud Storage.

Para evitar que se use una instantánea específica para restablecimientos futuros, borra el objeto PodSnapshot ejecutando el siguiente comando:

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

Reemplaza POD_SNAPSHOT_NAME por el nombre de la instantánea que deseas borrar, por ejemplo, example-podsnapshot.

¿Qué sigue?