La liaison tardive de stockage dynamique vous permet d'injecter des volumes d'agent Filestore directement dans des pods d'Agent Sandbox Google Kubernetes Engine (GKE) préchauffés et en cours d'exécution, dès qu'ils sont revendiqués. En contournant le cycle de vie standard de l'association de volumes Kubernetes, la liaison tardive dynamique permet d'obtenir une latence d'association de stockage inférieure à 100 ms sans nécessiter de redémarrage des pods.
Cette architecture permet aux plates-formes d'agents à haute densité et à faible latence d'effectuer les tâches suivantes :
- Éliminez les délais de démarrage à froid des pods et d'initialisation des conteneurs.
- Associez et dissociez de manière dynamique des espaces de travail persistants à la demande.
- Mettez en pause ou en veille prolongée les sessions d'agent inactives, et reprenez-les sur n'importe quel pod de bac à sable préchauffé disponible tout en préservant l'état du système de fichiers.
Avant de commencer
- Effectuez la configuration initiale dans Configurer l'environnement GKE pour les volumes d'agent Filestore.
- Vérifiez que votre cluster GKE exécute la version
1.36.0-gke.3302001ou une version ultérieure. - Vérifiez que votre
volume-pool-scStorageClassspécifievolumeBindingMode: ImmediateetreclaimPolicy: Delete.
Présentation de l'architecture
L'architecture de liaison tardive se compose de quatre composants :
- Outil d'orchestration de plate-forme ou contrôleur personnalisé : service de plan de contrôle ou contrôleur Kubernetes qui gère les cycles de vie des sessions. Il surveille les événements
SandboxClaim, résout les métadonnées de volume du locataire, appelle l'API du daemon du nœud de stockage pour lier ou dissocier le stockage, et gère les finaliseurs de suppression. - Daemon de nœud de stockage : un
DaemonSetprivilégié s'exécutant sur chaque nœud gVisor qui expose une API d'installation pour lier les exportations NFS Filestore aux répertoires de pods hôtes. SandboxTemplateavecforce-shared: modèle de pod de bac à sable gVisor qui permet aux installations de l'hôte de se propager de manière dynamique dans le conteneur de bac à sable gVisor.SandboxWarmPool: pool de pods de bac à sable préprovisionnés en cours d'exécution, prêts à recevoir des requêtes d'installation instantanément après la revendication.
Fonctionnement de la liaison tardive dynamique
Au lieu d'associer un PersistentVolumeClaim (PVC) au moment de la création du pod, la liaison tardive dynamique utilise le cycle de vie suivant :
- Préchauffer les bacs à sable : un
SandboxWarmPoolgère les pods gVisor en cours d'exécution configurés avec un volumeemptyDir, une propagation d'installationHostToContaineret l'annotationdev.gvisor.empty-dir.VOLUME_NAME.force-shared: "true", où<var>VOLUME_NAME</var>est le nom du volumeemptyDir. - Revendication et provisionnement : lorsqu'une session d'agent démarre, votre orchestrateur crée un
SandboxClaim(avec un finaliseur de suppression) pour revendiquer un pod chaud et provisionne ou sélectionne un PVC Filestore de sauvegarde. - Lier le stockage sur l'hôte : votre orchestrateur résout l'UID, le nœud et les détails d'exportation NFS Filestore du pod revendiqué, ajoute un finaliseur de suppression au pod et demande au daemon du nœud de stockage sur ce nœud d'installer le volume NFS dans le chemin d'accès
emptyDirdu pod sur l'hôte. Lorsque la propagation de montage est activée, l'espace de travail installé apparaît immédiatement dans le conteneur gVisor en cours d'exécution. Dissociation avant le démontage : lorsque la session est suspendue ou se termine, votre orchestrateur demande au daemon du nœud de démonter le volume NFS du répertoire hôte avant de supprimer les finaliseurs de
PodetSandboxClaim.
Pour obtenir un exemple d'implémentation de référence en production qui automatise ces étapes avec un contrôleur personnalisé et un daemon de nœud authentifié, consultez l'exemple de stockage à liaison tardive GKE Sandbox sur GitHub.
Déployer le daemon du nœud de stockage
Pour tester le workflow de liaison tardive, déployez un DaemonSet privilégié sur vos nœuds gVisor qui installe les utilitaires client NFS sur l'hôte et fournit un environnement d'exécution pour les commandes d'installation de l'hôte.
Créez un fichier manifeste nommé
storage-node-daemon.yaml:apiVersion: apps/v1 kind: DaemonSet metadata: name: storage-node-daemon namespace: default spec: selector: matchLabels: app: storage-node-daemon template: metadata: labels: app: storage-node-daemon spec: hostPID: true nodeSelector: sandbox.gke.io/runtime: gvisor tolerations: - key: "sandbox.gke.io/runtime" operator: "Equal" value: "gvisor" effect: "NoSchedule" containers: - name: daemon image: debian:stable-slim securityContext: privileged: true command: ["/bin/sh", "-c"] args: - | nsenter -t 1 -m -u -i -n -- apt-get update && \ nsenter -t 1 -m -u -i -n -- apt-get install -y nfs-common || true sleep infinityAppliquez le fichier manifeste :
kubectl apply -f storage-node-daemon.yaml
Configurer SandboxTemplate et SandboxWarmPool
Pour permettre la propagation des installations d'hôte dynamiques dans un bac à sable gVisor en cours d'exécution, votre SandboxTemplate doit inclure l'annotation dev.gvisor.empty-dir.workspace-volume.force-shared: "true" et définir mountPropagation: HostToContainer sur l'installation de volume emptyDir.
Créez un fichier manifeste nommé
sandbox-latebind.yamlcontenant le modèle et le pool de préchauffage :apiVersion: extensions.agents.x-k8s.io/v1alpha1 kind: SandboxTemplate metadata: name: late-bind-template namespace: default spec: networkPolicyManagement: Unmanaged podTemplate: metadata: annotations: dev.gvisor.empty-dir.workspace-volume.force-shared: "true" spec: runtimeClassName: gvisor automountServiceAccountToken: false nodeSelector: sandbox.gke.io/runtime: gvisor tolerations: - key: "sandbox.gke.io/runtime" value: "gvisor" effect: "NoSchedule" securityContext: runAsNonRoot: true runAsUser: 1000 runAsGroup: 1000 fsGroup: 1000 containers: - name: agent image: busybox:latest securityContext: capabilities: drop: ["ALL"] allowPrivilegeEscalation: false volumeMounts: - name: workspace-volume mountPath: /workspace mountPropagation: HostToContainer env: - name: MOUNT_PATH value: "/workspace" - name: SUB_DIR value: "user_data" command: ["/bin/sh", "-c"] args: - | echo "Waiting for late-bind signal..." while [ ! -f $MOUNT_PATH/.ready ]; do sleep 0.05; done echo "Filestore volume mounted successfully!" ls -la $MOUNT_PATH/$SUB_DIR date >> $MOUNT_PATH/$SUB_DIR/session.txt sleep infinity volumes: - name: workspace-volume emptyDir: {} --- apiVersion: extensions.agents.x-k8s.io/v1alpha1 kind: SandboxWarmPool metadata: name: late-bind-warmpool namespace: default spec: replicas: 2 sandboxTemplateRef: name: late-bind-templateAppliquez le fichier manifeste :
kubectl apply -f sandbox-latebind.yaml
Revendiquer un bac à sable et lier dynamiquement l'espace de stockage
Créez un fichier manifeste nommé
late-bind-claim.yamlqui revendique un bac à sable chaud avec un finaliseur de suppression (agent.sandbox/storage-cleanup) et provisionne un PVC de volume d'agent Filestore :apiVersion: extensions.agents.x-k8s.io/v1alpha1 kind: SandboxClaim metadata: name: late-bind-session-1 namespace: default finalizers: - agent.sandbox/storage-cleanup spec: sandboxTemplateRef: name: late-bind-template --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: session-1-pvc namespace: default spec: accessModes: [ReadWriteMany] storageClassName: volume-pool-sc resources: requests: storage: 1GiAppliquez le fichier manifeste :
kubectl apply -f late-bind-claim.yaml
Récupérez les détails du pod attribué et les attributs d'exportation NFS Filestore sous-jacents :
POD_NAME=$(kubectl get pods \ -l extensions.agents.x-k8s.io/claimed-by=late-bind-session-1 \ -o jsonpath='{.items[0].metadata.name}') POD_UID=$(kubectl get pod "${POD_NAME}" -o jsonpath='{.metadata.uid}') NODE_NAME=$(kubectl get pod "${POD_NAME}" -o jsonpath='{.spec.nodeName}') PV_NAME=$(kubectl get pvc session-1-pvc -o jsonpath='{.spec.volumeName}') NFS_IP=$(kubectl get pv "${PV_NAME}" \ -o jsonpath='{.spec.csi.volumeAttributes.ip}') NFS_PATH="/$(kubectl get pv "${PV_NAME}" \ -o jsonpath='{.spec.csi.volumeAttributes.volume}')"Ajoutez un finaliseur de suppression au pod revendiqué pour empêcher Kubelet de supprimer le pod pendant que l'installation de l'hôte est active :
kubectl patch pod "${POD_NAME}" --type=merge \ -p '{"metadata":{"finalizers":["agent.sandbox/storage-cleanup"]}}'Installez le volume NFS Filestore dans le répertoire
emptyDirde l'hôte du pod et signalez l'état de préparation :DAEMON_POD=$(kubectl get pods -l app=storage-node-daemon \ --field-selector spec.nodeName="${NODE_NAME}" \ -o jsonpath='{.items[0].metadata.name}') HOST_DIR="/var/lib/kubelet/pods/${POD_UID}/volumes/kubernetes.io~empty-dir/workspace-volume" kubectl exec "${DAEMON_POD}" -- nsenter -t 1 -m -- sh -c " mkdir -p ${HOST_DIR}/user_data && mount -t nfs ${NFS_IP}:${NFS_PATH} ${HOST_DIR}/user_data && chown -R 1000:1000 ${HOST_DIR}/user_data && echo ready > ${HOST_DIR}/.ready "Vérifiez que le volume est installé dans le pod de bac à sable en cours d'exécution :
kubectl logs "${POD_NAME}" -c agentLe résultat confirme que le volume a été installé :
Waiting for late-bind signal... Filestore volume mounted successfully! drwxr-xr-x 2 1000 1000 4096 ... user_data
Dissocier le stockage et libérer le bac à sable
Lorsqu'une session d'agent est suspendue ou se termine, démontez l'espace de stockage de l'hôte avant d'autoriser Kubernetes à supprimer le pod.
Lancez la suppression de
SandboxClaimen arrière-plan. En raison du finaliseur, Kubernetes marque la revendication pour suppression, mais suspend l'arrêt du pod :kubectl delete sandboxclaim late-bind-session-1 --wait=false
Démontez le volume NFS Filestore sur le nœud hôte :
kubectl exec "${DAEMON_POD}" -- nsenter -t 1 -m -- \ umount -l "${HOST_DIR}/user_data"Supprimez les finaliseurs du
SandboxClaimet du pod pour terminer l'arrêt :kubectl patch sandboxclaim late-bind-session-1 --type=merge \ -p '{"metadata":{"finalizers":[]}}' kubectl patch pod "${POD_NAME}" --type=merge \ -p '{"metadata":{"finalizers":[]}}'
Pour reprendre la session ultérieurement, créez un SandboxClaim et installez le PVC existant (session-1-pvc) dans le pod chaud nouvellement revendiqué.
Étapes suivantes
- Découvrez l'intégration statique d'Agent Sandbox.
- Déployez des charges de travail GKE autogérées.
- Découvrez comment créer et gérer des pools de volumes.