Restaurer à partir d'un instantané de pod

Les instantanés de pods Google Kubernetes Engine (GKE) permettent d'améliorer la latence de démarrage des charges de travail en restaurant les instantanés des pods en cours d'exécution. Un instantané de pod enregistre l'état complet du pod, y compris la mémoire et les modifications apportées au système de fichiers racine. Lorsque de nouveaux réplicas sont créés, l'instantané est restauré au lieu d'initialiser le pod à partir d'un état vierge. Le pod reprend ensuite l'exécution à partir du point où l'instantané a été créé.

Ce document explique comment activer et configurer les snapshots de pods GKE pour vos charges de travail.

Pour en savoir plus sur le fonctionnement des instantanés de pod, consultez À propos des instantanés de pod.

Avant de commencer

Avant de commencer, effectuez les tâches suivantes :

  • Activez l'API Google Kubernetes Engine.
  • Activer l'API Google Kubernetes Engine
  • Si vous souhaitez utiliser Google Cloud CLI pour cette tâche, installez puis initialisez la gcloud CLI. Si vous avez déjà installé la gcloud CLI, obtenez la dernière version en exécutant la commande gcloud components update. Il est possible que les versions antérieures de la gcloud CLI ne permettent pas d'exécuter les commandes de ce document.

Activer les instantanés de pods

Pour activer les instantanés de pods, commencez par créer ou mettre à jour un cluster avec la fonctionnalité d'instantanés de pods activée. Créez ou mettez à jour ensuite un pool de nœuds pour qu'il s'exécute dans GKE Sandbox.

  1. Pour activer la fonctionnalité sur un cluster, procédez comme suit :

    • Pour activer les snapshots de pods sur un nouveau cluster, exécutez la commande suivante :

      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
      

      Remplacez les éléments suivants :

      • CLUSTER_NAME : nom du cluster
      • CLUSTER_VERSION : version de votre nouveau cluster, qui doit être 1.34.1-gke.3084001 ou ultérieure.
      • PROJECT_ID : ID de votre projet.
    • Pour activer les snapshots de pods sur un cluster existant, procédez comme suit :

      1. Mettez à jour le cluster vers la version 1.34.1-gke.3084001 ou ultérieure :

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

        Remplacez les éléments suivants :

        • CLUSTER_NAME : nom du cluster
        • NODEPOOL_VERSION : nom de votre pool de nœuds.
        • CLUSTER_VERSION : version à utiliser pour mettre à jour votre nouveau cluster, qui doit être 1.34.1-gke.3084001 ou ultérieure.
      2. Activez les instantanés de pod sur votre cluster :

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

        Remplacez PROJECT_ID par l'ID du projet.

  2. Activez GKE Sandbox sur votre cluster Standard :

    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
    

    Remplacez les variables suivantes :

    • NODE_POOL_NAME : nom de votre nouveau pool de nœuds.
    • NODE_VERSION : version à utiliser pour le pool de nœuds.
    • MACHINE_TYPE : type de machine à utiliser pour les nœuds.

    Pour en savoir plus sur l'utilisation de gVisor, consultez Isoler vos charges de travail à l'aide de GKE Sandbox.

Stocker des instantanés

Les instantanés de pods sont stockés dans un bucket Cloud Storage, qui contient l'état de la mémoire et (facultativement) du GPU. Les instantanés de pods nécessitent la fédération d'identité de charge de travail pour GKE afin d'activer et d'utiliser le compte de service du pod pour s'authentifier auprès de Cloud Storage.

Les instantanés de pods nécessitent la configuration suivante pour le bucket :

  • Espaces de noms hiérarchiques : ils doivent être activés pour permettre un nombre plus élevé de requêtes de lecture et d'écriture par seconde. Les espaces de noms hiérarchiques nécessitent également que l'accès uniforme au niveau du bucket soit activé.
  • Suppression réversible : étant donné que les instantanés de pod utilisent les importations composites parallèles, vous devez désactiver les fonctionnalités de protection des données telles que la suppression réversible. Si vous ne la désactivez pas, la suppression des objets temporaires peut augmenter considérablement votre facture de stockage.
  • Emplacement : l'emplacement du bucket Cloud Storage doit être le même que celui du cluster GKE, car les performances peuvent être affectées si les instantanés sont transférés entre différentes régions.

Créer un bucket Cloud Storage

Pour créer le bucket et les autorisations requises, procédez comme suit :

  1. créer un bucket Cloud Storage ; La commande suivante crée un bucket avec la configuration requise :

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

    Remplacez les éléments suivants :

    • BUCKET_NAME : nom de votre bucket.
    • LOCATION : emplacement de votre bucket.

    Pour obtenir la liste complète des options de création de buckets, consultez les options de buckets create.

Accorder aux charges de travail l'autorisation d'accéder au bucket Cloud Storage

Par défaut, GKE n'est pas autorisé à accéder à Cloud Storage. Pour lire et écrire des fichiers d'instantanés, vous devez accorder des autorisations IAM au compte de service Kubernetes (KSA) utilisé par vos pods de charge de travail.

  1. Obtenez des identifiants pour pouvoir communiquer avec votre cluster à l'aide des commandes kubectl :

    gcloud container clusters get-credentials "CLUSTER_NAME"
    
  2. Pour chaque pod, procédez comme suit :

    1. Créez un KSA pour chaque pod :

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

      Remplacez les éléments suivants :

      • KSA_NAME : nom de votre KSA.
      • NAMESPACE : espace de noms de vos pods.
    2. Accordez à la clé de compte de service l'autorisation d'accéder au 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"
      

      Remplacez les éléments suivants :

      • PROJECT_NUMBER : votre numéro de projet.
      • PROJECT_ID : ID de votre projet.

(Facultatif) Créer des dossiers gérés pour le bucket Cloud Storage

La création de dossiers vous permet d'isoler les autorisations pour les instantanés des pods qui ne se font pas mutuellement confiance, ce qui est utile dans les cas d'utilisation multitenants. Pour configurer des dossiers gérés, procédez comme suit :

  1. Créez un rôle IAM personnalisé qui ne contient que les autorisations nécessaires pour les instantanés de pod :

    gcloud iam roles create podSnapshotGcsReadWriter \
        --project="PROJECT_ID" \
        --permissions="storage.objects.get,storage.objects.create,storage.objects.delete,storage.folders.create"
    
  2. Attribuez le rôle roles/storage.bucketViewer à tous les KSA dans l'espace de noms cible. Ce rôle permet aux ARM de lire les métadonnées des buckets, mais n'accorde pas d'autorisations de lecture ou d'écriture pour les objets du 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"
    

    Remplacez les éléments suivants :

    • PROJECT_NUMBER : votre numéro de projet.
    • PROJECT_ID : ID de votre projet.
  3. Pour chaque KSA qui doit stocker des instantanés de pod, procédez comme suit :

    1. Créez un dossier géré pour le KSA :

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

      Remplacez FOLDER_PATH par le chemin d'accès au dossier géré, par exemple my-app-snapshots.

    2. Attribuez au compte de service de clé le rôle personnalisé podSnapshotGcsReadWriter sur le dossier géré :

      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"
      

      Remplacez KSA_NAME par le nom du KSA.

Configurer le stockage pour les instantanés

Pour spécifier où stocker les fichiers d'instantané, créez une ressource PodSnapshotStorageConfig.

  1. L'exemple suivant configure GKE pour stocker les instantanés de pods dans le chemin d'accès FOLDER_PATH/ à l'intérieur du bucket Cloud Storage BUCKET_NAME. Enregistrez le manifeste suivant sous le nom 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"
    

    Remplacez les éléments suivants :

    • NAMESPACE : espace de noms de vos pods. Par défaut, il s'agit de la valeur default.
    • BUCKET_NAME : nom du bucket Cloud Storage.
    • FOLDER_PATH : chemin d'accès au dossier géré Cloud Storage.
  2. Appliquez le fichier manifeste :

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

Créer une règle d'instantané

Pour activer les snapshots pour un pod, créez une ressource PodSnapshotPolicy avec un sélecteur correspondant aux libellés du pod.

  1. L'exemple suivant crée une règle qui s'applique aux pods portant le libellé app: my-app et qui utilise la configuration de stockage example-pod-snapshot-storage-config. Enregistrez le fichier manifeste suivant sous le nom 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. Appliquez le fichier manifeste :

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

Optimiser la taille des instantanés

Lorsqu'un instantané de pod est déclenché, gVisor capture l'état complet de tous les conteneurs, y compris :

  • État de l'application, comme la mémoire et les registres
  • Modifications apportées au système de fichiers racine et à tmpfs (y compris les volumes emptyDir)
  • État du noyau, tel que les descripteurs de fichiers ouverts, les threads et les sockets

La taille de l'instantané est déterminée par ces facteurs. Les instantanés plus volumineux mettent plus de temps à être enregistrés et restaurés. Pour optimiser les performances, avant de déclencher un instantané, vous devez nettoyer tout état ou fichier d'application qui ne sont pas nécessaires après la restauration du pod à partir de l'instantané.

L'optimisation de la taille des snapshots est particulièrement importante pour les charges de travail telles que les grands modèles de langage (LLM). Les serveurs LLM téléchargent souvent les pondérations du modèle dans un stockage local (rootfs ou tmpfs) avant de les charger dans le GPU. Lorsqu'un instantané est pris, l'état du GPU et les fichiers de pondération du modèle sont enregistrés. Dans ce scénario, si le modèle fait 100 Go, le snapshot obtenu fera environ 200 Go (100 Go de fichiers de modèle, plus 100 Go représentant l'état du GPU). Une fois les pondérations du modèle chargées dans le GPU, les fichiers du système de fichiers ne sont souvent plus nécessaires pour que l'application s'exécute. En supprimant ces fichiers de modèle avant de déclencher l'instantané, vous pouvez réduire de moitié la taille de l'instantané et restaurer l'application avec une latence considérablement réduite.

Déclencher un instantané

Vous pouvez déclencher un instantané à partir d'une charge de travail lorsque l'application est prête, ou vous pouvez déclencher manuellement un instantané à la demande pour un pod spécifique.

Déclencher un instantané à partir d'une charge de travail

Pour déclencher un instantané à partir du code de votre application, configurez votre application pour qu'elle envoie un signal lorsqu'elle est prête pour un instantané. Pour signaler que le service est prêt, écrivez 1 dans le fichier /proc/gvisor/checkpoint, par exemple echo 1 > /proc/gvisor/checkpoint.. L'opération d'écriture démarre le processus d'instantané de manière asynchrone et renvoie immédiatement. La lecture à partir du même descripteur de fichier bloquera le processus de lecture jusqu'à ce que l'instantané et la restauration soient terminés et que la charge de travail soit prête à reprendre.

L'utilisation exacte varie en fonction de votre application, mais l'exemple suivant montre un déclencheur d'instantané pour une application Python. Pour déclencher un instantané à partir de cet exemple de charge de travail, procédez comme suit :

  1. Enregistrez le manifeste suivant sous le nom 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. Pour déployer l'application, procédez comme suit :

    kubectl apply -f my-app.yaml
    

Déclencher manuellement un instantané

Pour déclencher manuellement un instantané à la demande pour un pod spécifique, créez une ressource PodSnapshotManualTrigger. Le déclenchement manuel d'un instantané est disponible dans les versions 1.34.1-gke.3556000 et ultérieures de GKE.

  1. L'exemple suivant déclenche un instantané pour un pod nommé my-pod. Enregistrez le manifeste suivant sous le nom example-manual-trigger.yaml :

    apiVersion: podsnapshot.gke.io/v1alpha1
    kind: PodSnapshotManualTrigger
    metadata:
      name: example-manual-trigger
      namespace: NAMESPACE
    spec:
      targetPod: my-pod
    
  2. Appliquez le fichier manifeste :

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

Pour vérifier si l'instantané a bien été déclenché, consultez le champ status de la ressource PodSnapshotManualTrigger :

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

Le champ status indique si le déclenchement du snapshot a réussi ou échoué.

Valider des instantanés

Pour vérifier qu'un instantané a été pris, consultez l'historique des événements pour les événements 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

Remplacez POD_NAME par le nom de votre pod, par exemple my-app ou my-pod.

Le résultat se présente comme suit :

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

Gérer les instantanés

Lorsque vous créez un instantané de pod, une ressource CRD PodSnapshot est créée pour stocker l'état du pod à ce moment-là. Le champ status de cette ressource indique si l'opération d'instantané a réussi et si l'instantané est disponible pour les restaurations.

Pour afficher toutes les ressources PodSnapshot d'un espace de noms, exécutez la commande suivante :

kubectl get podsnapshots.gke.io --namespace NAMESPACE

Le résultat se présente comme suit :

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

Restaurer une charge de travail à partir d'un instantané

Pour restaurer votre charge de travail à partir du dernier instantané, vous pouvez supprimer le pod existant après la création d'un instantané, puis redéployer le pod. Vous pouvez également déployer un nouveau pod avec une spécification identique. GKE restaure automatiquement le pod à partir de l'instantané correspondant.

Les étapes suivantes montrent comment un pod est restauré à partir d'un instantané correspondant en supprimant et en redéployant le pod :

  1. Supprimez le pod :

    kubectl delete -f POD_NAME.yaml
    

    Remplacez POD_NAME par le nom de votre pod, par exemple my-app.

  2. Appliquez à nouveau le pod :

    kubectl apply -f POD_NAME.yaml
    
  3. Consultez les journaux pour confirmer la restauration de l'instantané :

    kubectl logs my-app --namespace NAMESPACE
    

    Le résultat dépend de la façon dont vous avez configuré votre application. Dans l'exemple d'application, les journaux affichent GKE Pod Snapshot: restore lorsqu'une opération de restauration se produit.

Restaurer à partir d'un instantané spécifique

Par défaut, GKE restaure les charges de travail à partir de la ressource PodSnapshot la plus récente correspondant au pod. Lorsqu'un instantané est pris, GKE génère automatiquement un nom unique (UUID) pour la ressource PodSnapshot, que vous pouvez afficher en exécutant kubectl get podsnapshots.gke.io --namespace NAMESPACE.

Pour restaurer une charge de travail à partir d'une ressource PodSnapshot ancienne ou spécifique, ajoutez l'annotation podsnapshot.gke.io/ps-name à la spécification du pod de votre charge de travail, en spécifiant le nom de la ressource PodSnapshot à utiliser pour la restauration de la charge de travail :

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

Remplacez POD_SNAPSHOT_NAME par le nom de l'instantané à partir duquel vous souhaitez effectuer la restauration. Vous pouvez obtenir les noms des instantanés en exécutant la commande kubectl get podsnapshots.gke.io --namespace NAMESPACE.

Pour que GKE utilise l'instantané spécifié pour la restauration, l'état de la ressource PodSnapshot doit être Ready et exister dans le même espace de noms que le pod. Si PodSnapshot n'est pas Ready ou n'existe pas dans le même espace de noms que le pod, la charge de travail effectue un démarrage à froid au lieu d'être restaurée à partir d'un instantané.

Désactiver les instantanés

La suppression du CRD PodSnapshotPolicy empêche la création d'instantanés et la restauration des pods. Les pods en cours d'exécution ne sont pas affectés par la suppression des ressources. Toutefois, si vous supprimez la règle pendant qu'un pod est en cours d'enregistrement ou de restauration, il est possible qu'il passe à l'état "Échec".

Pour désactiver la création et la restauration de snapshots pour les nouveaux pods régis par une règle, supprimez PodSnapshotPolicy en exécutant la commande suivante :

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

Remplacez SNAPSHOT_POLICY par le nom de l'PodSnapshotPolicy que vous souhaitez supprimer, par exemple example-pod-snapshot-policy.

Vous pouvez également supprimer une ressource PodSnapshot spécifique afin que les pods ne soient plus restaurés à partir de cet instantané spécifique. La suppression de la ressource PodSnapshot supprime également les fichiers stockés dans Cloud Storage.

Pour empêcher l'utilisation d'un instantané spécifique pour les restaurations futures, supprimez l'objet PodSnapshot en exécutant la commande suivante :

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

Remplacez POD_SNAPSHOT_NAME par le nom de l'instantané que vous souhaitez supprimer, par exemple example-podsnapshot.

Étapes suivantes