Sobre snapshots de pods do GKE

Os snapshots de pods do Google Kubernetes Engine (GKE) ajudam a melhorar a latência de inicialização da carga de trabalho restaurando snapshots de pods em execução. Um snapshot de pod salva todo o estado do pod, incluindo alterações na memória e no sistema de arquivos. Quando você cria novas réplicas, elas são restauradas do snapshot, permitindo que a carga de trabalho seja retomada em vez de começar de um novo estado.

Este documento apresenta uma visão geral conceitual dos snapshots de pod do GKE. Para saber como ativar e usar esse recurso, consulte Restaurar de um snapshot de pod.

Quando usar snapshots de pod

Use snapshots de pod para cargas de trabalho com tempos de inicialização longos, por exemplo, cargas de trabalho de inferência de IA que carregam modelos grandes na memória da CPU ou da GPU ou grandes aplicativos que carregam muitas bibliotecas e dependências. Cargas de trabalho que já têm tempos de inicialização rápidos geralmente não se beneficiam dos snapshots de pod.

Como os snapshots de pod funcionam

Os snapshots de pods do GKE armazenam uma cópia exata do estado do processo de um pod em um momento específico. Quando novas réplicas são criadas, em vez de inicializar o pod de um estado novo, ele é restaurado de um snapshot, retomando a execução do ponto em que o snapshot foi tirado.

Para usar snapshots de pods, crie definições de recursos personalizados (CRDs) do Kubernetes para configurar de maneira declarativa o comportamento do snapshot. Um agente em execução em cada nó do GKE gerencia o ciclo de vida do snapshot. Com base nas políticas definidas, o agente determina quando criar novos snapshots e quando usar os snapshots atuais para restaurar novos pods. Um controlador em execução no plano de controle do GKE limpa snapshots obsoletos e resolve problemas. O Cloud Storage armazena seus snapshots de pod.

Definições de recursos personalizados

Os snapshots de pod são configurados de forma declarativa com os seguintes CRDs:

  • PodSnapshotStorageConfig: especifica o local de armazenamento dos snapshots. Apenas buckets do Cloud Storage são compatíveis.
  • PodSnapshotPolicy: define quais pods serão incluídos no snapshot com base em seletores de rótulo do Kubernetes. Esse recurso contém a maioria das opções de configuração do recurso, incluindo como os snapshots são acionados e as políticas de retenção.
  • PodSnapshotManualTrigger: (opcional) se você não estiver usando um gatilho de carga de trabalho, define um gatilho manual para criar um snapshot de um pod específico.

Acionadores de snapshot

É possível acionar um snapshot de pod das seguintes maneiras:

  • Gatilho da carga de trabalho: o aplicativo dentro do pod sinaliza ao agente do GKE que está pronto para um snapshot. Esse tipo de gatilho é executado uma vez em um ciclo de carga de trabalho, por exemplo, em um estado pronto da carga de trabalho. Essa abordagem é melhor para melhorar a latência de inicialização de cargas de trabalho com escalonamento horizontal.
  • Acionador manual: é possível acionar um snapshot sob demanda para um pod específico criando um recurso personalizado PodSnapshotManualTrigger. Esse tipo de gatilho pode ser executado quantas vezes forem necessárias. Essa abordagem é melhor para situações em que não é possível modificar o aplicativo para sinalizar a prontidão.

Correspondência de snapshots

A correspondência de pods determina se um snapshot de pod é compatível com um pod específico. Essa correspondência é alcançada criando um hash exclusivo das especificações essenciais de tempo de execução do pod, também chamadas de especificação destilada do pod. Esse hash é incorporado ao snapshot do pod. Para que um pod posterior seja restaurado desse snapshot de pod, ele precisa gerar um hash idêntico da própria especificação de pod destilada. Esse processo ajuda a garantir que os pods de checkpoint e restaurados sejam idênticos nas configurações de tempo de execução.

A destilação simplifica a especificação do pod, mantendo apenas os campos de tempo de execução críticos, como image, e removendo campos não essenciais, como nodeName ou nodeSelector. É preciso garantir que os valores desses campos essenciais sejam consistentes entre o pod usado para checkpointing e o pod destinado à restauração.

Os seguintes campos do objeto Pod influenciam o hash exclusivo:

  • metadata:
    • annotations: apenas anotações relevantes para o tempo de execução do gVisor, como as que começam com o prefixo dev.gvisor.*.
    • labels: batch.kubernetes.io/job-completion-index
  • spec:
    • volumes: name, volumeSource, hostPath, persistentVolumeClaim, configMap
    • containers:
      • name
      • image
      • command
      • args
      • workingDir
      • ports: name, containerPort, protocol
      • volumeMounts: name, readOnly, recursiveReadOnly, mountPath, subPath, mountPropagation, subPathExpr
      • volumeDevices: name
      • lifecycle: postStart, preStop
      • terminationMessagePath
      • terminationMessagePolicy
      • securityContext (e todos os subcampos)
      • stdin
      • stdinOnce
      • tty
    • initContainers: os mesmos subcampos de containers.
    • dnsPolicy
    • automountServiceAccountToken
    • hostNetwork
    • hostPID
    • hostIPC
    • shareProcessNamespace
    • securityContext
    • dnsConfig
    • runtimeClassName
    • os
    • hostUsers

Os seguintes critérios adicionais precisam corresponder para que um snapshot seja considerado compatível:

  • Hardware: o novo pod precisa ser executado em um nó com uma série e arquitetura de máquina idênticas ao pod original. A série de máquinas e a arquitetura precisam ser as mesmas. O número de CPUs e a quantidade de memória podem mudar. Os tipos de máquina E2 não são aceitos devido à arquitetura dinâmica subjacente.
  • Controle de versões: a versão do kernel do gVisor e a versão do driver da GPU precisam ser iguais.

O GKE gerencia a compatibilidade de snapshots. Se o GKE encontrar um snapshot compatível, ele vai restaurar o novo pod do snapshot. Se não houver um snapshot compatível, o pod será iniciado normalmente.

Restaurar a disposição e o carregamento em segundo plano

Quando um pod é restaurado de um snapshot, o kernel do gVisor é restaurado primeiro, o que geralmente leva alguns segundos. Para minimizar a latência de inicialização, o aplicativo é retomado imediatamente após a restauração do kernel. Ele não espera que a memória do aplicativo seja totalmente carregada. A memória do aplicativo é restaurada usando um mecanismo de streaming em segundo plano.

Se o aplicativo tentar acessar uma parte da memória que ainda não foi carregada, ocorre uma falha de página. O gVisor intercepta essa falha, pausa a linha de execução do aplicativo e busca imediatamente a página de memória necessária do armazenamento. Essa busca sob demanda tem prioridade sobre o stream em segundo plano.

Devido a esse carregamento em segundo plano, o acesso à memória pode ter uma pequena quantidade de latência nos primeiros segundos após uma restauração, se o aplicativo precisar de memória que ainda não foi transmitida. Essa latência desaparece quando o estado da memória está totalmente sincronizado.

Esse comportamento de carregamento em segundo plano também se aplica ao estado da GPU. Por exemplo, um pod de modelo de linguagem grande (LLM) pode parecer estar no estado Running e responder a verificações de rede, mesmo que a memória da GPU ainda esteja sendo preenchida. O modelo não vai responder totalmente para inferência até que o estado da GPU seja totalmente restaurado. Por isso, ao medir a velocidade de restauração, capture o momento em que o servidor de modelos foi iniciado. É possível verificar quando o servidor de modelo é iniciado usando métricas como tempo para o primeiro token (TTFT) ou testes de prontidão do pod.

Estado da GPU

Os snapshots de pods oferecem suporte à captura do estado das GPUs. Quando você aciona um snapshot para um pod que usa GPUs, a ferramenta cuda-checkpoint da NVIDIA salva o estado da GPU na memória do processo. Isso significa que todos os dados armazenados na GPU, por exemplo, pesos do modelo, são incluídos no snapshot. Em seguida, o pod é pausado e um snapshot é criado. Durante a restauração, o processo é invertido.

Como o estado da GPU é gravado na memória do processo, o uso de memória do pod aumenta durante as operações de snapshot e restauração. Considere esse requisito de memória adicional ao definir limites de memória para seus pods.

Considerações sobre pods restaurados

Do ponto de vista da API Kubernetes, um novo pod é criado. Quando o pod é iniciado, se houver um snapshot correspondente, ele será restaurado desse snapshot, incluindo a memória original e o estado do processo. No entanto, alguns aspectos do estado do pod precisam mudar para que ele funcione como uma instância nova e exclusiva.

Considere as seguintes mudanças de estado após uma restauração:

  • Interfaces de rede: o pod restaurado recebe um novo endereço IP. Todas as interfaces de rede e rotas são reconfiguradas. As conexões de rede ativas que existiam no momento do snapshot são fechadas após a restauração. Os soquetes de escuta continuam funcionando.
  • Nome do host: o pod restaurado assume uma nova identidade e recebe um novo nome do host.
  • Estado do aplicativo: o estado do aplicativo, que precisa ser exclusivo para cada pod, como IDs de experimentos ou sementes de números aleatórios, precisa ser reinicializado após uma restauração.
  • Secrets: as chaves de criptografia e os certificados criados antes da criação do instantâneo precisam ser recriados.
  • Variáveis de ambiente: é possível mudar as variáveis de ambiente entre um snapshot e uma restauração. No entanto, como as variáveis de ambiente são armazenadas na memória do aplicativo, o GKE Sandbox não consegue encontrá-las e substituí-las de maneira confiável. Se a carga de trabalho depender de novas variáveis de ambiente após uma restauração, o pod precisará atualizá-las manualmente. As novas variáveis de ambiente estão disponíveis no arquivo /proc/gvisor/spec_environ. O formato do arquivo é o mesmo de /proc/<pid>/environ.

Estado que muda após a restauração

Nem todo o estado é retido após a restauração. As seguintes partes do estado do pod mudam para que o pod possa assumir uma nova identidade:

  • Interfaces de rede: o pod restaurado recebe um novo endereço IP. Todas as interfaces e rotas são reconfiguradas. As conexões de rede ativas que existiam no momento do snapshot são fechadas após a restauração. Os soquetes de escuta, as conexões de loopback e as conexões de soquete de domínio Unix continuam funcionando.
  • Nome do host: o pod restaurado assume uma nova identidade e recebe um novo nome do host.
  • Tempo decorrido: o tempo decorrido avança para o horário atual.

Limitações e requisitos

Os snapshots de pods do GKE têm as seguintes limitações:

  • Os pods precisam ser executados no GKE Sandbox porque os snapshots de pod dependem do ambiente de execução de contêiner gVisor fornecido pelo GKE Sandbox.
  • Os snapshots de pod não são compatíveis com tipos de máquina E2.
  • Os snapshots de pod funcionam com pods de GPU única. Apenas as seguintes configurações de várias GPUs são compatíveis:
    • g2-standard-4 (1 x L4)
    • g2-standard-8 (1 x L4)
    • g2-standard-12 (1 x L4)
    • g2-standard-16 (1 x L4)
    • g2-standard-32 (1 x L4)
    • g2-standard-48 (4 x L4)
    • g2-standard-96 (8 x L4)
    • a2-highgpu-1g (1 x A100-40GB)
    • a2-ultragpu-1g (1 x A100-80GB)
    • a3-highgpu-1g (1 x H100-80GB)
  • Não é possível usar a GPU parcialmente. Se um nó tiver várias GPUs, um pod precisará usar todas elas. Por exemplo, não é possível usar snapshots de pod com quatro pods que usam uma GPU cada em uma máquina com quatro GPUs.
  • Não é possível usar o contêiner sidecar do driver FUSE CSI do Cloud Storage com snapshots de pod.

A seguir