Aller au contenu principal

Hermes Agent sur GKE Autopilot

Hermes Agent sur GKE Autopilot

Hermes Agent est l'agent d'IA personnel open source (sous licence MIT), auto-hébergé et auto-améliorant de Nous Research : il apprend des compétences par l'expérience, conserve une mémoire d'une session à l'autre, et se connecte à des plateformes de messagerie ainsi qu'à une API compatible OpenAI depuis un unique processus de passerelle (documentation). Ce module déploie l'image officielle nousresearch/hermes-agent sur GKE Autopilot au-dessus du socle App_GKE, qui provisionne et gère l'infrastructure Google Cloud et Kubernetes partagée.

Ce guide se concentre sur les services cloud qu'utilise Hermes et sur la manière de les explorer et de les exploiter depuis la console Google Cloud et la ligne de commande. Pour les mécanismes communs à toutes les applications GKE — Workload Identity, entrée, autoscaling, CI/CD, Cloud Armor, IAP, Binary Authorization, VPC Service Controls, sauvegardes et cycle de vie du déploiement — reportez-vous au guide du socle App_GKE plutôt que de les répéter ici.


1. Vue d'ensemble​

Hermes s'exécute sous la forme d'un pod de passerelle à réplica unique sur GKE Autopilot. Le déploiement assemble un ensemble délibérément restreint de services Google Cloud :

FonctionnalitéService Google CloudRemarques
CalculGKE AutopilotPod de passerelle, 2 vCPU / 2 GiB par défaut, réplicas min=1 / max=1
État de l'agentNFS autogéré (Services_GCP)Monté sur /opt/data — configuration SQLite, sessions, compétences, mémoires. Pas de Cloud SQL
SecretsSecret Manager (+ SecretSync)ANTHROPIC_API_KEY, API_SERVER_KEY et mot de passe du tableau de bord générés automatiquement, OPENAI_API_KEY / TELEGRAM_BOT_TOKEN facultatifs
Image de conteneurArtifact Registry (miroir)Image préconstruite officielle mise en miroir ; aucun build personnalisé, aucune étape Cloud Build
RéseauVPC + Cloud Load BalancingService LoadBalancer externe avec adresse IP statique réservée par défaut
Base de données / cache—Ni Cloud SQL, ni Redis — Hermes repose entièrement sur SQLite sur NFS

Valeurs par défaut judicieuses à connaître d'emblée :

  • Tout l'état de l'agent se trouve dans /opt/data, et ce chemin est fixé dans l'image. Le NFS partagé de la plateforme est monté directement par-dessus (enable_nfs = true, nfs_mount_path = "/opt/data", tous deux par défaut et imposés par une validation au moment du plan). Sans ce montage, chaque redémarrage de pod ou redéploiement efface silencieusement l'identité accumulée par l'agent.
  • max_instance_count est validé à 1. L'état de Hermes est en SQLite, qui suit un modèle à écrivain unique — un second réplica simultané corrompt la base de données. Le socle déploie en outre les applications adossées à NFS avec la stratégie Recreate, afin que les mises à jour ne fassent jamais tourner brièvement deux pods sur le volume.
  • Le serveur d'API compatible OpenAI écoute sur le port 8642 et exige l'API_SERVER_KEY générée automatiquement comme jeton bearer.
  • Les sondes sont par défaut des sondes TCP d'écoute de port — le serveur d'API exige une authentification, si bien qu'une sonde HTTP recevrait un 401 et bloquerait le déploiement.
  • Le tableau de bord web (port 9119, authentification basique) n'est pas exposé par le Service — accédez-y avec kubectl port-forward.
  • API_SERVER_KEY est injectée sous forme de Secret Kubernetes explicite plutôt que via SecretSync, qui peut matérialiser une valeur vide au premier déploiement avant la fin de la réplication de Secret Manager. Tous les autres secrets sont adossés à SecretSync.
  • Au moins une clé de fournisseur de modèles est requise lors du déploiement initial (anthropic_api_key, ou enable_openai + openai_api_key) ; un contrôle au moment du plan avertit lorsqu'aucune n'est fournie.
  • Aucun job d'initialisation, aucun amorçage de base de données — le premier démarrage se contente d'initialiser /opt/data sur le partage NFS.

2. Services Google Cloud et comment les explorer​

Toutes les commandes supposent que vous avez exécuté gcloud container clusters get-credentials <cluster> --region <region> --project <project> et que PROJECT, REGION et NAMESPACE sont définis. L'espace de noms et les autres identifiants figurent dans les sorties du déploiement.

A. GKE Autopilot — la charge de travail Hermes​

Le pod de passerelle Hermes est planifié sur Autopilot, qui facture le CPU et la mémoire réellement demandés par le pod. Les réplicas sont fixés à un ; les signaux intéressants sont la disponibilité du pod, les redémarrages et le montage du volume NFS.

  • Console : Kubernetes Engine → Workloads → sélectionnez la charge de travail Hermes pour voir les pods et les événements ; Services & Ingress affiche l'adresse IP externe.
  • CLI :
    kubectl get pods,svc -n "$NAMESPACE"
    kubectl describe pod -n "$NAMESPACE" <pod> # events: probes, mounts
    kubectl logs -n "$NAMESPACE" deploy/<service-name> --tail=100

Consultez App_GKE pour Autopilot, les types de charges de travail et le cycle de vie du déploiement.

B. Stockage partagé NFS — l'identité de l'agent​

L'intégralité de l'état de l'agent (base de configuration SQLite, clés d'API, sessions, compétences apprises, mémoires) réside sur le serveur NFS autogéré partagé provisionné par Services_GCP (create_network_filesystem = true), monté sur /opt/data dans le pod. La VM NFS doit être à l'état RUNNING avant le déploiement de ce module — la découverte la trouve par son libellé.

  • Console : Compute Engine → VM instances (la VM du serveur NFS).
  • CLI :
    gcloud compute instances list --project "$PROJECT" \
    --filter="name~nfs" --format="table(name,zone,status)"
    # Confirm the mount inside the pod:
    kubectl exec -n "$NAMESPACE" deploy/<service-name> -- df -h /opt/data
    kubectl exec -n "$NAMESPACE" deploy/<service-name> -- ls /opt/data

Le partage et ses données appartiennent à Services_GCP — détruire le déploiement Hermes ne supprime pas l'état de l'agent sur l'export NFS.

C. Secret Manager​

Cinq secrets peuvent exister par déploiement : ANTHROPIC_API_KEY (fourni par l'opérateur), API_SERVER_KEY (hexadécimal de 64 caractères généré automatiquement — le jeton bearer de l'API de la passerelle), HERMES_DASHBOARD_BASIC_AUTH_PASSWORD (généré automatiquement) et, en option, OPENAI_API_KEY et TELEGRAM_BOT_TOKEN. Ils apparaissent dans l'espace de noms sous forme de Secrets Kubernetes (SecretSync pour la plupart ; un Secret explicite pour API_SERVER_KEY).

  • Console : Security → Secret Manager.
  • CLI :
    gcloud secrets list --project "$PROJECT" --filter="name~hermes"
    gcloud secrets versions access latest --secret=<secret-name> --project "$PROJECT"
    kubectl get secrets -n "$NAMESPACE"

Des variables d'identifiants laissées vides lors d'un déploiement de mise à jour conservent la version latest stockée. Consultez App_GKE pour l'intégration de SecretSync.

D. Artifact Registry — l'image mise en miroir​

L'image officielle nousresearch/hermes-agent:<version> est mise en miroir dans Artifact Registry avant le déploiement (enable_image_mirroring = true) afin que les nœuds ne tirent jamais depuis Docker Hub. Il n'y a aucune étape Cloud Build — il s'agit d'un module préconstruit. Les images mises en miroir sont tirées avec imagePullPolicy: Always.

  • Console : Artifact Registry → Repositories.
  • CLI :
    gcloud artifacts repositories list --project "$PROJECT" --location "$REGION"
    gcloud artifacts docker images list \
    "$REGION-docker.pkg.dev/$PROJECT/<repo>" --filter="package~hermes"

E. Réseau et entrée​

La passerelle est exposée par défaut via un Service LoadBalancer externe, avec une adresse IP statique réservée afin que l'adresse survive aux redéploiements. Le serveur d'API applique sa propre authentification par jeton bearer ; le caractère public du point de terminaison est donc voulu. Un domaine personnalisé avec un certificat géré peut être ajouté via la Gateway API.

  • Console : Network services → Load balancing ; VPC network → IP addresses.
  • CLI :
    kubectl get svc -n "$NAMESPACE"
    gcloud compute addresses list --project "$PROJECT"

Consultez App_GKE pour les domaines personnalisés, Cloud CDN et les adresses IP statiques.

F. Cloud Logging et Monitoring​

Les sorties stdout/stderr des pods sont envoyées vers Cloud Logging ; les métriques GKE vers Cloud Monitoring. Le test de disponibilité est désactivé par défaut — le serveur d'API exige une authentification, si bien qu'un test de disponibilité non authentifié échouerait toujours.

  • Console : Logging → Logs Explorer ; Monitoring → Dashboards / Alerting.
  • CLI :
    gcloud logging read 'resource.type="k8s_container" AND resource.labels.namespace_name="'"$NAMESPACE"'"' \
    --project "$PROJECT" --limit 50

3. Comportement de l'application Hermes​

  • Initialisation du répertoire de données au premier démarrage. L'ENTRYPOINT de l'image est /init de s6-overlay, qui démarre en tant que root, applique chown au volume /opt/data (le nouveau répertoire NFS) au profit de l'utilisateur non root hermes, puis abandonne ses privilèges et démarre la passerelle (container_args = ["gateway", "run"] — le CMD par défaut de l'image est la CLI interactive, la passerelle doit donc être démarrée explicitement).
  • Aucun job d'initialisation de base de données. Hermes crée sa propre base de configuration SQLite sous /opt/data au premier démarrage ; il n'y a rien à amorcer et initialization_jobs est vide. database_type = "NONE" et enable_redis = false sont codés en dur dans l'appel au socle.
  • L'accès à l'API exige l'API_SERVER_KEY. Le point de terminaison compatible OpenAI sur le port 8642 s'authentifie avec un jeton bearer :
    KEY=$(gcloud secrets versions access latest --secret=<api-server-key-secret> --project "$PROJECT")
    EXTERNAL_IP=$(kubectl get svc -n "$NAMESPACE" \
    -o jsonpath='{.items[?(@.spec.type=="LoadBalancer")].status.loadBalancer.ingress[0].ip}')
    curl -s -H "Authorization: Bearer $KEY" "http://${EXTERNAL_IP}:8642/v1/models"
    (Le Service associe son port au port du conteneur ; vérifiez le port exposé avec kubectl get svc.)
  • Tableau de bord via port-forward. Le tableau de bord web intégré au processus (gestion des clés d'API, configuration des profils) s'exécute sur le port 9119 derrière une authentification basique et n'est pas exposé par le Service. Accédez-y en local :
    kubectl port-forward -n "$NAMESPACE" deploy/<service-name> 9119:9119
    # then open http://localhost:9119 — user `admin`, password from Secret Manager
  • Configuration des connecteurs (Telegram). Définissez enable_telegram = true et fournissez telegram_bot_token (obtenu auprès de @BotFather). Le connecteur Telegram de Hermes interroge en long polling sortant — aucun webhook, routeur ou URL de rappel publique n'est nécessaire. Une validation au moment du plan rejette enable_telegram = true avec un jeton vide. Les autres connecteurs (Discord, Slack, WhatsApp, Signal) se configurent via la map environment_variables de l'opérateur.
  • Les mises à jour de version utilisent Recreate. Comme l'application est adossée à NFS, le socle remplace le pod en l'arrêtant puis en le redémarrant, au lieu d'une mise à jour progressive — une brève interruption de disponibilité pendant les mises à jour est attendue et protège la base SQLite d'un chevauchement à deux écrivains.

4. Variables de configuration​

Les variables sont regroupées exactement comme elles apparaissent sur la plateforme de déploiement. Seuls les paramètres propres à Hermes ou notables pour lui sont listés ; toutes les autres entrées sont héritées d'App_GKE avec leur comportement et leurs valeurs par défaut standard.

Groupe 1 — Projet, identité et identifiants​

VariableValeur par défautDescription
project_id(obligatoire)Projet Google Cloud cible.
regionus-central1Région de la charge de travail et des ressources régionales.
anthropic_api_key""Clé du fournisseur de modèles principal, injectée en tant que ANTHROPIC_API_KEY. Obligatoire lors du déploiement initial (ou utilisez OpenAI) ; omettez-la lors des mises à jour pour conserver la version stockée.
api_server_key"" (auto)Jeton bearer du serveur d'API compatible OpenAI. Hexadécimal de 64 caractères généré automatiquement s'il est vide.
enable_openai / openai_api_keyfalse / ""Fournisseur secondaire facultatif, injecté en tant que OPENAI_API_KEY.
enable_dashboardtrueExécute le tableau de bord sur le port 9119 dans le processus ; accessible via kubectl port-forward.
dashboard_username / dashboard_passwordadmin / "" (auto)Authentification basique du tableau de bord ; mot de passe généré automatiquement dans Secret Manager.

Groupe 3 — Identité de l'application​

VariableValeur par défautDescription
application_namehermesNom de base des ressources. Ne le modifiez pas après le premier déploiement.
application_versionlatestTag de l'image nousresearch/hermes-agent ; épinglez un tag de version en production.

Groupe 4 — Exécution et mise à l'échelle​

VariableValeur par défautDescription
container_resources2000m / 2GiLimites de CPU et de mémoire du conteneur de passerelle.
min_instance_count1Conservez 1 pour éviter les démarrages à froid des sessions de l'agent.
max_instance_count1Validé à 1 — SQLite à écrivain unique sur le NFS partagé.
container_port8642Port du serveur d'API compatible OpenAI de la passerelle.
timeout_seconds3600Les sessions de l'agent peuvent être de longue durée.
container_image_sourceprebuiltDéploie l'image officielle sans étape de build.
enable_image_mirroringtrueMet l'image en miroir dans Artifact Registry pour éviter les limites de débit de Docker Hub.

Groupe 5 — Variables d'environnement et secrets​

VariableValeur par défautDescription
environment_variables{}Configuration supplémentaire ; les variables gérées par le module (API_SERVER_*, HERMES_DASHBOARD*) sont prioritaires. À utiliser pour les identifiants des connecteurs Discord/Slack/WhatsApp/Signal ou les points de terminaison de fournisseurs (par exemple OpenRouter).
secret_environment_variables{}Map variable d'environnement → nom d'un secret Secret Manager existant.

Groupe 6 — Backend GKE et cluster​

VariableValeur par défautDescription
service_typeLoadBalancerAdresse IP externe par défaut ; le serveur d'API applique une authentification par jeton bearer.
session_affinityClientIPRoutage persistant (réplica unique, donc sans grande portée).
termination_grace_period_seconds60Délai laissé aux sessions actives de l'agent pour se terminer à l'arrêt.

Groupe 10 — Observabilité et santé​

VariableValeur par défautDescription
startup_probeTCP, délai de 10s, 36 tentativesÉcoute de port TCP — sûre quelle que soit l'authentification du serveur d'API ; marge pour le montage NFS et l'initialisation au premier démarrage.
liveness_probeTCP, délai de 30sÉcoute de port TCP.
uptime_check_configdésactivéUn test de disponibilité non authentifié échouerait toujours face au serveur d'API authentifié.

Groupe 13 — Système de fichiers (NFS)​

VariableValeur par défautDescription
enable_nfstrueObligatoire — validé. Toute l'identité de l'agent réside sous /opt/data.
nfs_mount_path/opt/dataRépertoire de données fixe de l'image ; le partage NFS est monté directement par-dessus.

Groupe 14 — Cloud Storage et Artifact Registry​

VariableValeur par défautDescription
gcs_volumes[]Montages GCSFuse auxiliaires uniquement — ne pointez jamais l'un d'eux vers /opt/data (SQLite n'est pas sûr sur GCSFuse).
max_images_to_retain / delete_untagged_images / image_retention_days(définies)Règle de nettoyage d'Artifact Registry.

Groupe 15 — Connecteurs Hermes​

VariableValeur par défautDescription
enable_telegramfalseProvisionne le secret du jeton du bot Telegram et injecte TELEGRAM_BOT_TOKEN.
telegram_bot_token""Jeton du bot obtenu auprès de @BotFather ; obligatoire (validé) lorsque enable_telegram = true.

Groupe 19 — Domaine personnalisé et IP statique​

VariableValeur par défautDescription
enable_custom_domaintrueConfiguration de domaine personnalisé via la Gateway API avec SSL géré (nécessite application_domains).
reserve_static_iptrueAdresse IP externe stable d'un redéploiement à l'autre.

Variables inertes conservées par convention : les variables de base de données (groupe 16), Redis (miroirs du groupe 15), SQL personnalisé (groupe 18) et enable_cloudsql_volume sont déclarées par souci de cohérence avec la convention, mais codées en dur à off dans main.tf — Hermes n'a ni base de données ni Redis.


5. Sorties​

Ces valeurs sont renvoyées lors d'un déploiement réussi et constituent le moyen le plus rapide de localiser et d'explorer les ressources en cours d'exécution.

SortieDescription
service_nameNom du Service Kubernetes.
namespaceEspace de noms dans lequel s'exécute la charge de travail.
service_cluster_ipClusterIP interne au cluster.
stage_service_cluster_ipsMap des ClusterIP des services propres à chaque étape.
service_external_ipAdresse IP externe du LoadBalancer (lorsqu'une IP statique est réservée).
api_urlURL permettant d'atteindre le serveur d'API de la passerelle.
storage_bucketsBuckets Cloud Storage créés (aucun par défaut).
network_name / network_exists / regionsRéseau VPC, présence, régions disponibles.
container_image / container_registryImage déployée et dépôt Artifact Registry.
monitoring_enabled / monitoring_notification_channelsÉtat de la surveillance et canaux.
initialization_jobs / cron_jobsNoms des jobs d'initialisation et planifiés (vides par défaut).
statefulset_nameNom du StatefulSet (lorsqu'une charge de travail StatefulSet est sélectionnée).
deployment_id / tenant_id / resource_prefixIdentifiants de nommage.
project_id / project_numberIdentifiants du projet.
cicd_enabled / cicd_configurationÉtat et détails de la CI/CD.
github_repository_url / github_repository_owner / github_repository_nameDétails GitHub de la CI/CD.
artifact_registry_repository / cloudbuild_trigger_name / cloudbuild_trigger_idDépôt et déclencheur de build.
kubernetes_readyIndique si le point de terminaison du cluster était lisible et si les charges de travail Kubernetes ont été déployées (false lors du premier apply d'un nouveau cluster inline — relancez l'apply).

6. Pièges de configuration et valeurs par défaut judicieuses​

Risque : Critique (perte de données / panne / sécurité) — Élevé (service dégradé) — Moyen (coût ou dégradation partielle) — Faible (mineur).

Validation au moment du plan. Le fichier validation.tf de ce module et le moteur du socle App_GKE valident les valeurs et leurs combinaisons au moment du plan — max_instance_count > 1, enable_nfs = false, un connecteur Telegram sans son jeton, ou OpenAI activé sans clé font tous échouer le plan avec une erreur claire et nommée avant la création de toute ressource.

ParamètreValeur judicieuseRisqueConséquence en cas d'erreur
max_instance_count1 (validé)CritiqueUn second réplica simultané écrit dans la même base SQLite sur NFS — la violation du modèle à écrivain unique corrompt tout l'état de l'agent.
enable_nfstrue (validé)CritiqueSans le montage NFS, /opt/data est un disque de pod éphémère — chaque redémarrage / redéploiement efface silencieusement l'identité de l'agent (configuration, sessions, compétences, mémoires).
gcs_volumes sur /opt/datajamaisCritiqueGCSFuse ne fournit ni verrouillage POSIX ni renommages atomiques ; SQLite sur GCSFuse se corrompt. Conservez l'état sur NFS.
quota_memory_requests / _limitsunités binaires (4Gi, 8192Mi)CritiqueLes entiers nus sont des octets et bloquent toute planification de pods dans l'espace de noms.
anthropic_api_key (ou la paire OpenAI)définie au premier déploiementÉlevéSans aucune clé de fournisseur, l'agent ne peut pas exécuter un seul tour.
VM NFS pas à l'état RUNNINGattendre avant de déployerÉlevéLa découverte ne trouve aucun serveur → le module crée un NFS inline ou le montage échoue ; le pod reste bloqué en ContainerCreating.
startup_probe / liveness_probeTCP (par défaut)MoyenUne sonde HTTP contre le serveur d'API authentifié renvoie 401/403 indéfiniment — le pod ne devient jamais Ready et le déploiement reste bloqué.
min_instance_count1MoyenGKE n'a pas de mise à l'échelle à zéro, mais une réduction manuelle met les connecteurs hors ligne.
application_versionépingler un tag de versionMoyenlatest est résolu à nouveau à chaque mise en miroir ; le comportement peut changer à votre insu lors d'un redéploiement.
enable_telegram sans jetonbloquéFaibleLa validation au moment du plan le rejette ; le connecteur ne peut pas démarrer sans le jeton du bot.

Pour le comportement du socle évoqué tout au long de ce guide — IAM et Workload Identity, entrée et certificats, CI/CD, Cloud Armor, IAP, Binary Authorization, VPC-SC, sauvegardes et mise en miroir des images — consultez App_GKE. La configuration applicative propre à Hermes, partagée avec la variante Cloud Run, est décrite dans Hermes_Common.

Need RAD to do something it does not do yet? Request it on the roadmap, or vote on what is already there.