Progetta la tua infrastruttura per Agent Substrate su GKE

Google Kubernetes Engine (GKE) ti consente di scalare i cluster GKE Agent Substrate su GKE per supportare workload di agenti AI ad alta concorrenza, riducendo al minimo i costi di computing inattivo. Combinando i pool di nodi dell'infrastruttura di sistema dedicati con ComputeClass personalizzate e buffer di capacità, puoi isolare i componenti di sistema critici, automatizzare il fallback dell'hardware tra le serie di macchine Compute Engine e mantenere attiva la capacità dei worker in standby.

Leggi questo documento per dimensionare correttamente i componenti del cluster GKE, isolare l'infrastruttura di sistema e i pool di nodi del database, configurare il provisioning automatico dei nodi per le risorse WorkerPool e pianificare la manutenzione e gli upgrade del cluster. Questo documento è rivolto agli amministratori della piattaforma che eseguono il provisioning e gestiscono Agent Substrate sull'infrastruttura GKE.

Prima di iniziare

Prima di configurare l'infrastruttura del cluster per la scalabilità, assicurati che l'ambiente soddisfi i seguenti requisiti:

  • Modalità e versione del cluster GKE: devi utilizzare un cluster GKE Standard in cui sia il control plane sia i node pool eseguono la versione 1.37 o successive. I cluster GKE Autopilot non sono supportati per Agent Substrate su GKE.
  • Installazione di Agent Substrate su GKE: devi avere un'installazione esistente di Agent Substrate su GKE o pianificare l'installazione di Agent Substrate su GKE con l'isolamento dei nodi dell'infrastruttura di sistema abilitato. Per i passaggi di installazione, consulta Installa Agent Substrate su GKE.

Dimensiona correttamente il cluster Agent Substrate

Dimensiona il cluster in base al picco di spettatori simultanei e alle frequenze di ripresa di picco anziché alle medie. I nodi worker devono contenere il numero massimo di attori in esecuzione contemporaneamente e i componenti dell'infrastruttura di sistema e i percorsi di archiviazione devono tenere il passo con la velocità massima di ripresa e sospensione degli attori.

Stima i picchi di workload

Se non disponi di misurazioni di produzione, stima il picco di spettatori simultanei e la frequenza di ripresa dal numero totale di attori registrati (total_actors), dalla frazione media di attori in esecuzione contemporaneamente (average_active_fraction), dal moltiplicatore di burst del traffico (burst_factor) e dalla durata media di attività di un attore per turno (average_seconds_active_per_resume):

peak_running_actors = total_actors × average_active_fraction × burst_factor
peak_resume_rate    = peak_running_actors / average_seconds_active_per_resume

Ad esempio, se hai un totale di 100.000 attori con una media del 10% di attori attivi (10.000 attori) e un fattore di burst pari a due, il tuo cluster deve supportare 20.000 attori in esecuzione di picco. Se ogni attore viene eseguito per una media di 100 secondi prima di essere sospeso, per sostenere questo picco sono necessari 200 ripristini al secondo e 200 sospensioni al secondo.

Agent Substrate su GKE non sospende automaticamente gli attori inattivi; la sospensione deve essere attivata dall'applicazione o dall'orchestratore.

Dimensiona il piano dati

Questa sezione illustra le best practice per il dimensionamento del piano dati, inclusi i pod worker, i nodi GKE, la larghezza di banda degli snapshot e l'agente del nodo atelet.

Calcola i pod worker e i nodi GKE

Ogni pod worker in un WorkerPool ospita più attori. Un worker può accettare un nuovo attore mentre ospita un numero di attori inferiore al limite impostato dal flag --max-actors sul container ateworker (valore predefinito 1000) e ha una capacità di CPU e memoria rimanente sufficiente per rientrare nei limiti di ActorTemplate. Per ulteriori informazioni su come i limiti dei worker interagiscono con i limiti degli attori, consulta la guida open source Dimensionamento ottimale delle risorse nell'API Agent Substrate.

Calcola il numero richiesto di pod worker con il 20% di capacità di pianificazione disponibile (il fattore 0.8):

slots_per_worker = min(max_actors, worker_memory / actor_memory, worker_cpu / actor_cpu)
total_workers    = peak_running_actors / (slots_per_worker × 0.8)

In questa formula, il valore predefinito della variabile max_actors è 1000 (configurato dal flag --max-actors). Sottrai la memoria che il worker riserva per il proprio processo dal valore worker_memory. Per le risorse WorkerPool di microVM, aggiungi l'overhead di memoria del monitor della macchina virtuale (VMM) per attore segnalato dal worker al valore actor_memory, perché il posizionamento conteggia l'overhead rispetto alla capacità del worker.

Con un pod worker per nodo, il numero di worker è uguale al numero di nodi worker GKE. Non allocare il 100% della CPU e della memoria allocabili di un nodo al pod worker; lascia capacità su ogni nodo per il DaemonSet atelet (nello spazio dei nomi ate-system) e i daemon di sistema GKE. GKE Standard supporta fino a 65.000 nodi per cluster e fino a 512 pod per nodo. Il numero massimo predefinito è 110 pod per nodo (configurabile con il flag --max-pods-per-node) e i cluster di grandi dimensioni hanno requisiti aggiuntivi.

Dimensiona la larghezza di banda degli snapshot e i dischi dei nodi

Ogni sospensione dell'attore scrive uno snapshot sul disco del nodo locale nel percorso della directory /var/lib/ate. In modalità SYNCHRONOUS, l'agente atelet carica lo snapshot su Cloud Storage prima che l'operazione di sospensione venga restituita. In modalità ASYNCHRONOUS, l'agente atelet pianifica il caricamento su Cloud Storage dopo un ritardo di circa il valore del flag --snapshot-upload-delay (valore predefinito 5m) dal momento in cui viene acquisito lo snapshot. Agent Substrate memorizza nella cache l'ultimo snapshot sul nodo per il periodo configurato nel flag --snapshot-detach-delay, che per impostazione predefinita è 30m. Un attore che riprende l'esecuzione entro questo intervallo di tempo viene pianificato sullo stesso nodo e ripristinato dal disco locale anziché scaricare lo snapshot da Cloud Storage.

Stima le dimensioni dello snapshot non compresso (snapshot_size) come il limite di memoria di ActorTemplate più i dati scritti nel file system radice scrivibile o nelle directory permanenti. La gestione di file sparse e la compressione zstd riducono le dimensioni dello snapshot compresso (compressed_snapshot_size) trasferito da e verso Cloud Storage, dove Agent Substrate archivia fino a due snapshot per attore (lo snapshot precedente e quello in corso):

  • Larghezza di banda di picco di Cloud Storage (ogni direzione): peak_resume_rate × compressed_snapshot_size
  • Throughput di scrittura su disco del nodo di picco per nodo: 2 × peak_resume_rate × snapshot_size / total_nodes (sia i download di ripresa che i checkpoint di sospensione scrivono sul disco del nodo).

Il disco di avvio hyperdisk-balanced predefinito da 100 GiB in GKE fornisce 3600 IOPS e 290 MiB/s di throughput (le prestazioni predefinite scalano con le dimensioni del disco), il che può limitare le operazioni di snapshot in caso di I/O guest elevato. Quando crei i pool di nodi worker, monta un disco dedicato nel percorso della directory /var/lib/ate/snapshots o aumenta le prestazioni del disco di avvio utilizzando i flag --boot-disk-provisioned-iops e --boot-disk-provisioned-throughput con il comando gcloud container node-pools create.

Controlla la quota di Security Token Service

Ogni trasferimento di snapshot da o verso Cloud Storage richiede un token con ambito limitato all'attore, che il componente ate-api-server richiede all'API Security Token Service (STS). Il componente ate-api-server effettua fino a una richiesta STS per attore ogni 20-40 minuti (in genere al primo ripristino in quella finestra) e riutilizza il token fino a 20 minuti prima della scadenza.

La quota STS Exchange token global requests predefinita è di 6000 richieste per progetto al minuto ed è condivisa con Workload Identity Federation for GKE:

  • Quota STS richiesta (richieste al minuto): stima fino a 60 volte la frequenza massima di ripresa per gli attori il cui ultimo trasferimento di snapshot è avvenuto più di 20 minuti fa, più la capacità per Workload Identity Federation for GKE. Se non conosci questa tariffa, utilizza la formula 60 × peak_resume_rate come riserva. Ad esempio, 200 ripristini al secondo richiedono fino a 12.000 richieste al minuto.
  • Come aumentare la quota: richiedi un aumento della quota nella pagina Quote e limiti di sistema nella console Google Cloud . I trasferimenti di snapshot funzionano senza l'API Security Token Service abilitata nel tuo progetto, ma devi abilitare l'API affinché la quota venga visualizzata nella pagina Quote e limiti di sistema. Per saperne di più, consulta Quota per l'API Exchange Token in Security Token Service nella documentazione di Workload Identity Federation for GKE.

Ottimizza l'agente del nodo atelet

Il DaemonSet atelet esegue un pod per nodo worker per ripristinare e creare checkpoint degli attori. In ogni pod atelet, il container objectstore-plugin comprime e trasferisce gli snapshot da e verso Cloud Storage.

La tabella seguente descrive le impostazioni di dimensionamento delle chiavi per i container atelet e objectstore-plugin:

Impostazione Predefinito Indicazioni sul dimensionamento
CPU e memoria dei container atelet e objectstore-plugin Richieste: 50 mCPU, 128 MiB di memoria; nessun limite Configura la QoS estendibile senza limiti di memoria omettendo i limiti di memoria su entrambi i container, perché il raggiungimento di un limite di memoria arresta l'agente del nodo e interrompe tutti i ripristini sul nodo. Aumenta le richieste di CPU e memoria in modo che corrispondano all'utilizzo di picco misurato su un nodo completo alla frequenza di ripresa di picco, in modo che i pod worker non consumino le risorse necessarie all'agente atelet.
Flag --upload-memory-budget (container objectstore-plugin) e flag --snapshot-upload-workers (container atelet) Budget di 512 MiB; 2 worker di caricamento

Per evitare che i caricamenti simultanei di snapshot vengano messi in coda su nodi multi-attore con tassi di sospensione elevati, segui questi passaggi:

  • Aumenta il valore del flag --upload-memory-budget (e imposta la richiesta di memoria del container objectstore-plugin su un valore superiore a questo budget).
  • Aumenta il valore del flag --snapshot-upload-workers.
Flag --drain-timeout e campo terminationGracePeriodSeconds 5 minuti (flag --drain-timeout); 330 secondi (campo terminationGracePeriodSeconds) Controlla per quanto tempo l'agente atelet completa i ripristini in corso e i caricamenti di snapshot quando il relativo pod si arresta durante lo svuotamento o l'upgrade di un nodo. Se aumenti il valore del flag --drain-timeout per gli snapshot di grandi dimensioni, aumenta anche il valore del campo terminationGracePeriodSeconds nel DaemonSet atelet in modo che l'agente kubelet non arresti l'agente atelet prima del completamento dei caricamenti.

Dimensionare i componenti dell'infrastruttura di sistema e il database

Per i deployment dei componenti di sistema stateless nello spazio dei nomi ate-system che scalano orizzontalmente, stima il numero di repliche richieste con il 35% di capacità disponibile (il fattore 0.65) più una replica di riserva (+ 1) per tollerare le interruzioni dei nodi:

replicas = ceil(peak_load / (capacity_per_replica × 0.65)) + 1

La scalabilità orizzontale smette di migliorare il throughput dopo che una dipendenza condivisa (ad esempio i limiti di CPU o connessione di PostgreSQL) raggiunge la capacità. Dimensiona i componenti dell'infrastruttura di sistema e il database insieme. Per saperne di più sui flag dei componenti, consulta la guida all'installazione dell'operatore open source.

La tabella seguente descrive le regole di risorse e scalabilità per ogni componente dell'infrastruttura di sistema:

Componente Regole per QoS e risorse Scalabilità e ottimizzazione della connessione
Router in entrata (atenet-router) Configura la QoS garantita: imposta richieste e limiti di CPU e memoria corrispondenti in modo che il runtime Go allinei il numero di thread al budget della CPU del container. Scala le repliche in orizzontale in base alle richieste in entrata di picco al secondo, all'overhead mTLS e alle dimensioni del payload delle richieste.
Server API (ate-api-server) Configura la QoS garantita: imposta richieste e limiti di CPU e memoria corrispondenti in modo che il runtime Go allinei il numero di thread al budget della CPU del container. Scala le repliche in base ai cicli di ripresa e sospensione di picco al secondo (circa 4 ms di CPU per ciclo di ripresa e sospensione) e al carico di ricerca delle richieste in entrata. Imposta esplicitamente l'impostazione ateapi.postgres.poolMaxConns. Ogni replica apre fino a poolMaxConns + 6 connessioni al database e la somma di tutte le repliche deve essere inferiore all'impostazione max_connections di PostgreSQL.
Database (PostgreSQL) Configura la QoS estendibile con memoria garantita: imposta le richieste di memoria in modo che corrispondano ai limiti per bloccare la cache shared_buffers in memoria ed evitare l'espulsione per esaurimento della memoria (OOM). Ometti i limiti della CPU quando l'esecuzione avviene su un nodo ate-postgres dedicato, in modo che la limitazione della CPU del kernel non rallenti i burst di checkpoint e autovacuum. Scala verticalmente questo StatefulSet a istanza singola. Esegui il provisioning di una CPU sufficiente per mantenere l'utilizzo al di sotto dell'80% al picco di carico, di una RAM sufficiente per memorizzare nella cache la tabella Actor (con il parametro shared_buffers impostato su circa il 25% della memoria) e di una StorageClass supportata da SSD impostata al momento dell'installazione con l'impostazione ateapi.postgres.storageClass (ad esempio, la StorageClass dynamic-rwo su C4 o N4 o la StorageClass premium-rwo su C3 o N2). Aumenta il parametro max_connections nel ConfigMap postgres-config (il file postgresql.conf) per adattarlo a tutte le repliche ate-api-server.
Proxy in uscita (atenet-egress) Regole delle risorse: imposta una richiesta di CPU di 512 mCPU (limite di 8 vCPU) e una richiesta di memoria di 512 MiB (limite di 1 GiB). Aumenta le richieste e i limiti se il traffico in uscita dell'attore presenta una latenza maggiore. Scala le repliche orizzontalmente in base al traffico delle richieste in uscita dell'attore.
Controller worker (ate-controller) Regole delle risorse: mantieni una replica (nessuna elezione del leader). Imposta le richieste di CPU e memoria in base all'utilizzo di picco durante eventi di scale out di WorkerPool di grandi dimensioni. Se i nuovi pod worker impiegano troppo tempo per registrarsi in grandi parchi risorse, aumenta il valore del flag --worker-sync-concurrency (valore predefinito 2).
Controller dei certificati (podcertificate-controller) Regole delle risorse: viene eseguito nello spazio dei nomi podcertificate-controller-system per firmare i certificati mTLS per i nuovi pod worker prima che possano accettare gli attori. Per parchi risorse di migliaia di worker, aumenta i valori dell'impostazione podcert.workersPerSigner (valore predefinito 0, che mantiene il valore predefinito del manifest di 1 worker per firmatario), il flag --kube-api-qps (valore predefinito 5) e il flag --kube-api-burst (valore predefinito 10).
Provider di identità (ate-idp-server) Regole delle risorse: fornisce il documento di rilevamento OpenID Connect (OIDC) e il set di chiavi web JSON (JWKS) nello spazio dei nomi ate-system per la verifica dei token web JSON (JWT) dell'attore. Imposta le richieste di CPU e memoria in base al volume di query JWKS di picco. Scala le repliche in orizzontale se le relying party eseguono query sull'endpoint JWKS con tassi di richieste elevati senza memorizzare le chiavi cache.
Provider di credenziali (k8s-credential-provider) Regole delle risorse: vengono eseguite nello spazio dei nomi ate-system quando è abilitata l'inserimento delle credenziali dei secret di Kubernetes. Imposta le richieste di CPU e memoria in base al volume di inserimento delle credenziali in uscita. Scala le repliche in orizzontale in base alla frequenza delle richieste Actor in uscita che richiedono l'inserimento delle credenziali dei secret di Kubernetes nel proxy atenet-egress.

Isola l'infrastruttura di sistema e i pool di nodi worker

Nei cluster di produzione, la pianificazione degli attori con un elevato tasso di abbandono e il traffico degli snapshot sui nodi worker possono competere con i componenti dell'infrastruttura di sistema per CPU, memoria e I/O del disco. Separa il cluster GKE in tre livelli di pool di nodi distinti:

  • Pool di nodi del database (etichetta ate-postgres): un pool di nodi dedicato per lo StatefulSet PostgreSQL, che archivia tutti i metadati di Actor e Worker.
  • Pool di nodi dell'infrastruttura di sistema (etichetta ate-system-infra): un pool di nodi dedicato per i restanti servizi dell'infrastruttura di sistema (i componenti atenet-router, ate-api-server, atenet-egress, ate-controller, ate-idp-server e k8s-credential-provider).
  • Pool di nodi worker (WorkerPool): pool di nodi scalati dinamicamente gestiti da ComputeClass personalizzate di GKE e buffer di capacità di GKE per ospitare sandbox Actor attive.

Puoi isolare i componenti dell'infrastruttura del database e del sistema su nodi dedicati quando installi Agent Substrate su GKE utilizzando l'impostazione cordonSystemInfraComponents (o il flag --cordon-system-infra-components). Prima dell'installazione, devi creare entrambi i node pool con le etichette richieste e le incompatibilità NoSchedule:

# 1. Create the dedicated PostgreSQL node pool
gcloud container node-pools create ate-postgres-pool \
    --cluster=CLUSTER_NAME \
    --location=LOCATION \
    --node-locations=POSTGRES_ZONE \
    --machine-type=POSTGRES_MACHINE_TYPE \
    --num-nodes=1 \
    --node-labels=ate.dev/workloadType=ate-postgres \
    --node-taints=ate.dev/workloadType=ate-postgres:NoSchedule

# 2. Create the dedicated system infrastructure node pool
gcloud container node-pools create ate-system-infra-pool \
    --cluster=CLUSTER_NAME \
    --location=LOCATION \
    --machine-type=SYSTEM_INFRA_MACHINE_TYPE \
    --num-nodes=2 \
    --node-labels=ate.dev/workloadType=ate-system-infra \
    --node-taints=ate.dev/workloadType=ate-system-infra:NoSchedule

Sostituisci quanto segue:

  • CLUSTER_NAME: il nome del tuo cluster GKE Standard.
  • LOCATION: la zona o la regione di Compute Engine del control plane del cluster.
  • POSTGRES_ZONE: una singola zona di Compute Engine per lo StatefulSet PostgreSQL con una singola replica. Per un cluster a livello di regione, specifica una zona all'interno della regione del cluster in modo che il pool di nodi esegua il provisioning di un singolo nodo nella zona in cui verrà creato il disco permanente dello StatefulSet. Per un cluster di zona, specifica la zona del cluster.
  • POSTGRES_MACHINE_TYPE: il tipo di macchina Compute Engine dimensionato per l'istanza PostgreSQL.
  • SYSTEM_INFRA_MACHINE_TYPE: il tipo di macchina Compute Engine dimensionato per i componenti dell'infrastruttura di sistema (ad esempio, il tipo di macchina c3-standard-8).

In un cluster a livello di regione, il flag --num-nodes si applica per zona (ad esempio, l'impostazione del flag --num-nodes=2 in tre zone crea sei nodi in totale). Per posizionare il pool di nodi ate-system-infra-pool in zone specifiche, aggiungi il flag --node-locations.

Se attivi l'impostazione cordonSystemInfraComponents durante l'installazione e manca uno dei pool di nodi, i pod di sistema corrispondenti rimangono nello stato Pending.

Automatizza il targeting dell'hardware utilizzando ComputeClass personalizzate

Le ComputeClass personalizzate di GKE ti consentono di definire elenchi con priorità delle serie di macchine Compute Engine per i nodi WorkerPool e di eseguire automaticamente il fallback alle serie di macchine secondarie se una zona non dispone di risorse.

Seleziona la serie di macchine Compute Engine in base al runtime

Configura un ComputeClass separato per ogni runtime della sandbox:

  • Runtime MicroVM (Cloud Hypervisor): imposta il campo enableNestedVirtualization: true nelle priorità di ComputeClass e scegli come target le serie di macchine Compute Engine x86 che supportano la virtualizzazione nidificata (come N4, C3, C4 o N2) oppure utilizza i tipi di macchine bare metal x86, che eseguono KVM in modo nativo e non richiedono il campo enableNestedVirtualization. Le VM basate su Arm e le serie di macchine elencate in Limitazioni della virtualizzazione nidificata non sono supportate.
  • Runtime gVisor: scegli come target le serie di macchine Compute Engine x86 per uso generico o ottimizzate per il calcolo (come N4, C3, C4 o N2) senza virtualizzazione nidificata abilitata. Le serie di macchine eseguite su microarchitetture CPU miste (come E2) e le VM basate su Arm non sono supportate per Agent Substrate su GKE. Tutte le risorse WorkerPool selezionate da un ActorTemplate devono condividere la stessa architettura della CPU.

Per un confronto dettagliato, consulta Seleziona un runtime di sandbox.

Regole ComputeClass obbligatorie per Agent Substrate

Quando crei una classe ComputeClass per Agent Substrate sui nodi worker GKE, segui queste regole:

  • Utilizza ComputeClasses basate su nodi: non utilizzare la fatturazione basata su pod (il campo podFamily), che non supporta la virtualizzazione nidificata.
  • Non impostare il campo nodePoolConfig.sandbox.type: microvm: questa impostazione attiva il runtime Kata per GKE Sandbox sui workload basati su pod e applica un taint sandbox.gke.io/runtime=microvm che impedisce la pianificazione di Agent Substrate sui worker GKE. Agent Substrate su GKE gestisce il proprio runtime microVM e richiede solo la virtualizzazione nidificata di Compute Engine sui nodi Container-Optimized OS standard (tipo di immagine cos_containerd).
  • Configura le impostazioni del kernel Linux sysctl per un'elevata densità di sandbox: se un nodo worker esegue più di circa 800 sandbox contemporaneamente, devi aumentare i limiti del kernel Linux per il monitoraggio del file system (parametri fs.inotify.*) e per la tabella adiacente del protocollo di risoluzione degli indirizzi (ARP) (parametri net.ipv4.neigh.default.gc_thresh*). Il programma di installazione applica queste impostazioni solo ai cluster che crea. Quando configuri ComputeClasses personalizzate (utilizzando il campo priorityDefaults.nodeSystemConfig.linuxNodeConfig.sysctls) o crei in anticipo i node pool dei worker (utilizzando il flag --system-config-from-file), applica autonomamente i seguenti valori sysctl:

    • fs.inotify.max_user_instances: 65536
    • fs.inotify.max_user_watches: 1048576
    • net.ipv4.neigh.default.gc_thresh1: 4096
    • net.ipv4.neigh.default.gc_thresh2: 16384
    • net.ipv4.neigh.default.gc_thresh3: 32768

    Per ulteriori informazioni sulla configurazione dei parametri sysctl dei nodi, consulta Opzioni di configurazione di Sysctl.

Scegli un pattern di scale up per le risorse WorkerPool di microVM

I pod worker MicroVM richiedono la risorsa estesa ate.dev/kvm: 1, che viene pubblicizzata dal plug-in del dispositivo atelet solo dopo l'avvio di un nodo e dell'agente atelet. Poiché il provisioning automatico dei nodi GKE non vede la risorsa estesa ate.dev/kvm sui template dei nodi di cui non è stato eseguito il provisioning, un pod worker microVM in attesa non può attivare GKE per creare automaticamente un nuovo pool di nodi da zero repliche. Tuttavia, se un pool di nodi ha già almeno un nodo in esecuzione, GKE può fare lo scale up di quel pool di nodi.

La tabella seguente confronta i pattern supportati per la scalabilità delle risorse WorkerPool di microVM su GKE:

Pattern Come funziona Scalabilità fino a 0 nodi? Fallback con più priorità per l'indisponibilità delle risorse? Ideale se
Pool creati automaticamente con il campo minimumCapacity Imposta i campi nodePoolAutoCreation.enabled: true e minimumCapacity.targetNodeCount: 1 con priorità machineType esplicite. No (mantiene in esecuzione un nodo caldo) Solo al provisioning iniziale per il campo minimumCapacity a livello di classe; il fallback mid-burst richiede l'impostazione del campo minimumCapacity.targetNodeCount: 1 su ogni voce di fallback nel campo spec.priorities[] (mantenendo 1 nodo caldo per priorità) Vuoi la creazione automatica dei pool di nodi e mantenere sempre in esecuzione almeno un nodo worker.
Pool creati automaticamente con buffer di capacità Combina il campo nodePoolAutoCreation.enabled: true con un CapacityBuffer attivo o in standby il cui PodTemplate omette la risorsa estesa ate.dev/kvm. Sospensione in standby (ad esempio, circa l'8% del costo di calcolo in esecuzione su un nodo c3-standard-4 con un disco di avvio predefinito da 100 GiB) Sì (i segnaposto del buffer attivano il fallback del provisioning automatico dei nodi tra le priorità) Vuoi una scalabilità con burst rapida (da 1 a 4 secondi di attività o da 20 a 35 secondi per riprendere i nodi in standby e da 50 a 85 secondi prima che i nuovi worker siano pronti) con un costo di inattività ridotto.
Pool di 0 nodi precreati con etichette dei template di nodo Crea in anticipo pool di nodi con scalabilità automatica con l'etichetta clusterautoscaler-nodetemplate-resources.ate.dev/kvm=4096 e li fa riferimento nel campo spec.priorities[].nodepools di ComputeClass. Sì (0 nodi reali, nessun costo di computing inattivo) Sì, tra i node pool pre-creati Vuoi un'autentica scalabilità fino a zero senza mantenere buffer di capacità in standby.

Esempio: ComputeClass con il campo minimumCapacity

Quando utilizzi il campo minimumCapacity, ogni voce nel campo spec.priorities deve specificare un campo machineType esplicito anziché specificare solo il campo machineFamily:

apiVersion: cloud.google.com/v1
kind: ComputeClass
metadata:
  name: substrate-microvm
spec:
  priorityDefaults:
    enableNestedVirtualization: true
    nodeSystemConfig:
      linuxNodeConfig:
        sysctls:
          fs.inotify.max_user_instances: 65536
          fs.inotify.max_user_watches: 1048576
          net.ipv4.neigh.default.gc_thresh1: 4096
          net.ipv4.neigh.default.gc_thresh2: 16384
          net.ipv4.neigh.default.gc_thresh3: 32768
  priorities:
  - machineType: n4-standard-4
  - machineType: c3-standard-4
  - machineType: n2-standard-4
  nodePoolAutoCreation:
    enabled: true
  minimumCapacity:
    targetNodeCount: 1
  nodePoolConfig:
    imageType: cos_containerd
  whenUnsatisfiable: DoNotScaleUp

Per scegliere come target di un WorkerPool questa ComputeClass, aggiungi il campo nodeSelector: {cloud.google.com/compute-class: substrate-microvm} al modello di pod WorkerPool.

Quando una ComputeClass esegue il fallback tra diverse serie di macchine x86 (ad esempio da N4 a C3 o N2), il ripristino di uno snapshot durevole con fedeltà della memoria (la modalità SNAPSHOT_FIDELITY_MEMORY) richiede un worker le cui funzionalità della CPU siano un superset delle funzionalità della CPU dello snapshot. Se nessun worker compatibile ha capacità, Agent Substrate esegue il downgrade del ripristino alla fedeltà del file system radice (la modalità SNAPSHOT_FIDELITY_ROOTFS), che conserva i dati del file system radice e del volume durevole durante il riavvio dei processi dell'attore.

Esempio: scala da zero con pool di 0 nodi precreati

  1. Salva le impostazioni del kernel Linux ad alta densità sysctl come file system-config.yaml:

    linuxConfig:
      sysctl:
        fs.inotify.max_user_instances: '65536'
        fs.inotify.max_user_watches: '1048576'
        net.ipv4.neigh.default.gc_thresh1: '4096'
        net.ipv4.neigh.default.gc_thresh2: '16384'
        net.ipv4.neigh.default.gc_thresh3: '32768'
    
  2. Crea in anticipo i node pool di virtualizzazione nidificata principali e di riserva con 0 nodi con il flag --system-config-from-file=system-config.yaml e l'etichetta clusterautoscaler-nodetemplate-resources.ate.dev/kvm=4096 in modo che il gestore della scalabilità automatica dei cluster GKE sappia che il pool vuoto fornisce la risorsa estesa ate.dev/kvm:

    # Primary N4 pool (0 nodes)
    gcloud container node-pools create microvm-n4-pool \
        --cluster=CLUSTER_NAME \
        --location=LOCATION \
        --machine-type=n4-standard-4 \
        --enable-nested-virtualization \
        --system-config-from-file=system-config.yaml \
        --num-nodes=0 \
        --enable-autoscaling --total-min-nodes=0 --total-max-nodes=10 \
        --node-labels=cloud.google.com/compute-class=substrate-microvm-zero,clusterautoscaler-nodetemplate-resources.ate.dev/kvm=4096 \
        --node-taints=cloud.google.com/compute-class=substrate-microvm-zero:NoSchedule
    
    # Fallback C3 pool (0 nodes)
    gcloud container node-pools create microvm-c3-pool \
        --cluster=CLUSTER_NAME \
        --location=LOCATION \
        --machine-type=c3-standard-4 \
        --enable-nested-virtualization \
        --system-config-from-file=system-config.yaml \
        --num-nodes=0 \
        --enable-autoscaling --total-min-nodes=0 --total-max-nodes=10 \
        --node-labels=cloud.google.com/compute-class=substrate-microvm-zero,clusterautoscaler-nodetemplate-resources.ate.dev/kvm=4096 \
        --node-taints=cloud.google.com/compute-class=substrate-microvm-zero:NoSchedule
    

    Sostituisci quanto segue:

    • CLUSTER_NAME: il nome del tuo cluster GKE Standard.
    • LOCATION: la zona o la regione di Compute Engine del tuo cluster. L'utilizzo dei flag --total-min-nodes e --total-max-nodes imposta i limiti di scalabilità automatica sull'intero pool di nodi anziché per zona.
  3. Fai riferimento ai pool precreati in ordine di priorità nella tua ComputeClass:

    apiVersion: cloud.google.com/v1
    kind: ComputeClass
    metadata:
      name: substrate-microvm-zero
    spec:
      nodePoolAutoCreation:
        enabled: false
      priorities:
      - nodepools:
        - microvm-n4-pool
      - nodepools:
        - microvm-c3-pool
      whenUnsatisfiable: DoNotScaleUp
    

    Il campo priorityDefaults non si applica alle priorità che utilizzano il campo nodepools, perché le impostazioni dei nodi provengono dai node pool precreati. Come per le priorità di fallback create automaticamente, la ripresa di un attore su una serie di macchine di fallback le cui funzionalità della CPU non sono un superset delle funzionalità della CPU dello snapshot esegue il downgrade del ripristino alla modalità SNAPSHOT_FIDELITY_ROOTFS e riavvia i processi dell'attore.

Per ulteriori informazioni sulla configurazione di ComputeClass, consulta Controlla gli attributi dei nodi con scalabilità automatica con ComputeClass personalizzate.

Configura i buffer di capacità per la scalabilità con burst di WorkerPool

Quando un picco di traffico degli attori supera la capacità dei pod WorkerPool in esecuzione, i nuovi pod worker devono attendere il provisioning dei nodi di Compute Engine, l'inizializzazione dell'agente atelet e il pre-riscaldamento degli asset della sandbox prima di poter gestire gli attori. I buffer di capacità di GKE spostano il provisioning dei nodi e il preriscaldamento degli asset atelet dal percorso critico:

  • Buffer di capacità attivi (strategia buffer.x-k8s.io/active-capacity): mantengono i nodi pre-provisioning in esecuzione e pronti in modo che i nuovi pod worker vengano pianificati in uno-quattro secondi, al costo di esecuzione completo della VM Compute Engine.
  • Buffer di capacità in standby (strategia buffer.gke.io/standby-capacity): esegui il provisioning dei nodi e consenti all'agente atelet di inizializzare e preriscaldare gli asset della sandbox (il binario runsc o le immagini Cloud Hypervisor e Kata) sul disco durante la finestra di inizializzazione in standby prima che GKE sospenda le VM di Compute Engine. Questa finestra ha un valore predefinito di cinque minuti (5m) ed è configurata dall'annotazione buffer.gke.io/standby-capacity-init-time su CapacityBuffer. Aumenta il valore di questa annotazione se il preriscaldamento degli asset richiede più di cinque minuti. Quando si verifica un burst, GKE riprende i nodi sospesi in circa 20-35 secondi e l'idoneità end-to-end del WorkerPool (pianificazione dei pod worker, emissione dei certificati dei pod e registrazione della capacità con il componente ate-api-server) viene completata in circa 50-85 secondi. Durante la sospensione, paghi solo per la memoria della VM sospesa e lo spazio di archiviazione del disco di avvio. Ad esempio, il costo dello spazio di archiviazione sospeso è pari a circa l'8% del costo di computing in esecuzione su un nodo c3-standard-4 con un disco di avvio hyperdisk-balanced predefinito da 100 GiB; la percentuale esatta varia in base alla forma della macchina, alle dimensioni del disco di avvio e alle IOPS o al throughput di cui è stato eseguito il provisioning.

Per saperne di più sulle strategie di buffer, consulta Strategie per ridurre la latenza di avvio.

Limitazioni e regole per i buffer di capacità

Quando configuri i buffer di capacità per Agent Substrate su GKE, applica le seguenti regole:

  • Limitazioni delle forme di macchina di Compute Engine per i buffer di standby: la sospensione delle istanze di Compute Engine non è supportata sulle VM con SSD locali collegati o sulle forme di macchina con più di 208 GB di memoria (come il tipo di macchina c3-highmem-88 o le forme bare metal). Per forme di nodi worker di grandi dimensioni o nodi con SSD locali, utilizza i buffer di capacità attivi anziché i buffer di standby.
  • Evita di indirizzare il campo scalableRef a un WorkerPool con 0 repliche o a un deployment di microVM:
    • Il controller GKE CapacityBuffer non può risolvere una risorsa personalizzata (kind: WorkerPool) quando il pool viene scalato a 0 repliche.
    • Per le risorse WorkerPool di microVM, inoltre, non indirizzare il campo scalableRef al deployment sottostante, perché il template del pod di deployment include la risorsa estesa ate.dev/kvm: 1 (che impedisce al provisioning automatico dei nodi di fare lo scale out di un pool vuoto). Configura invece i buffer facendo riferimento a un PodTemplate (nel campo podTemplateRef) che seleziona ComputeClass senza richiedere la risorsa estesa ate.dev/kvm.
    • Per le risorse WorkerPool gVisor (che non richiedono la risorsa estesa ate.dev/kvm), puoi indirizzare il campo scalableRef direttamente al deployment sottostante di WorkerPool o utilizzare un PodTemplate.

Esempio: CapacityBuffer in standby utilizzando un PodTemplate

Il seguente manifest definisce un PodTemplate e un CapacityBuffer in standby che funzionano per le risorse microVM o gVisor WorkerPool:

apiVersion: v1
kind: PodTemplate
metadata:
  name: substrate-worker-buffer-template
  namespace: WORKERPOOL_NAMESPACE
template:
  spec:
    nodeSelector:
      cloud.google.com/compute-class: COMPUTE_CLASS_NAME
    containers:
    - name: buffer-placeholder
      image: registry.k8s.io/pause:3.9
      resources:
        requests:
          cpu: "WORKER_CPU_REQUEST"
          memory: "WORKER_MEMORY_REQUEST"
---
apiVersion: autoscaling.x-k8s.io/v1beta1
kind: CapacityBuffer
metadata:
  name: substrate-standby-buffer
  namespace: WORKERPOOL_NAMESPACE
spec:
  podTemplateRef:
    name: substrate-worker-buffer-template
  replicas: BUFFER_REPLICAS
  provisioningStrategy: buffer.gke.io/standby-capacity

Sostituisci quanto segue:

  • WORKERPOOL_NAMESPACE: lo spazio dei nomi Kubernetes del tuo WorkerPool (ad esempio my-workerpool).
  • COMPUTE_CLASS_NAME: il nome della ComputeClass personalizzata scelta come target dal tuo WorkerPool (ad esempio, substrate-microvm).
  • WORKER_CPU_REQUEST e WORKER_MEMORY_REQUEST: le richieste di CPU e memoria di un singolo pod worker nel tuo WorkerPool (ad esempio, 2 CPU e 4Gi di memoria su un nodo con 4 vCPU), lasciando la capacità del nodo per l'agente atelet e i daemon di sistema GKE. La corrispondenza di questi valori con le richieste di un pod worker consente di garantire che ogni replica del buffer esegua il provisioning di un nodo worker in standby anziché raggruppare più segnaposto del buffer in un singolo nodo.
  • BUFFER_REPLICAS: il numero di nodi worker di standby da mantenere preriscaldati (ad esempio, 4 nodi).

Quando utilizzi i buffer di capacità in standby, aggiungi una tolleranza per l'incompatibilità buffer.gke.io/standby-capacity-node-suspended (con il campo operator: "Exists") al DaemonSet atelet in modo che i pod atelet sostitutivi possano rimanere pianificati sui nodi in standby sospesi (ad esempio, durante un aggiornamento in sequenza di DaemonSet). Per un esempio di configurazione di DaemonSet, consulta Precarica le immagini sui buffer di standby.

Se più workload condividono la stessa ComputeClass, aggiungi tolleranze di separazione dei workload e etichette nodeSelector corrispondenti sia al template del pod WorkerPool sia al PodTemplate del buffer, in modo che GKE esegua il provisioning di nodi con taint dedicati che non vengono richiesti da altri workload. Aggiungi anche una tolleranza corrispondente al DaemonSet atelet in modo che l'agente atelet possa pianificare su questi nodi dedicati. Per istruzioni passo passo, consulta Configura i buffer di capacità.

Gestisci gli upgrade e le interazioni del gestore della scalabilità automatica

Questa sezione descrive come gestire gli aggiornamenti del DaemonSet atelet, gli eventi di scale down del gestore della scalabilità automatica dei cluster e gli upgrade dei nodi senza interrompere gli Actor attivi.

Aggiorna il DaemonSet atelet con i buffer di standby

I nodi buffer di standby sospesi presentano il taint buffer.gke.io/standby-capacity-node-suspended e un taint non raggiungibile mentre sono sospesi, pertanto l'agente kubelet su un nodo sospeso non può confermare le eliminazioni dei pod. Assicurati che il DaemonSet atelet tolleri il taint buffer.gke.io/standby-capacity-node-suspended (con il campo operator: "Exists"). Anche con questa tolleranza, durante un aggiornamento in sequenza standard del DaemonSet atelet (con il campo maxUnavailable: 1), i pod sui nodi sospesi entrano nello stato Terminating e possono bloccare l'avanzamento dell'aggiornamento sui nodi in esecuzione.

Prima di aggiornare il DaemonSet atelet su un cluster con nodi in standby sospesi, esegui una delle seguenti operazioni:

  • Per evitare che i nodi in standby non raggiungibili esauriscano il budget di aggiornamento, imposta il campo spec.updateStrategy.rollingUpdate.maxUnavailable nel DaemonSet atelet su un valore maggiore del numero massimo di nodi in standby sospesi.
  • Prima di aggiornare il DaemonSet atelet, scala temporaneamente le repliche CapacityBuffer di standby a 0 e attendi che il gestore della scalabilità automatica dei cluster rimuova tutti i nodi del buffer di standby sospesi (in genere da 10 a 15 minuti). Per verificare se alcuni nodi segnalano ancora uno stato della condizione Suspended pari a True, esegui questo comando:

    kubectl get nodes -o custom-columns='NAME:.metadata.name,SUSPENDED:.status.conditions[?(@.type=="Suspended")].status'
    

Proteggi gli attori attivi durante lo scale down e gli upgrade

Poiché gli Actor attivi vengono eseguiti all'interno di sandbox gestite dall'agente atelet anziché come singoli pod Kubernetes, le richieste di CPU e memoria di un nodo potrebbero sembrare basse al gestore della scalabilità automatica dei cluster GKE, anche se un pod Worker su quel nodo ospita Actor attivi. Quando un nodo viene svuotato, l'agente kubelet invia un segnale SIGTERM al pod Worker e il Worker inoltra il segnale SIGTERM al processo principale di ogni container di ogni Actor che ospita. Ogni Actor attivo ha quindi fino a 30 minuti per essere sospeso prima che il Worker si arresti. Assegna a ogni Actor stateful un gestore SIGTERM che non esca dal segnale e che chiami il metodo SuspendActor con la modalità DURABILITY_MODE_SYNCHRONOUS. Un attore il cui processo principale termina con l'indicatore SIGTERM perde immediatamente lo stato non salvato. Se il pod worker si arresta mentre ospita ancora un attore attivo, l'attore entra nello stato ACTOR_STATE_CRASHED.

Per ridurre al minimo le interruzioni durante gli eventi di scale down e gli upgrade dei cluster GKE, applica le seguenti pratiche:

  • Evita di utilizzare VM spot per i nodi WorkerPool stateful, perché il prerilascio delle VM spot fornisce solo un preavviso di terminazione compreso tra 15 secondi e 2 minuti prima dell'arresto del nodo.
  • Coordina lo svuotamento nell'orchestratore in modo che gli attori attivi vengano sottoposti a checkpoint e sospesi prima che i pod worker si arrestino o impedisci al gestore della scalabilità automatica dei cluster di espellere i pod worker attivi (ad esempio, utilizzando l'annotazione del pod cluster-autoscaler.kubernetes.io/safe-to-evict: "false"). Se imposti l'annotazione safe-to-evict: "false" in modo statico nel template del pod WorkerPool, il gestore della scalabilità automatica dei cluster non farà fare lo scale down di un nodo mentre è pianificato un pod worker, anche se questo worker ospita zero attori attivi. Per rilasciare i nodi inattivi, devi fare lo scale down delle repliche di WorkerPool o gestire l'annotazione in modo dinamico. Per saperne di più sul ciclo di vita dell'espulsione dei worker e sul recupero degli attori che hanno subito un arresto anomalo con il metodo RevertActor, consulta Espulsione nella guida all'API Agent Substrate.
  • Configura gli upgrade di sovraccarico di GKE e consulta Esegui l'upgrade in un ambiente con risorse limitate in modo che venga eseguito il provisioning dei nuovi nodi worker prima che i nodi worker esistenti vengano isolati e svuotati.

Passaggi successivi