Skip to content

Stack ​

Portée : namespaced · Umbrella optionnel · Sous licence (fonctionnalité managed-deployment + un quota stacks)

Stack est une resource umbrella optionnelle qui crée et possède un lot organisé des resources granulaires, câble automatiquement leurs références et agrège la progression — une expérience de provisionnement en une passe de type déploiement ARM.

Elle ne remplace pas les resources par composant. Les CRDs granulaires demeurent une manière de première classe de composer la plateforme à la main ; Stack se place simplement par-dessus pour les équipes qui souhaitent un objet unique pour gérer tout un environnement.

Quand l'utiliser ​

  • Utilisez Stack lorsque vous voulez provisionner et suivre un environnement complet (secrets
    • datastores + gateway + Observability + UI) comme une seule unité, l'opérateur câblant les références croisées pour vous et regroupant le statut en un seul endroit.
  • Utilisez les resources granulaires lorsque vous voulez un contrôle fin, que vous composez des resources à travers plusieurs namespaces à la main, ou que vous partagez des datastores entre plusieurs charges de travail gérées indépendamment.

Ce qu'elle fait ​

  • Crée + possède les composants groupés (l'opérateur définit des owner references afin que tout le lot soit collecté par le garbage collector avec le Stack).
  • Câble automatiquement les références entre eux (Gateway→Postgres, Gateway→Observability, ChatUI→Gateway, charges de travail→datastores) — cela repose sur la capacité auto-wiring.
  • Agrège la progression dans status.components[] et status.endpoints, de sorte qu'un seul kubectl get stack affiche l'état de préparation et les URLs de tout l'environnement.

Politique de dérive ​

Par défaut, le Stack applique en continu la spécification organisée à ses enfants : toute modification manuelle apportée à une CR de composant générée (par exemple augmenter la taille de stockage d'un datastore ou le nombre de réplicas d'une charge de travail) est annulée à la prochaine réconciliation. spec.driftPolicy permet d'assouplir ce comportement :

driftPolicyComportement
Enforce (par défaut)La spécification organisée est réappliquée à chaque réconciliation — les modifications manuelles des enfants sont annulées (correction complète de la dérive).
AdoptLa spécification organisée est appliquée à la création et chaque fois que la spécification du Stack lui-même change (un « redéploiement » de type ARM). Entre deux modifications du Stack, les modifications manuelles par composant sont préservées.

Adopt reproduit le comportement d'un déploiement Azure Resource Manager : le Stack initialise et câble les resources, puis vous pouvez ajuster chaque composant directement. Modifier le Stack lui-même réapplique chaque enfant et écrase votre dérive ; considérez donc une modification du Stack comme un redéploiement.

L'owner reference est conservée sous les deux politiques, de sorte que la suppression du Stack entraîne toujours en cascade la suppression (et le démantèlement) de chaque composant qu'il a créé.

yaml
apiVersion: core.navique.com/v1alpha1
kind: Stack
metadata:
  name: forge
spec:
  driftPolicy: Adopt   # permettre d'ajuster les composants individuellement après la création
  # ...

Dimensionnement des datastores ​

Chaque datastore géré sous spec.datastores accepte un raccourci resources optionnel qui dimensionne le CPU et la mémoire du conteneur sous-jacent. Il est pris en compte pour les datastores Postgres, ClickHouse, Redis et MongoDB (mode managed uniquement) et propagé vers l'enfant PostgresCluster / ClickHouseCluster / RedisInstance / MongoCluster émis, dans son champ managed.resources.

ChampCorrespond à
cpudemande (request) de CPU
memorydemande (request) de mémoire
memoryLimitlimite de mémoire

Le raccourci n'a délibérément pas de limite de CPU (les limites de CPU brident au lieu de protéger). Si vous en avez besoin, utilisez directement la CRD de datastore autonome, qui accepte un managed.resources complet.

yaml
apiVersion: core.navique.com/v1alpha1
kind: Stack
metadata:
  name: forge
spec:
  datastores:
    postgres:
      storageSize: 20Gi
      resources: { cpu: 500m, memory: 1Gi, memoryLimit: 2Gi }
    clickhouse:
      storageSize: 50Gi
      resources: { cpu: 500m, memory: 2Gi, memoryLimit: 3Gi }
    redis:
      storageSize: 5Gi
      resources: { cpu: 100m, memory: 256Mi, memoryLimit: 512Mi }
    mongo:
      storageSize: 20Gi
      resources: { cpu: 250m, memory: 1Gi, memoryLimit: 2Gi }

Si resources est omis, les valeurs par défaut du chart en amont s'appliquent (ClickHouse conserve sa limite mémoire de 3Gi réglée par l'opérateur pour éviter les OOM sous la charge de Langfuse).

Choisir l'implémentation de la passerelle ​

spec.gateway.type choisit le produit de passerelle : litellm (défaut) ou waeg (la passerelle Wäg, via le waeg-operator). Voir Gateway → Passerelle Wäg pour les différences.

Avec type: waeg, le Stack :

  • exige datastores.clickhouse.enabled dans le mode de stockage split par défaut — l'admission rejette le Stack sinon, car c'est là que vivent les analyses de Wäg. Posez gateway.waeg.storageMode: single pour les garder dans le Postgres du Stack, ce qui supprime entièrement cette exigence — voir Stockage analytique de Wäg ;
  • câble automatiquement le ClickHouse (et le Redis, s'il est activé) du Stack comme second plan de stockage de la passerelle — en mode split uniquement ;
  • déclare la base waeg sur ce ClickHouse pour que la passerelle puisse seulement démarrer : Wäg ne crée que ses tables, jamais sa base (ClickHouseCluster → databases[]) ;
  • nomme la base Postgres logique de la passerelle waeg plutôt que litellm, pour que les deux implémentations ne partagent jamais un schéma ;
  • n'attache aucune référence Langfuse — Wäg ne peut pas exporter les traces de façon déclarative, donc le Stack ne câble rien que la passerelle devrait refuser.

spec.gateway.waeg transmet les réglages propres à Wäg : topology, jobWorkers, worker, storageMode, openfga, autoscaling, bootstrapAdmin, dataEncryptionKeySecretRef, modelAccess, scim et jwt. La licence Enterprise se déclare une seule fois, via spec.gateway.licenseSecretRef, et l'organisation de la passerelle via spec.gateway.organization — dont une passerelle Wäg a besoin avant qu'une ChatUI puisse s'y rattacher.

yaml
spec:
  datastores:
    clickhouse: { enabled: true, backup: { enabled: true, provider: s3, s3: { destinationPath: s3://b } } }
    redis:      { enabled: true }
  gateway:
    enabled: true
    type: waeg
    licenseSecretRef: { name: waeg-enterprise-license, key: license }
    waeg:
      topology: Split
      worker: { enabled: true, replicas: 2 }
      scim:
        enabled: true
        tokenSecretRef: { name: waeg-scim-token, key: scim-token }
        defaultRole: viewer
      jwt:
        appClaim: azp
        requireRegisteredApplication: true

Les champs propres à LiteLLM décrits plus bas (rolePermissions, healthCheck, storePromptsInLogs, guardrails, limites par modèle — ainsi que la moitié « correspondances de claims » de jwtAuth) sont signalés sur la condition FeaturesSupported de la passerelle enfant lorsque type: waeg — ils ne sont jamais abandonnés en silence.

Stockage analytique de Wäg ​

spec.gateway.waeg.storageMode choisit où vivent les analyses de la passerelle (journaux de requêtes, usage, dépenses). C'est la transmission par le Stack de Gateway.spec.waeg.storageMode.

ModeLes analyses vivent dansdatastores.clickhouse.enabled
split (défaut)le ClickHouse du Stackrequis
singlele Postgres du Stackinutile — aucun ClickHouse n'est provisionné

Le défaut de Wäg lui-même est single, et c'est son point de départ recommandé ; cet opérateur conserve split par défaut, par continuité et parce qu'il tient la charge. Avec single, le Stack ne provisionne aucun ClickHouse et la règle d'admission qui en exigeait un ne s'applique plus. Conserver le défaut sans ClickHouse est rejeté avec :

gateway.type=waeg with the default storageMode 'split' requires
datastores.clickhouse.enabled; set gateway.waeg.storageMode: single to keep
analytics in Postgres instead

Changer de mode ne migre pas l'historique analytique

Les deux plans sont des magasins distincts. Modifier storageMode sur un Stack en service pointe la passerelle vers l'autre ; les analyses déjà collectées restent où elles sont, et ni l'opérateur ni Wäg ne les recopie.

yaml
apiVersion: core.navique.com/v1alpha1
kind: Stack
metadata:
  name: forge
  namespace: forge
spec:
  datastores:
    postgres:
      enabled: true
      storageSize: 20Gi
      backup: { enabled: true, provider: s3, s3: { destinationPath: s3://forge-pg } }
    redis: { enabled: true }
    # aucun bloc clickhouse — storageMode: single n'en a pas besoin
  gateway:
    enabled: true
    type: waeg
    organization: { name: forge }
    waeg:
      storageMode: single

En mode split (le défaut), le Stack déclare en plus la base waeg sur son ClickHouse managé, car Wäg ne crée que ses tables et jamais sa base — voir ClickHouseCluster → databases[].

Organisation du gateway ​

spec.gateway.organization crée l'organisation de premier niveau de la passerelle — l'objet sur lequel remontent les budgets et les plafonds de débit. Le champ est transmis tel quel à spec.organization du Gateway enfant.

ChampDescription
name (obligatoire)Nom de l'organisation
maxBudgetPlafond de dépenses de l'organisation
budgetDurationPériode au terme de laquelle le plafond est réinitialisé (p. ex. 30d). LiteLLM uniquement — les politiques de budget de Wäg n'ont pas de champ de période
rpmLimitPlafond de requêtes par minute
tpmLimitPlafond de tokens par minute

Sur une passerelle type: litellm, l'organisation reste optionnelle : les équipes, les clés et les modèles fonctionnent sans elle.

Une passerelle Wäg en exige une avant qu'une ChatUI puisse s'y rattacher

Avec type: waeg, ce champ est obligatoire pour câbler automatiquement une ChatUI. Wäg n'a pas de clé virtuelle autonome : une clé appartient à une application, et les applications sont rattachées à une organisation — sans organisation, il n'y a donc rien sous quoi émettre les identifiants de la ChatUI. Avant l'existence de ce champ, un Stack avec gateway.type: waeg et chatUI.enabled: true laissait la ChatUI bloquée sur

Gateway "…" is type=waeg and has no spec.organization: a Wäg virtual key belongs
to an application, and applications are org-rooted

sans rien de réglable depuis un Stack pour y remédier : le Gateway granulaire disposait de spec.organization, le Stack n'offrait aucune transmission. Renseignez-le ici et l'opérateur enregistre la ChatUI comme WaegApplication sous cette organisation, puis émet sa WaegVirtualKey à partir d'elle.

C'est également à l'organisation que se rattachent les autorisations de spec.gateway.waeg.modelAccess : l'ACL de modèles est déclarée contre elle et reste sans effet sans elle.

yaml
spec:
  datastores:
    clickhouse: { enabled: true, backup: { enabled: true, provider: s3, s3: { destinationPath: s3://forge-ch } } }
    redis:      { enabled: true }
  gateway:
    enabled: true
    type: waeg
    licenseSecretRef: { name: waeg-enterprise-license, key: license }
    organization:
      name: navique-ag
      maxBudget: 2000
      rpmLimit: 1000
      tpmLimit: 500000
    waeg:
      modelAccess:                  # rattaché à l'organisation : elle est requise
        openByDefault: false
        fallbackMode: deny
        grants:
          - models: [premium, economy]
  chatUI:
    enabled: true                   # câblée comme application sous navique-ag

Voir ChatUI se connecte en tant qu'application pour les objets émis par l'opérateur, et Ce qui n'est pas appliqué pour les champs d'organisation que Wäg ne peut pas honorer.

Licence Enterprise du gateway ​

spec.gateway.licenseSecretRef fournit la licence Enterprise de la passerelle et est transmis à instance.licenseSecretRef du Gateway. Avec type: litellm, il s'agit de la clé LiteLLM Enterprise ; avec type: waeg, de la licence Wäg Enterprise — et donc de la différence entre une passerelle Enterprise opérationnelle et une passerelle qui répond 402 license_required.

Chaque module Wäg Enterprise en dépend — SSO, SCIM, audit, CMEK, FIPS et l'habillage de la console — et son application est inconditionnelle. Sans ce champ, une passerelle Wäg gérée par un Stack n'a donc aucune fonctionnalité Enterprise accessible.

yaml
spec:
  gateway:
    type: waeg
    licenseSecretRef: { name: waeg-enterprise-license, key: license }

La clé du Secret vaut license par défaut. Laissez le backend SecretsManagement du Stack matérialiser le Secret plutôt que de le créer à la main.

L'habillage suit la licence

Dès qu'une passerelle Wäg est sous licence, l'opérateur applique automatiquement le thème Navique intégré à sa console (une ConfigMap <gateway>-branding qu'il possède). Le Stack n'offre pas de champ de retrait — pour votre propre thème, ou pour conserver la livrée de Wäg, utilisez le Gateway granulaire avec waeg.brandingConfigMapRef / waeg.defaultBranding: false.

Dimensionnement du gateway ​

spec.gateway.resources dimensionne le conteneur du proxy LiteLLM. Contrairement au raccourci des datastores, il s'agit d'un ResourceRequirements Kubernetes complet (vous pouvez donc définir une limite de CPU) ; il est transmis tel quel à instance.resources du Gateway émis → spec.resources de la LiteLLMInstance. L'omettre laisse la valeur par défaut du litellm-operator.

yaml
spec:
  gateway:
    resources:
      requests: { cpu: "500m", memory: 512Mi }
      limits:   { cpu: "2", memory: 2Gi }

Épingler le build du proxy gateway ​

spec.gateway.image épingle l'image du proxy LiteLLM. La valeur est transmise au Gateway généré (instance.image), puis à la LiteLLMInstance (spec.image).

yaml
spec:
  gateway:
    image:
      repository: ghcr.io/berriai/litellm
      tag: v1.94.0-dev.2

Laissez ce champ vide sauf si vous qualifiez un build précis. Sans épinglage, le litellm-operator applique son propre tag par défaut — celui qui est validé avec son point d'entrée de migration de base de données. Un tag arbitraire peut casser la migration et rendre le gateway indisponible.

Ne corrigez pas le Gateway enfant à la main : avec la politique de dérive par défaut Enforce, la Stack réapplique ses ressources enfants à chaque réconciliation et votre modification est annulée en quelques secondes. Déclarez l'épinglage ici.

Auth JWT & RBAC du gateway ​

spec.gateway.jwtAuth et spec.gateway.rolePermissions activent l'authentification d'API par JWT et l'accès aux modèles par rôle sur le gateway du Stack — transmis directement à instance.jwtAuth / instance.rolePermissions du gateway. Voir Authentification d'API par JWT & RBAC pour les champs. Nécessite une licence LiteLLM Enterprise.

yaml
spec:
  gateway:
    jwtAuth:
      enabled: true
      userRolesJWTField: roles
      userAllowedRoles: ["basic_user"]
      enforceRBAC: true
    rolePermissions:
      internal_user: { models: ["anthropic-claude"] }

Habillage de la console Wäg ​

spec.gateway.waeg.brandingConfigMapRef et defaultBranding sont transmis à l'habillage de la console de la passerelle : le thème Navique par défaut, votre propre thème avec la fonctionnalité sous licence custom-branding, ou la livrée propre à Wäg avec defaultBranding: false.

Sur une passerelle Wäg ​

spec.gateway.jwtAuth active aussi l'authentification JWT pour type: waeg — enabled, publicKeyURL (→ le jwksUrl de Wäg), issuer, audience et userIDJWTField (→ subjectClaim) s'appliquent. Les réglages propres à Wäg vivent dans spec.gateway.waeg.jwt ; spec.gateway.rolePermissions et les correspondances de claims (userRolesJWTField, userRoleJWTField, userAllowedRoles, enforceRBAC, userIDUpsert, teamIDsJWTField, adminJWTScope) sont en revanche signalés comme non pris en charge : Wäg autorise via OpenFGA et les applications enregistrées. Voir Authentification JWT du plan de données.

yaml
spec:
  gateway:
    type: waeg
    licenseSecretRef: { name: waeg-enterprise-license, key: license }
    jwtAuth:
      enabled: true
      publicKeyURL: https://login.microsoftonline.com/<tenant>/discovery/v2.0/keys
      issuer: https://login.microsoftonline.com/<tenant>/v2.0
      audience: <client-id>
      userIDJWTField: sub
    waeg:
      jwt:
        appClaim: azp
        requireRegisteredApplication: true

Les commutateurs de durcissement peuvent empêcher le démarrage

waeg.jwt.allowMasterKey: false ou allowVirtualKeys: false exigent jwtAuth.enabled: true, une publicKeyURL, une audience et insecureSkipVerify: false — sinon Wäg refuse de démarrer. allowVirtualKeys: false coupe en outre toutes les clés d'application, y compris celle de la ChatUI du Stack.

Approvisionnement SCIM Wäg ​

spec.gateway.waeg.scim active les points d'accès SCIM v2 de Wäg sur la passerelle du Stack : votre IdP approvisionne et retire directement les utilisateurs de la console. C'est indépendant du SSO — cela fonctionne sans aucune connexion interactive câblée — et cela exige spec.gateway.licenseSecretRef.

yaml
spec:
  gateway:
    type: waeg
    licenseSecretRef: { name: waeg-enterprise-license, key: license }
    waeg:
      scim:
        enabled: true                                              # défaut
        tokenSecretRef: { name: waeg-scim-token, key: scim-token }  # requis
        defaultRole: viewer
        orgSource: waeg
        roleMap: { "AI Platform Admins": admin }

Le jeton porteur est projeté sur les pods de la passerelle sous le nom WAEG_EE_SCIM_TOKEN : faire tourner le Secret constitue donc toute la procédure de rotation. Les points d'accès se trouvent sous /waeg/admin/v1/ee/scim/v2. Voir Approvisionnement SCIM pour tous les champs.

Datastores de la ChatUI : MongoDB et Meilisearch ​

MongoDB (le stockage des conversations) et Meilisearch (la recherche) alimentent la ChatUI et se configurent sous datastores.mongo / datastores.meilisearch — avec le même sélecteur mode: managed | external que les autres datastores. Ils ne sont provisionnés que lorsque la ChatUI est activée, et sont managed par défaut.

  • managed (par défaut) : le Stack provisionne et possède une MongoCluster / MeilisearchInstance et y raccorde la ChatUI. Dimensionnez via storageSize (Meilisearch honore aussi storageClass / resources).
  • external : aucune CR de datastore n'est provisionnée ; la ChatUI est raccordée à une instance gérée par l'utilisateur. Mongo nécessite connectionSecretRef (clé de Secret MONGO_URI, remplaçable via .key). Meilisearch nécessite host plus un connectionSecretRef contenant la clé maître (clé de Secret MEILI_MASTER_KEY).
yaml
spec:
  datastores:
    mongo:
      mode: managed
      storageSize: 10Gi
    meilisearch:
      mode: external
      host: https://search.example.com
      connectionSecretRef: { name: meili-master-key }   # clé MEILI_MASTER_KEY

Serveurs MCP (recherche web & outils) ​

chatUI.mcp câble des serveurs MCPServer dans l'interface LibreChat du Stack. Deux approches, combinables :

  • catalog — serveurs intégrés que le Stack provisionne et possède en tant qu'enfants MCPServer (un par clé) et câble dans la ChatUI. Première entrée : websearch (recherche web d'entreprise). Nécessite la licence bundled-mcp-catalog ; une entrée non autorisée est Refused et ignorée (l'interface démarre quand même).
  • refs — câble des CR MCPServer préexistants que vous créez vous-même (catalogue ou externe — p. ex. un serveur MCP interne au cluster auto-hébergé), dans n'importe quel namespace. Le Stack les référence sans posséder leur cycle de vie.
yaml
spec:
  chatUI:
    enabled: true
    mcp:
      catalog: [ websearch ]                 # le Stack crée + câble le MCPServer
      refs:
        - { name: my-internal-mcp }          # un MCPServer que vous gérez

Référencer un serveur MCP active automatiquement le point de terminaison Agents de LibreChat. Les enfants MCPServer du Stack apparaissent dans son arbre de progression et sont démantelés avec le Stack. Voir MCPServer pour la définition du serveur et la liste d'autorisation SSRF automatique.

Garde-fous (chemin de données) ​

gateway.guardrails câble des garde-fous de chemin de données Guardrail dans le Gateway du Stack. Deux méthodes combinables :

  • catalog — moteurs intégrés que le Stack provisionne et possède en tant qu'enfants Guardrail (un par clé) et câble dans le Gateway. Première entrée : pseudonymizer (pseudonymisation des PII). Nécessite la licence guardrail (Enterprise) ; une entrée non autorisée est Refused et ignorée (le Gateway démarre quand même, sans protection).
  • refs — câblent des CRs Guardrail préexistants que vous créez vous-même (catalog ou garde-fou HTTP externe), dans n'importe quel namespace. Le Stack les référence sans en posséder le cycle de vie.
yaml
spec:
  gateway:
    enabled: true
    guardrails:
      catalog: [ pseudonymizer ]             # le Stack crée + câble le Guardrail
      refs:
        - { name: my-guardrail }             # un Guardrail que vous gérez

Les garde-fous du catalogue comme externes sont sous licence et passent par le proxy de contrôle de licence injecté par l'opérateur (échoue en mode fermé si la licence expire). Les enfants Guardrail du Stack apparaissent dans son arbre de progression et sont démantelés avec le Stack. Voir Guardrail pour la définition complète.

Déboguer un garde-fou au sein d'un Stack ​

Définissez logLevel (et éventuellement blockedReason) sur le Stack, pas sur l'enfant :

yaml
spec:
  gateway:
    guardrails:
      catalog: [ pseudonymizer ]
      logLevel: debug                        # un enregistrement du proxy par requête
      blockedReason: "blocked by the Navique license gate"

Un Stack réécrit la spec curatée de chacun de ses enfants : avec la valeur par défaut driftPolicy: Enforce, un kubectl patch du logLevel sur le Guardrail enfant est donc annulé — et comme le Stack observe ses enfants Guardrail, le patch déclenche précisément la réconciliation qui le défait. (Avec driftPolicy: Adopt un patch manuel survit, mais seulement jusqu'à la prochaine modification du Stack, et cela désactive la correction de dérive pour tous les enfants.) Ces champs s'appliquent aux enfants catalog que le Stack possède ; les garde-fous câblés via refs vous appartiennent — définissez logLevel directement sur ces CR.

Les compteurs de décision du proxy ne demandent aucune activation — voir Diagnostic d'un appel de garde-fou en échec.

Sauvegardes et protection contre la suppression ​

Comme un Stack est le chemin emprunté par les utilisateurs non techniques, il traite les données avec état de manière défensive.

Les sauvegardes sont obligatoires pour les datastores avec état managés. Un Stack doit définir un backup activé pour chaque datastores.postgres, datastores.clickhouse et datastores.mongo managé (le même ensemble qui est verrouillé automatiquement) — sinon il est rejeté (Postgres à l'admission via CEL ; ClickHouse/Mongo au reconcile), de sorte que personne ne met en place un datastore sans sauvegardes. Redis (cache) et Meilisearch (index reconstructible) en sont exemptés. Le bloc a partout la même forme neutre (s3/azure/gcs + planification + rétention) et est propagé vers l'enfant managé ; Postgres utilise le PITR natif de CNPG, ClickHouse un CronJob clickhouse-backup, MongoDB un CronJob mongodump+rclone. Un datastore externe n'a besoin d'aucune sauvegarde ici — vous gérez cela vous-même. Définissez datastores.requireBackup: false pour ignorer l'exigence (utilisateurs avancés / CI).

Les datastores managés sont verrouillés automatiquement. Lorsque le Stack provisionne un PostgresCluster, un ClickHouseCluster ou un MongoCluster managé (qui contient l'historique des conversations de la ChatUI), il crée également un Lock dessus, de sorte qu'un kubectl delete accidentel est bloqué. Redis (un cache) et Meilisearch (un index de recherche reconstructible) ne sont jamais verrouillés.

  • Il s'agit d'une protection contre la suppression au niveau de la couche de données : la suppression du Stack reste bloquée tant que vous n'avez pas retiré ces Locks — les datastores (et leurs PVCs) ne sont jamais détruits par accident. Le Stack rapporte le ou les Locks bloquants dans son statut.
  • Le Stack crée chaque Lock une seule fois et n'en recrée jamais un que vous avez retiré — ainsi, pour supprimer un Stack protégé, il vous suffit de faire kubectl delete lock <name> d'abord, puis de supprimer le Stack. L'opérateur ne vous fera pas la course en remettant le Lock.
  • Définissez datastores.protectData: false pour ne pas créer les Locks (les Locks existants sont laissés intacts).
yaml
spec:
  datastores:
    postgres:
      storageSize: 20Gi
      backup:
        enabled: true
        provider: s3
        s3:
          destinationPath: s3://forge-backups/pg
          credentialsSecretRef: { name: pg-backup }
    clickhouse: { storageSize: 20Gi }
    redis: { storageSize: 5Gi }
    # protectData: false   # renoncer aux Locks automatiques (non recommandé)

Séparation par namespace ​

Par défaut, chaque composant se place dans le namespace du Stack. Chaque bloc de composant accepte optionnellement un namespace pour le placer ailleurs :

yaml
spec:
  gateway:   { namespace: forge-gateway }
  chatUI:    { namespace: forge-ui }
  observability: { type: langfuse }  # reste dans le namespace du Stack

Lorsqu'un composant déclare un namespace, le Stack :

  • crée le namespace s'il n'existe pas (et le laisse en place à la suppression) ;
  • place un SecretsManagement dans chaque namespace hébergeant une charge de travail, afin que le secretsRef de chaque composant se résolve localement ;
  • câble automatiquement les références cross-namespace (p. ex. une Gateway dans un namespace vers le Postgres/Langfuse dans un autre) — vous ne définissez toujours aucune référence à la main.

Comme les owner references Kubernetes ne peuvent pas franchir les namespaces, un enfant cross-namespace est suivi via le label core.navique.com/owned-by et retiré par le finalizer du Stack à la suppression (les enfants du même namespace conservent la cascade par owner reference). Les namespaces créés ne sont pas supprimés.

SSO / OIDC login ​

spec.sso configure l'authentification unique sur tout le Stack à partir d'un seul fournisseur d'identité. L'émetteur/fournisseur/scopes partagés s'appliquent à chaque composant activé, tandis que chaque composant obtient son propre client OAuth (les URLs de callback diffèrent) via une référence de client par composant. Un composant reçoit le SSO uniquement lorsqu'il est activé et que sa référence de client est définie, ce qui vous permet de déployer le SSO de manière sélective.

ChampDescription
issuerURLURL de base partagée de l'émetteur OIDC / de découverte
providerNameLibellé d'affichage partagé
scopesScopes demandés partagés
provider / tenantID / authorizationEndpoint / tokenEndpoint / userinfoEndpointVariante de fournisseur + endpoints réservés au Gateway (voir les notes SSO du Gateway)
gateway / chatUI / observabilityRéférences de client OAuth par composant ({ name, clientIDKey?, clientSecretKey? })
yaml
spec:
  sso:
    issuerURL: https://idp.example.com
    providerName: "Acme SSO"
    provider: generic-oidc
    authorizationEndpoint: https://idp.example.com/authorize
    tokenEndpoint: https://idp.example.com/token
    userinfoEndpoint: https://idp.example.com/userinfo
    gateway:  { name: gateway-oidc }
    chatUI:   { name: chatui-oidc }
    observability: { name: langfuse-oidc }

C'est ce qui alimente le SSO en libre-service depuis l'assistant de déploiement de la console de gestion. Les détails par composant (les variables d'environnement que reçoit chaque application, les licences) figurent sur les pages Gateway, ChatUI et Observability.

Mesh ​

spec.mesh.mode inscrit les namespaces des composants du Stack au ServiceMesh du cluster (mTLS + isolation). Par défaut auto (rejoindre quand un ServiceMesh prêt existe, sinon no-op) ; enabled en exige un ; disabled ne rejoint jamais. Le Stack se contente d'étiqueter ses namespaces — le singleton ServiceMesh réalise l'inscription — de sorte qu'un mesh activé plus tard rejoint les Stacks existants sans redéploiement.

Licences ​

Stack requiert la fonctionnalité managed-deployment et un quota d'instances stacks dans la License. Sans eux, composez la plateforme avec les resources granulaires, qui sont toujours disponibles (sous réserve de leurs propres quotas dans l'édition Community).

Voir Éditions et licences.

Cœur open source sous AGPL-3.0. Les composants Enterprise sont propriétaires et soumis à licence.