Scrydon

Modes de routage — Sous-chemin et sous-domaine

Choisissez comment les applications Scrydon sont exposées en externe. Le mode sous-chemin (par défaut) place toutes les applications sous un seul nom d'hôte avec un préfixe de chemin ; le mode sous-domaine place chaque application sur son propre nom d'hôte. Le même binaire compilé gère les deux modes — le choix se fait dans les valeurs Helm.

Scrydon livre chaque application destinée aux clients (Cortex, Agentic, Analytics, Platform) ainsi que les API de support (Better-Auth, api-ontology, api-table) et l'éditeur de notebooks Marimo comme des processus distincts. La façon dont ils sont exposés aux navigateurs est un choix au moment du déploiement, contrôlé par une seule valeur Helm : routing.mode.

Sous-chemin (subpath, par défaut)Sous-domaine (subdomain)
Exemples d'URLapp.customer.com/cortex
app.customer.com/agentic
app.customer.com/api/auth
cortex.customer.com
agentic.customer.com
auth.customer.com
Enregistrements DNS1 enregistrement A1 wildcard ou 5+ enregistrements A
Certificats TLS1 certificat d'hôte1 wildcard ou 5+ certificats d'hôte
Objets Ingress2ingress-frontdoor + ingress-marimo-sidecar (séparés pour que le middleware forward-auth de marimo ne se propage pas aux SPA)Un par application (5+, marimo inclus)
Portée des cookiesLimitée à l'hôte (plus forte)Domain=.customer.com (inter-sous-domaine)
Surface CORSUne seule origineUne origine par sous-domaine
Idéal pourAuto-hébergement clientSaaS multi-produits où chaque application nécessite un DNS / TLS / SSO indépendant

La recommandation pour tout cluster déployé par un client est de conserver la valeur par défaut et de rester en mode sous-chemin, sauf s'il existe une raison spécifique d'en changer (stratégie de domaine personnalisé par application, royaumes SSO séparés, etc.).

Comment ça fonctionne

Un seul binaire compilé par application gère les deux modes. Le préfixe de chemin est injecté à l'exécution via trois mécanismes :

  1. values.yaml Helm → ConfigMap. Le chart résout le préfixe de chemin par application ("" en mode sous-domaine, /cortex etc. en mode sous-chemin) et l'expose comme variable d'environnement BASE_PATH dans le ConfigMap de chaque application. Les liens inter-applications sont composés par le chart de sorte que les variables d'environnement PUBLIC_*_APP_URL soient déjà correctes dans les deux modes.
  2. Démarrage de l'application. L'application lit BASE_PATH, monte sa table d'actifs statiques sous le préfixe et réécrit les réponses HTML du rendu côté serveur (SSR) pour que les URL d'actifs absolues incluent le préfixe. Un petit <script>window.__SCRYDON_BASE_PATH__="…"</script> est injecté pour que le code côté client reste synchronisé.
  3. TanStack Router. Chaque application transmet le préfixe résolu en tant que basepath à createTanStackRouter. Tous les <Link>, navigations et correspondances de routes respectent automatiquement le préfixe.

Le même mécanisme s'applique aux services API (Better-Auth, api-ontology, api-table) — ils lisent BASE_PATH et montent leurs racines sous ce préfixe.

Pourquoi ne pas simplement réécrire les chemins dans l'ingress ?

La suppression du préfixe dans l'ingress (/cortex/foo/foo avant le pod) est le raccourci qui semble évident, mais ça ne fonctionne pas pour le type de SPA que nous émettons. Le HTML SSR contient des URL d'actifs absolues (<script src="/_build/assets/abc123.js">). Lorsque le navigateur est sur /cortex/dashboard, il récupère /_build/assets/abc123.js directement — sans préfixe, sans moyen pour l'ingress de le rerouter vers le bon pod. Les noms de fichiers d'actifs avec hash changent aussi à chaque compilation, ce qui rend impossible à une réécriture par regex statique de distinguer quelle application doit servir un bundle donné.

Scrydon adopte l'approche à l'exécution pour que le même binaire fonctionne dans les deux modes sans recompilation — la même approche utilisée par Grafana (GF_SERVER_ROOT_URL), GitLab (URL racine relative) et la plupart des consoles de fournisseurs cloud.

Démarrage rapide en mode sous-chemin (recommandé)

# values.customer.yaml
routing:
  mode: subpath
  host: app.example.com
  # Chemins par défaut — à remplacer uniquement si vous avez besoin d'une organisation différente.
  # paths:
  #   cortex: /cortex
  #   agentic: /agentic
  #   analytics: /analytics
  #   platform: /platform
  #   apiAuth: /api/auth
  #   apiOntology: /api/ontology
  #   apiTable: /api/table
  #   agenticRealtime: /agentic/realtime
  #   marimo: /marimo

DNS : un enregistrement A pour app.example.com. TLS : un certificat (cert-manager + Let's Encrypt par défaut). Ingress : ingress-frontdoor (une règle de chemin par SPA + API) plus ingress-marimo-sidecar (chemin /marimo, réutilise le même secret TLS — maintenu comme Ingress séparé pour que son middleware forward-auth ne s'applique pas aux SPA).

Démarrage rapide en mode sous-domaine

# values.customer.yaml
routing:
  mode: subdomain

auth:
  publicUrl: https://auth.example.com
  ingress: { hostname: auth.example.com }
  corsOrigins:
    - https://app.example.com
    - https://cortex.example.com
    - https://agentic.example.com
    - https://ws-agentic.example.com
    - https://analytics.example.com

platform:
  publicUrl: https://app.example.com
  ingress: { hostname: app.example.com }

cortex:
  publicUrl: https://cortex.example.com
  ingress: { hostname: cortex.example.com }

agentic:
  publicUrl: https://agentic.example.com
  publicSocketUrl: https://ws-agentic.example.com
  app: { ingress: { hostname: agentic.example.com } }
  realtime:
    ingress:
      hostname: ws-agentic.example.com
      annotations:
        # Requis pour que le WebSocket realtime reste sur le même pod pour toute la
        # durée d'une session. Remplacez les clés spécifiques à Traefik par les
        # équivalents de votre contrôleur d'ingress si vous n'utilisez pas Traefik.
        traefik.ingress.kubernetes.io/service.sticky.cookie: "true"
        traefik.ingress.kubernetes.io/service.sticky.cookie.name: scrydon_realtime_affinity
        traefik.ingress.kubernetes.io/service.sticky.cookie.secure: "true"
        traefik.ingress.kubernetes.io/service.sticky.cookie.httponly: "true"

analytics:
  publicUrl: https://analytics.example.com
  ingress: { hostname: analytics.example.com }
  marimoSidecar:
    ingress:
      hostname: marimo.example.com   # hôte propre, certificat TLS propre

DNS : un enregistrement A par sous-domaine (ou un wildcard). TLS : un certificat par hôte (ou un certificat wildcard). Ingress : un par application — ingress-cortex, ingress-auth, ingress-marimo-sidecar, etc.

Implications DNS + TLS

Mode sous-chemin (hôte unique)

app.example.com         A   <ingress LB IP>

Requête cert-manager : un Certificate pour app.example.com, émis par le ClusterIssuer letsencrypt-prod. Aucun wildcard nécessaire. Le chart configure automatiquement l'Ingress front-door lorsque ingress.tls.enabled: true.

Mode sous-domaine (hôtes par application)

app.example.com         A   <ingress LB IP>
cortex.example.com      A   <ingress LB IP>
agentic.example.com     A   <ingress LB IP>
ws-agentic.example.com  A   <ingress LB IP>
analytics.example.com   A   <ingress LB IP>
auth.example.com        A   <ingress LB IP>
marimo.example.com      A   <ingress LB IP>   # uniquement si marimoSidecar.enabled

Chaque Ingress par application demande son propre Certificate. Si votre fournisseur DNS le supporte, un certificat wildcard *.example.com réduit cela à une seule cible de rotation. Les cookies inter-sous-domaines dépendent du domaine enregistrable correspondant — ne pas mélanger le mode sous-domaine avec plusieurs domaines enregistrables non apparentés.

Comportement des cookies et de CORS

Le chart configure la portée des cookies selon routing.mode :

  • Sous-chemin : les cookies sont limités à l'hôte (sans attribut Domain=). Une seule origine pour l'ensemble du produit, donc CORS se réduit à une seule entrée de liste d'autorisation plus les URL des Services internes du cluster.
  • Sous-domaine : les cookies utilisent Domain=<domaine-enregistrable> pour que les sessions survivent à la navigation inter-sous-domaines. La liste d'autorisation CORS énumère chaque sous-domaine par application.

En mode sous-chemin, vous n'avez pas besoin de maintenir les tableaux auth.corsOrigins — le chart compose la liste correcte automatiquement.

Éditeur de notebooks Marimo

L'éditeur de notebooks Marimo est un processus Python livré derrière son propre Ingress (ingress-marimo-sidecar). Sa configuration varie selon le mode de routage :

Sous-cheminSous-domaine
Hôterouting.host (partagé avec le front-door)analytics.marimoSidecar.ingress.hostname
Chemin/marimo (par défaut — voir routing.paths.marimo)/
Secret TLStls-frontdoor (partagé avec le front-door — évite deux certificats en compétition pour le même hôte)tls-marimo-sidecar (dédié)

Pour désactiver marimo entièrement, définissez analytics.marimoSidecar.enabled: false.

Préparation DNS / TLS côté client :

  • Sous-chemin : rien de supplémentaire — l'enregistrement A app.example.com et le certificat tls-frontdoor couvrent déjà /marimo.
  • Sous-domaine : ajoutez un enregistrement A pour marimo.example.com (ou incluez-le dans votre wildcard) et laissez cert-manager demander automatiquement tls-marimo-sidecar.

Changer de mode sur un déploiement en production

Les deux modes sont pleinement pris en charge — vous pouvez basculer en changeant une valeur et en exécutant helm upgrade. Les étapes :

  1. Provisionnez les nouveaux enregistrements DNS et certificats TLS pour le mode cible. Sous-chemin → 1 enregistrement. Sous-domaine → enregistrements par application.

  2. Mettez à jour values.customer.yaml : changez routing.mode et (pour le sous-chemin) définissez routing.host, ou (pour le sous-domaine) définissez publicUrl + ingress.hostname pour chaque application.

  3. Appliquez :

    helm upgrade scrydon oci://scrydonops.azurecr.io/scrydon/charts/scrydon \
      --version "${CURRENT_VERSION}" \
      --namespace scrydon-platform \
      -f values.customer.yaml \
      --wait
  4. Vérifiez :

    # Sous-chemin : ingress-frontdoor + ingress-marimo-sidecar
    kubectl -n scrydon-platform get ingress
    # Sous-domaine : un Ingress par application
    kubectl get ingress -A | grep ingress-
    # Les pods redémarrent automatiquement car BASE_PATH a changé dans le ConfigMap
    kubectl -n scrydon-platform get pods
  5. Basculez le DNS si vous l'avez modifié. Les anciennes sessions avec cookie sous l'hôte précédent seront ignorées — les utilisateurs seront invités à se reconnecter une fois.

Un retour arrière consiste simplement à remettre routing.mode à sa valeur précédente et à ré-exécuter helm upgrade ; les templates d'Ingress par application sont conservés dans le chart pour les deux modes.

Déploiements multi-espace de noms

L'Ingress front-door suppose que le Service de chaque application a été déployé dans le même espace de noms que le front-door (la valeur par défaut du chart). Les clients utilisant des topologies multi-espaces de noms — par exemple analytics dans son propre espace de noms, agentic dans un autre — doivent soit :

  • Aplatir le déploiement vers un espace de noms unique (recommandé pour les installations plus petites), soit
  • Passer en mode sous-domaine, qui émet un Ingress par application dans l'espace de noms propre à chaque application.

Les objets Ingress Kubernetes ne peuvent pas référencer des Services dans d'autres espaces de noms, de sorte qu'un vrai mode sous-chemin multi-espace de noms nécessiterait des Services ExternalName ou des contrôleurs d'ingress par espace de noms — hors du périmètre du chart par défaut.

Sur cette page

Sur cette page