Helm
Référence complète du chart Helm Scrydon — une installation condensée ainsi que toutes les valeurs exposées par le chart, avec leur rôle, leur justification et leur configuration.
Voici la référence de configuration du chart Helm Scrydon. Ce document présente une installation condensée, puis les groupes de valeurs importants pour l'exploitation — ce que fait chaque clé, pourquoi la modifier et comment procéder. Si vous souhaitez simplement démarrer un cluster le plus rapidement possible, commencez par la page Localisation (On-Premise, Azure (AKS), Air-Gapped) et revenez ici pour les options.
Pour un cluster air-gapped (sans internet sortant), consultez le Déploiement Air-Gapped — le même chart est livré dans un paquet Zarf.
Fonctionnement de la configuration
Trois couches, de la priorité la plus basse à la plus haute :
- Valeurs par défaut du chart — le chart fournit des valeurs de production sensées pour tout. La liste de référence est le
values.yamldu chart lui-même (voir Inspecter le chart localement). - Votre
values.customer.yaml— le fichier que vous passez avec-f. Ne surchargez que ce dont vous avez besoin ; tout le reste hérite de la valeur par défaut. - Flags
--set— priorité maximale, utile pour injecter des secrets au moment de l'installation depuis un gestionnaire de secrets.
helm install scrydon oci://scrydonops.azurecr.io/scrydon/charts/scrydon \
--version <version> -n scrydon-platform \
-f values.customer.yaml \
--set apiTable.secrets.STARROCKS_PASSWORD="$(vault kv get -field=password kv/scrydon/starrocks)"Les secrets vivent dans votre fichier de valeurs.
values.customer.yamlethelm get values <release>reproduisent toutes les valeurs fournies par l'utilisateur. Ne placez pas ce fichier dans un dépôt de code source, ou gérez-le via Sealed Secrets / SOPS / External Secrets Operator, et restreignez le RBAC du cluster sur le Secret de la release.
Inspecter le chart localement
Le chart est un artefact OCI dans scrydonops.azurecr.io — il n'existe pas de miroir Git public. Téléchargez-le pour lire chaque template et le values.yaml par défaut complet :
helm pull oci://scrydonops.azurecr.io/scrydon/charts/scrydon \
--version <version> --untar
less scrydon/values.yaml # the authoritative default for every key belowValider votre configuration
Le chart embarque un schéma de valeurs (values.schema.json). Il rejette les
clés inconnues ou mal orthographiées au niveau racine et dans les groupes
stricts à haut risque tels que routing, gateway, license, les namespaces,
Pod Security et NetworkPolicy. Certains blocs applicatifs — notamment les clés
imbriquées de runtimePlane dans les charts actuels — restent permissifs : la
validation du schéma est nécessaire, mais pas suffisante. Une faute comme
routing.mdoe échoue immédiatement :
Error: values don't meet the specifications of the schema(s) in the following chart(s):
scrydon:
- routing: Additional property mdoe is not allowedAvant une installation ou une mise à niveau, exécutez un contrôle préalable avec vos valeurs et votre version de Kubernetes :
# 1. Schema + lint — catches typo'd keys and structural mistakes
helm lint ./scrydon -f your-values.yaml
# 2. Render and validate against your Kubernetes version
# (kubeconform: https://github.com/yannh/kubeconform)
helm template scrydon ./scrydon -f your-values.yaml \
| kubeconform --strict --ignore-missing-schemas \
--kubernetes-version "$(kubectl version -o json | jq -r '.serverVersion.gitVersion' | tr -d v)"
# 3. Dry-run the install against the live cluster (server-side validation)
helm install scrydon ./scrydon -f your-values.yaml --dry-run=serverLe chart exige Kubernetes 1.28 ou ultérieur (kubeVersion: ">=1.28.0-0") — helm install refuse les clusters plus anciens avec une
erreur claire plutôt que d'échouer en cours de déploiement.
Installation rapide
Le minimum pour obtenir un cluster opérationnel. Chaque étape est développée avec des notes spécifiques à l'environnement sur les pages Localisation.
# 1. Log in to the registry (username = ACR token name from your account team)
helm registry login scrydonops.azurecr.io --username <acr-token-name>
# 2. Create the release namespace + an image-pull secret in it.
# The chart defaults every service to scrydon-platform; split namespaces
# are opt-in via namespaces.* (create the secret in each one you target).
kubectl create namespace scrydon-platform 2>/dev/null || true
kubectl create secret docker-registry scrydon-registry --namespace scrydon-platform \
--docker-server=scrydonops.azurecr.io \
--docker-username=<acr-token-name> --docker-password=<acr-token-password># 3. values.customer.yaml — the entire minimal install.
global:
imageRegistry: scrydonops.azurecr.io # pull images from the ACR you logged into
imagePullSecrets:
- scrydon-registry
storageClass: <your-storage-class> # cloud default class name, or your on-prem provisioner
routing:
host: app.example.com # the hostname your DNS points at
gateway:
tls:
enabled: true # browser reaches Scrydon over HTTPS — see Gateway below
infra:
db:
credentials:
password: REPLACE-WITH-DB-PASSWORD # openssl rand -hex 16
auth:
secrets:
AUTH_SECRET: REPLACE-WITH-AUTH-SECRET # openssl rand -hex 32
apiTable:
secrets:
STARROCKS_PASSWORD: REPLACE-WITH-STARROCKS-PW # openssl rand -hex 24# 4. Install
helm install scrydon oci://scrydonops.azurecr.io/scrydon/charts/scrydon \
--version <version> --namespace scrydon-platform \
-f values.customer.yaml --wait --wait-for-jobsLancer l'assistant de configuration
Ouvrez https://app.example.com/platform/setup (ou /setup si vous avez monté platform à la racine). Six étapes :
| # | Étape | Ce qu'elle fait |
|---|---|---|
| 1 | Licence | Collez ou déposez le bundle JSON { jwt, publicKey }. L'assistant contrôle l'expiration et affiche le niveau / CPU / RAM / VRAM. À l'étape suivante, le serveur vérifie le JWT à l'aide des clés de signature Scrydon intégrées à la version et l'enregistre dans platform_config ; une licence refusée n'est pas enregistrée. Le format du bundle est affiché dans le Vérificateur de licence. Les fichiers .jwt seuls sont rejetés. |
| 2 | Compte administrateur | Créez le premier administrateur (e-mail + mot de passe). À la validation, la licence est persistée et l'utilisateur administrateur créé. |
| 3 | Organisation | Nommez votre organisation — le tenant racine. |
| 4 | Stockage | Pointez l'organisation vers un stockage objet compatible S3 ou Azure (endpoint, bucket/conteneur, identifiants), ou passez l'étape pour rester sur le stockage de fichiers local. Les identifiants sont chiffrés ; les réglages non secrets vont dans storage_config. Configurable plus tard sur https://<host>/platform/settings/platform/storage. |
| 5 | Configurez la livraison (SMTP, par défaut ; Resend ; SendGrid ; ou ignorer — configurable ultérieurement sous Paramètres → Plateforme → E-mail). Sans fournisseur réel, les nouvelles inscriptions ignorent la vérification par e-mail ; une fois un fournisseur configuré, elles reçoivent un OTP. | |
| 6 | Terminer | Marque setup_completed = true et redirige vers l'accueil de la plateforme. |
Passer l'étape Stockage laisse l'organisation sur le stockage de fichiers local. Les tables gérées d'Analytics sont exclusivement Iceberg et stockent les données dans le stockage objet propre à l'organisation : Analytics reste donc derrière un avis « Stockage objet requis » tant qu'un stockage compatible S3 ou Azure n'est pas configuré. Tout le reste fonctionne normalement.
Pré-injecter la licence
Évitez l'étape licence de l'assistant en donnant au chart le champ jwt de votre fichier de licence lors de la première installation. La valeur est lue une seule fois pour initialiser la base de données ; ensuite la licence vit dans platform_config et est gérée depuis l'interface :
auth:
secrets:
AUTH_SECRET: REPLACE-WITH-AUTH-SECRET
LICENSE: "eyJhbGciOiJNTC1EU0EtNjUi…" # the file's `jwt` fieldLorsqu'elle est définie, l'étape Licence de l'assistant s'ouvre déjà vérifiée. Il n'y a pas de valeur de clé publique : auth.secrets.LICENSE_PUBLIC_KEY est ignorée en production, et la mise à jour supprime toute ligne de clé publique qu'elle avait stockée.
Référence de configuration
Chaque groupe ci-dessous correspond à une clé de premier niveau dans le values.yaml du chart, dans l'ordre du fichier. Les valeurs par défaut indiquées sont celles du chart ; ne surchargez que ce dont vous avez besoin.
global — registre, images, stockage
Paramètres à l'échelle du cluster, hérités par chaque service.
| Clé | Défaut | Rôle / justification |
|---|---|---|
global.imageRegistry | "" | Racine du registre d'images de conteneurs (ex. scrydonops.azurecr.io, un Harbor interne, un host:port de homelab). Vide génère des références non préfixées scrydon/<name>:<tag>. À définir par environnement. Ne couvre pas le plan de contrôle Dapr — voir dapr.global.registry ci-dessous. |
dapr.global.registry | ghcr.io/dapr | Registre des cinq images du plan de contrôle Dapr. Une option distincte, car elles proviennent du sous-chart Dapr, que global.imageRegistry ne peut pas atteindre (les valeurs d'un sous-chart Helm sont du YAML statique). Sur un cluster à registre privé ou air-gapped, vous devez définir les deux : un injecteur bloqué en ImagePullBackOff fait échouer l'admission de chaque pod Scrydon (webhookFailurePolicy: Fail), ce qui ressemble à un blocage sans rapport. helm install émet un avertissement lorsqu'une seule des deux est définie. |
<image>.registry | "" | Surcharge par image de global.imageRegistry, sur chaque bloc d'image tierce (global.images.busybox, infra.db.image, infra.starrocks.image, infra.seaweedfs.image, infra.lakekeeper.image, opa.image, eventBackbone.valkey.image). Vide hérite de la valeur globale ; définissez un hôte explicite pour récupérer une image depuis un autre emplacement. Nécessaire lorsque votre miroir ne contient pas toutes les images amont sous une même portée. |
global.imagePullSecrets | [] | Noms des secrets d'extraction ajoutés à chaque pod. Indiquer le secret créé à l'étape 2. |
global.imagePullPolicy | Always | Politique standard de récupération Kubernetes. |
global.requireExplicitSecrets | false | Faire échouer le rendu au lieu de générer un secret qui ne peut pas être conservé. Définissez true pour le GitOps et le rendu hors ligne des manifestes — voir Rendu sans cluster actif. |
global.storageClass | "" | Le provisionneur pour chaque PVC. Pas de valeur cloud par défaut — définir la classe de votre cloud (managed-csi, gp3, standard-rwo) ou votre provisionneur on-prem (ceph-rbd, vsphere-csi, local-path). |
global.nfs.enabled | false | Utiliser des PV statiques NFS à la place du provisionnement dynamique. Pour les clusters homelab / NFS — définir aussi server + basePath. |
global.scheduling.spreadAcrossNodes | true | Attacher une anti-affinité de pods souple à chaque charge de travail durable (les applications et le socle infra gourmand en mémoire : Postgres, StarRocks, SeaweedFS, Valkey) afin qu'elles préfèrent des nœuds distincts. Sans cela, l'ordonnanceur peut empiler plusieurs pods de plusieurs Gio sur un même nœud, que le kubelet évince ensuite sous pression mémoire. « Souple » signifie que l'ordonnancement n'est jamais bloqué : les clusters mono-nœud et de petite taille démarrent donc normalement — à laisser activé. Passer à false uniquement pour regrouper délibérément sur un seul nœud. |
global.azure.enabled | false | Mode Azure Marketplace : les images sont résolues depuis MCR via global.azure.images.* et les composants tiers du data-plane (StarRocks/SeaweedFS) sont désactivés automatiquement. Défini par le package Marketplace, pas manuellement. |
global:
imageRegistry: scrydonops.azurecr.io
imagePullSecrets:
- name: scrydon-registry
storageClass: managed-csinamespaces — placement des charges de travail
Chaque service cible par défaut scrydon-platform. Surchargez par service pour un isolement multi-namespace ; le chart aligne automatiquement les politiques ACL Dapr et le RBAC de lecture des secrets.
namespaces:
infra: scrydon-infra
platform: scrydon-platform
agentic: scrydon-agentic
analytics: scrydon-platform
cortex: scrydon-platformgateway — exposition et schéma TLS
La périphérie repose sur la Gateway API de Kubernetes (Gateway + HTTPRoute), et non
sur Ingress. Ingress est gelée : elle reste GA, conserve ses garanties de stabilité et
Kubernetes ne prévoit pas de la supprimer — mais elle ne reçoit plus aucun développement, et
Kubernetes recommande la Gateway API à sa place. Le chart suit cette recommandation.
Le chart génère une Gateway nommée gateway-frontdoor dans l'espace de noms de la
plateforme, et une HTTPRoute par application activée dans l'espace de noms de cette
application, rattachée à l'unique Gateway par-delà les espaces de noms.
La Gateway API n'est pas présente dans un cluster standard. Avant l'installation, le cluster
a besoin des CRD gateway.networking.k8s.io et d'une GatewayClass dont le nom correspond
à gateway.className. Définissez traefik.enabled: true pour que le chart installe une
release Traefik qui fournit les deux, ou pointez gateway.className vers une classe déjà
exploitée par votre équipe plateforme. Voir Prérequis Kubernetes.
| Clé | Défaut | Rôle / justification |
|---|---|---|
gateway.enabled | true | Générer la Gateway et ses HTTPRoutes. Désactivez si vous placez votre propre périphérie devant le cluster. |
gateway.className | traefik | Le nom de la GatewayClass (et non d'une IngressClass). N'importe quelle implémentation conforme achemine le trafic du chart ; le seul contrôle non portable est gateway.publicAuthRateLimit ci-dessous. |
gateway.listenerPorts.http | 8000 | Le port sur lequel votre contrôleur écoute, et non le port public — voir Ports des listeners. |
gateway.listenerPorts.https | 8443 | Idem, pour le listener HTTPS. |
gateway.tls.enabled | true | Critique. Signifie « Scrydon est-il accessible via HTTPS par le navigateur ? » — pilote le schéma des URL publiques, les origines CORS, les cookies sécurisés et l'origine de callback Better-Auth, et décide si un listener HTTPS et la route de redirection sont générés. Par défaut true (sécurisé par défaut), y compris derrière un équilibreur de charge qui termine le TLS (App Gateway / ALB) et transmet du HTTP brut à Traefik — le navigateur reste en HTTPS, donc laisser true. Mettre à false uniquement pour les déploiements HTTP seul (dev local / smoke kind). Mettre false sur une installation frontée HTTPS casse silencieusement la connexion (Mixed Content + origine de callback incompatible). |
gateway.tls.existingSecret | "" | Apporter votre propre certificat au lieu des noms tls-frontdoor / tls-<app> du chart. Obligatoire pour les installations air-gap et on-prem avec un certificat d'AC d'entreprise. Un seul Secret, un seul espace de noms : la Gateway possède tous les listeners, le Secret n'est donc lu que depuis l'espace de noms de la plateforme — même en installation répartie. |
gateway.tls.certManager.enabled | true | Ajouter cert-manager.io/cluster-issuer sur la Gateway (une seule annotation pour toute la porte d'entrée ; cert-manager regroupe les listeners par Secret de certificat). Nécessite la prise en charge Gateway API de cert-manager — config.enableGatewayAPI=true, voir Prérequis TLS. Définir false lorsque vous fournissez vous-même le certificat et que cert-manager est installé — sinon il peut laisser une commande ACME en attente qui entre en conflit avec votre véritable certificat. |
gateway.tls.clusterIssuer | letsencrypt-prod | Émetteur utilisé lorsque certManager.enabled est activé. |
gateway.publicAuthRateLimit.enabled | false | Limitation de débit grossière en périphérie publique sur la règle routing.paths.apiAuth, appliquée avant que la requête n'atteigne api-platform et distincte des limites par endpoint de Better Auth. Traefik uniquement — la limitation de débit ne fait pas partie du canal standard de la Gateway API, elle est donc attachée comme Middleware Traefik via un filtre ExtensionRef et le rendu échoue si gateway.className vaut autre chose que traefik. |
gateway.publicAuthRateLimit.average / .period / .burst | 10 / 1m / 10 | Le seau lui-même. |
gateway.annotations | {} | Annotations fusionnées sur la Gateway. Le point d'accroche des réglages propres à l'implémentation (ajustements d'équilibreur cloud, références de frontend). Les routes n'en ont besoin d'aucune. |
traefik.enabled | false | Installer Traefik comme dépendance intégrée du chart, avec le provider Gateway activé, sa propre Gateway par défaut désactivée et la GatewayClass traefik publiée. Désactivé par défaut : un cluster disposant déjà d'une implémentation conforme doit la conserver et se contenter de définir gateway.className. |
Trois contrôles qui étaient auparavant des annotations propres au contrôleur relèvent désormais du cœur de la Gateway API et sont générés sans condition ; ils existent donc sur toute implémentation conforme et non plus seulement sur Traefik :
- Le retrait des en-têtes Dapr / on-behalf-of. Chaque règle de route qui transmet porte un filtre
RequestHeaderModifierqui supprimedapr-caller-app-id,dapr-api-token,x-scrydon-self-call, les en-têtes d'identitéx-on-behalf-of-*etx-scrydon-storage-scopedes requêtes externes. Il n'y a plus ni branche par classe ni mode pouvant silencieusement ne rien produire :ingress.stripDaprHeaders.*— et l'avertissement d'installation qui l'accompagnait — disparaît sans remplacement. - La redirection HTTP → HTTPS. Un filtre
RequestRedirectsur le listener HTTP, généré dès quegateway.tls.enabledest actif.ingress.middleware.forceHttps.*disparaît sans remplacement. - La précédence des chemins. La spécification impose le préfixe correspondant le plus long
d'abord, sur toutes les routes d'un listener : l'ordre de déclaration n'a donc plus
d'importance et la règle racine
/est simplement la moins prioritaire.
Les chemins internes des services ne sont pas publiés. Sur chaque nom d'hôte, /api/internal
sous la racine de chaque application (/api/internal, /platform/api/internal,
/agentic/api/internal, etc.) correspond à une règle sans backend : la passerelle répond 500
et ne transmet jamais la requête ; ces routes ne sont joignables qu'à l'intérieur du maillage de
services. C'est aussi du cœur de Gateway API.
Les choix de certificats pour Let's Encrypt, les domaines exclusivement privés, l'ACME interne et les certificats d'entreprise statiques sont traités dans Certificats TLS.
Ports des listeners : 8000 / 8443, et non 80 / 443
gateway.listenerPorts.* est le port sur lequel votre contrôleur écoute, pas celui auquel
vos utilisateurs se connectent. C'est la seule valeur propre à l'implémentation dans toute la
périphérie.
Traefik associe un listener de Gateway à l'un de ses entryPoints par le port, et ces
entryPoints écoutent sur :8000 (web) et :8443 (websecure) dans le conteneur tandis que son
Service publie 80/443. Un listener déclaré sur le port 80 est rejeté d'emblée (vérifié sur
Traefik v3.6.10, le 2026-09-12) :
Accepted=False reason=PortUnavailable
"Cannot find entryPoint for Gateway: no matching entryPoint for port 80 and protocol HTTP"Une implémentation managée qui écoute sur le port public — Application Gateway for
Containers, un ALB cloud — attend au contraire 80 / 443 ici :
gateway:
className: <your-gatewayclass>
listenerPorts:
http: 80
https: 443Autres implémentations Gateway API
Définissez gateway.className sur votre GatewayClass et le routage fonctionne sans
changement : le chart n'émet que des ressources Gateway et HTTPRoute du cœur de la
spécification, sans aucune annotation de contrôleur sur les routes. Deux points à vérifier
avant de changer :
| Contrôle | Portable ? |
|---|---|
Retrait des en-têtes Dapr / on-behalf-of (RequestHeaderModifier) | Cœur. Fonctionne sur toute implémentation conforme. |
Redirection HTTP → HTTPS (RequestRedirect) | Cœur. |
| Précédence des chemins (préfixe le plus long) | Cœur, imposé par la spécification. |
Terminaison TLS via les certificateRefs du listener | Cœur. |
gateway.listenerPorts.* | Propre à l'implémentation — voir Ports des listeners. |
gateway.publicAuthRateLimit | Traefik uniquement. Attaché comme Middleware Traefik via un filtre ExtensionRef ; le rendu échoue sur toute autre classe. Laissez la valeur à false et appliquez la limite sur votre propre périphérie. |
Tout ce que le chart n'exprime pas — limites de taille de corps de requête, délais de lecture,
comportement d'inactivité WebSocket sur la route routing.paths.agenticRealtime — se configure
sur votre implémentation elle-même et non via ce chart ; gateway.annotations est le seul point
d'accroche d'annotations et il s'applique à la Gateway, pas aux routes. Dimensionnez la limite
de taille de corps au moins à hauteur du plafond d'upload de 100 Mo de la plateforme.
Une remarque portable : les implémentations dont la sonde de santé du backend vise / par
défaut reçoivent une chaîne de redirections des applications SSR. Pointez la sonde vers le
/api/healthz de chaque application, avec le mécanisme de health check fourni par votre
implémentation.
ingress-nginx est retiré — le projet a été archivé le 2026-03-24 et ne publie plus
aucune version, correction de bug ou correctif de sécurité. Ne l'installez pas, et ne pointez
pas gateway.className vers une classe Ingress nginx : le chart ne génère plus du tout
d'objets Ingress.
routing — sous-chemin vs sous-domaine
Choisit comment les applications sont exposées. Discussion complète : Modes de routage.
| Clé | Défaut | Rôle / justification |
|---|---|---|
routing.mode | subpath | subpath place toutes les applications sous un même nom d'hôte avec un préfixe de chemin (un enregistrement DNS, un certificat — recommandé pour l'auto-hébergement). subdomain place chaque application sur son propre nom d'hôte (DNS wildcard + certificat — utilisé par notre SaaS). |
routing.host | — | Le nom d'hôte unique vers lequel pointe votre DNS, ex. app.example.com. |
routing.paths.* | /cortex, /agentic, … | Préfixes de chemin par application en mode sous-chemin. Mettre une valeur à "" pour monter cette application à la racine. Les applications consomment le préfixe résolu via BASE_PATH. |
routing.annotations a disparu. Cette clé n'existait que parce qu'une installation en
sous-chemin comportait exactement un Ingress et aucun autre moyen de l'annoter ; les deux modes
de routage génèrent désormais une seule Gateway, et gateway.annotations est cet endroit —
voir Autres implémentations Gateway API.
routing:
mode: subpath
host: app.example.com
paths:
cortex: /scrydon/cortex # customize prefixes if needed
platform: /scrydon/platformdapr — maillage de services et identité
Les appels de service à service utilisent Dapr avec mTLS ; les politiques ACL du chart sont basées sur le domaine de confiance SPIFFE.
| Clé | Défaut | Rôle / justification |
|---|---|---|
dapr.enabled | true | Injection de sidecar + composants crypto + comptes de service. |
dapr.reserveSidecarPorts | true | Réserve les ports gRPC du sidecar (50001-50002) dans la plage de ports éphémères de chaque pod Dapr, via le sysctl sûr net.ipv4.ip_local_reserved_ports. Sans cela, une connexion sortante de l'application peut prendre l'un de ces ports en premier, et daprd redémarre en boucle avec bind: address already in use. Ne désactivez que si un moteur de politiques refuse les sysctls de pod. |
dapr.installControlPlane | true | Installer le plan de contrôle Dapr comme sous-chart dans le namespace de la release. Mettre false si Dapr est déjà installé à l'échelle du cluster. |
dapr.controlPlaneNamespace | "" | Quand installControlPlane: false et que Dapr est ailleurs (ex. dapr-system), le définir sur ce namespace. Il est alors obligatoire, pas optionnel : le chart y pointe son binding de lecture des secrets, le RBAC de l'opérateur Dapr et la politique d'egress de marimo-document ; laissé vide, tout vise le namespace de la release — le sidecar de marimo-document ne joint alors pas dapr-sentry et l'installation ne devient jamais prête. |
dapr.trustDomain | scrydon | Domaine de confiance SPIFFE. Toutes les ACL générées en dépendent. Ne surchargez que pour correspondre à un CA Dapr existant — mais cela désactive l'isolation d'identité inter-clusters. |
dapr.global.tag | 1.18.9 | Tag d'image du plan de contrôle Dapr + sidecar, synchronisé avec la dépendance de Chart.yaml. Utilisez cette version testée avec un plan de contrôle externe. |
dapr.crypto.masterKey | "" | Clé maître AES-256. Générée automatiquement à la première installation et préservée lors des mises à jour. BYO : openssl rand -base64 32. |
dapr.postgresStateStore.maxConns | 2 | Taille du pool de connexions de chaque composant Dapr state.postgresql, dans chaque sidecar auquel il s'applique. Sans valeur, Dapr utilise le nombre de cœurs du nœud (au moins 4) par composant et par pod. |
dapr.secretStore.enabled | true | Créer le composant Dapr SecretStore adossé aux secrets Kubernetes. |
dapr.apiLogging.enabled | false | Journaliser chaque appel d'API du sidecar (msg="HTTP API Called"). Désactivé par défaut : sur un cluster chargé, c'est de loin le plus gros producteur de logs (46 % du volume total avant désactivation), un journal d'accès rarement lu mais toujours indexé et conservé. Activez-le le temps de diagnostiquer un problème de routage du sidecar, puis désactivez-le. |
dapr.apiLogging.obfuscateURLs | true | Masquer les segments d'URL dans ces lignes de journal. À laisser activé : les routes du planificateur contiennent des identifiants de locataire (/v1.0-alpha1/jobs/data-source-tick-org-<uuid-org>), donc le désactiver écrit des identifiants d'organisation dans votre système de journalisation. |
Apporter votre propre Dapr requiert la version testée 1.18.9, le domaine de confiance
scrydon(ou faire correspondre viadapr.trustDomain) et un injecteur de sidecar opérationnel. Voir Installations Dapr existantes.
Base de données — Postgres intégré ou BYO
infra.db contrôle le Postgres intégré (pgvector). Pour une instance externe/managée, la recette complète — notes par fournisseur, clés infra.db.external.*, pré-création des bases — est sur BYO Database.
| Clé | Défaut | Rôle / justification |
|---|---|---|
infra.db.enabled | true | Exécuter le Postgres intégré dans le cluster. Mettre false pour utiliser une instance managée via infra.db.external.*. |
infra.db.credentials.password | "" | Lors d'un vrai helm install, vide génère un mot de passe aléatoire conservé dans secrets-infra, qui survit à helm uninstall avec db-pvc. Une fois Postgres initialisé, le mot de passe du secrets-infra actif l'emporte toujours : une autre valeur ici est ignorée (les notes d'installation le signalent) au lieu de casser toutes les connexions. Pour le changer, voir Faire tourner le mot de passe du Postgres intégré. Un rendu sans accès au cluster (helm template, ArgoCD, helm diff) ne peut pas lire secrets-infra : il utilise cette valeur telle qu'écrite, ou postgres si elle est vide, comme le chart l'a toujours fait. Lors d'une installation active, une valeur explicite ne peut contenir que A-Z a-z 0-9 . _ ~ ! $ & ' ( ) * + , ; = -, car elle est insérée sans échappement dans chaque URL de connexion. openssl rand -hex 16 convient. |
infra.db.storage.size | 5Gi | Taille du PVC pour la base intégrée. |
infra.db.postgres.maxConnections | 250 | max_connections pour Postgres intégré. Gardez cette valeur au-dessus de la somme des pools applicatifs générés et des pools des magasins d'état Dapr (dapr.postgresStateStore.maxConns), multipliée par le nombre de réplicas de chaque charge de travail plus un — une mise à niveau démarre chaque nouveau pod avant d'arrêter l'ancien —, avec une marge pour les migrations et l'administration : un pool actif occupe l'intégralité de sa limite. Avec les limites par défaut, cette somme vaut 207 (217 avec collaboration.enabled), pour 237 connexions utilisables après 3 emplacements superutilisateur et 10 pour les jobs et les opérateurs. Augmenter une limite ou un nombre de réplicas consomme cette marge. |
infra.lakekeeper.databasePool.readMax / writeMax | 10 / 5 | Pools de connexions en lecture et en écriture de Lakekeeper (LAKEKEEPER__PG_READ_POOL_CONNECTIONS / LAKEKEEPER__PG_WRITE_POOL_CONNECTIONS). Comptés dans le même budget de connexions. |
infra.db.resources.limits.memory | 4Gi | Plafond mémoire du Postgres intégré, dimensionné pour maxConnections: 250 (requête 2Gi). Le réduire sans abaisser aussi le plafond de connexions expose le postmaster à un arrêt OOM par le noyau sous charge. |
infra.db.tls.enabled | true | TLS intra-cluster (certificat auto-signé automatique, ISO 27001 A.8.24). Laisser activé pour la base intégrée ; les utilisateurs Postgres managé désactivent et utilisent le TLS du fournisseur. |
infra.db.backup.enabled | false | CronJob pg_dump optionnel (A.8.13). Définir schedule et retentionDays. databases est vide par défaut, ce qui sauvegarde toutes les bases créées par le chart ; ne listez des noms que pour en sauvegarder moins. Chaque exécution écrit aussi globals-<horodatage>.sql.gz (les rôles du cluster, sans mots de passe), qu'une restauration applique en premier. Les utilisateurs Postgres managé utilisent la sauvegarde du fournisseur. |
infra.db.backup.offCluster.enabled | false | Envoyer les dumps logiques conservés, accompagnés de leurs fichiers .sha256, vers Azure Blob. Définir endpoint, container, objectPrefix et credentialSecret ; le cycle de vie et l'immuabilité côté distant restent une politique Azure. |
infra.db.external.existingSecrets.* | "" | Mode BYO A (recommandé) — noms de Secrets par application contenant DATABASE_URL (auth/agentic), DATABASE_URL_ANALYTICS, etc. |
infra.db.external.<app>Url | "" | Mode BYO B — DSN applicatifs en ligne (apparaissent dans helm get values). sslMode ajouté comme ?sslmode=. |
infra.db.external.lakekeeperUrl | "" | DSN Postgres de Lakekeeper. Requis lorsque infra.db.enabled=false et que Lakekeeper est activé ; utilisé pour les connexions en lecture et en écriture et stocké dans secrets-lakekeeper. |
# Bundled (default) — just set a strong password:
infra:
db:
credentials:
password: REPLACE-WITH-DB-PASSWORD
# BYO managed Postgres:
infra:
db:
enabled: false
external:
existingSecrets:
auth: scrydon-auth-db
agentic: scrydon-agentic-db
lakekeeperUrl: "postgres://scrydon:REDACTED@pg.example.com:5432/lakekeeper"
sslMode: requireStarRocks — Tables managées (OLAP)
Pod unique allin1-ubuntu. Alimente l'interface Tables et le fallback d'inférence de schéma agentique. Associé à apiTable.
| Clé | Défaut | Rôle / justification |
|---|---|---|
infra.starrocks.enabled | true | Exécuter StarRocks intégré. Mettre false (avec apiTable.enabled: false, ou pointer apiTable.starrocks.host vers un cluster externe) pour l'ignorer. Désactivé automatiquement en mode Azure. |
infra.starrocks.storage.size | 20Gi | Taille du PVC. Les métadonnées FE et le stockage BE partagent ce PVC, qui survit donc aux redémarrages du pod (le mot de passe root défini ci-dessous persiste). |
infra.starrocks.resources | 5–8Gi / 0.5–2 CPU | Le composant data-plane intégré le plus lourd — voir Réduction. |
apiTable.starrocks.replicationNum | "1" | Nombre de réplicas de table StarRocks utilisé dans chaque CREATE TABLE. La valeur par défaut "1" correspond au déploiement intégré allin1 en pod unique (un seul nœud BE). Ne l'augmentez pour correspondre à votre nombre de BE que lorsque apiTable.starrocks.host pointe vers un cluster externe multi-nœuds — une valeur supérieure au nombre de nœuds BE actifs fait échouer la création de table avec ERROR 1064: replication num should be less than or equal to the number of available BE nodes. |
Le StarRocks intégré est en pod unique (FE + un BE dans un même processus). apiTable.secrets.STARROCKS_PASSWORD est géré pour vous : l'image intégrée livre root sans mot de passe, et si vous définissez une valeur non vide, un sidecar password-reconciler dans le pod starrocks-fe applique automatiquement la même valeur à StarRocks — à l'installation, après les redémarrages et lorsque vous faites tourner la valeur. Laissez-la vide pour un root sans mot de passe, ou définissez-la et le chart la provisionne — aucune étape manuelle. Voir Identifiants StarRocks.
apiTable.starrocks.replicationNum vaut désormais "1" par défaut pour correspondre au BE unique : il n'a donc plus besoin d'être ajusté pour le déploiement intégré — augmentez-le uniquement lorsque apiTable.starrocks.host pointe vers un cluster externe multi-nœuds.
Pour une production multi-AZ, passez à l'starrocks-kubernetes-operator (séparation FE/BE), définissez apiTable.starrocks.replicationNum selon son nombre de BE et pointez apiTable.starrocks.host vers son Service FE.
SeaweedFS — stockage objet
Stockage compatible S3 en pod unique pour les téléversements.
Une seule réplique sur un volume ReadWriteOnce : un déploiement (une mise à niveau
du chart qui change son image ou ses identifiants) arrête l'ancien pod avant de
démarrer le nouveau. Les écritures de tables pendant cette fenêtre reçoivent
503 object_store_unavailable et sont réessayées. Le pod n'est déclaré prêt
qu'une fois que son master liste un nœud de stockage, ce qui limite la fenêtre à
quelques secondes. Utilisez un S3 managé si le stockage doit rester disponible
pendant les mises à niveau.
| Clé | Défaut | Rôle / justification |
|---|---|---|
infra.seaweedfs.enabled | true | Exécuter le stockage intégré. Désactivez si vous placez un S3 managé devant la plateforme (AWS S3, Azure Blob via API S3, GCS, MinIO) configuré sur https://<host>/platform/settings/platform/storage. Désactivé automatiquement en mode Azure. |
infra.seaweedfs.s3.existingSecret | "" | Vide → le chart gère des clés d'accès/secret aléatoires (préservées lors des mises à jour, conservées à la désinstallation). Indiquer un Secret pré-créé avec accessKey/secretKey pour BYO. |
infra.seaweedfs.storage.size | 20Gi | Taille du PVC. |
Stockage par défaut du déploiement
L'emplacement où chaque organisation sans stockage S3 ou Azure propre conserve ses
fichiers, sous orgs/<organizationId>/ dans un même bucket. Seul auth
(api-platform) résout le stockage, il est donc le seul à recevoir les variables
d'environnement STORAGE_DEFAULT_S3_*. Sans stockage par défaut, ces organisations ne
peuvent rien téléverser tant qu'un administrateur n'a pas configuré le stockage, et
l'étape stockage de l'assistant de configuration devient obligatoire.
| Clé | Défaut | Rôle / justification |
|---|---|---|
storage.deploymentDefault.enabled | auto | auto : activé lorsque s3.endpoint est défini ou que le SeaweedFS intégré est activé, ce qui couvre toutes les installations sauf celles avec global.azure.enabled. true force l'activation et fait échouer le rendu s'il n'existe aucun stockage vers lequel pointer. false le désactive. |
storage.deploymentDefault.s3.endpoint | "" | Vide → le SeaweedFS intégré (svc-seaweedfs-s3.<infra-ns>:8333). Définissez-le pour utiliser un stockage externe compatible S3 ; existingSecret devient alors obligatoire. |
storage.deploymentDefault.s3.existingSecret | "" | Secret contenant accessKey/secretKey dans le namespace auth. Vide → les identifiants SeaweedFS, copiés dans ce namespace lorsqu'il diffère du namespace infra. |
storage.deploymentDefault.s3.bucket | scrydon-uploads | Créé à la première écriture. |
storage.deploymentDefault.s3.publicEndpoint | "" | Endpoint accessible par le navigateur pour les URL présignées. Vide → les transferts passent par la plateforme. |
storage.deploymentDefault.s3.region / forcePathStyle | us-east-1 / true | Réglages standard du client S3. |
Vous mettez à niveau depuis une version où les organisations sans paramètres de stockage
utilisaient le stockage local ? Les fichiers présents sur les volumes de téléversement
des pods ne sont pas déplacés. Sur emptyDir, ils sont perdus au redémarrage d'un pod.
Copiez-les dans le stockage par défaut avant la mise à niveau. Pour cela, copiez
/app/uploads hors de chaque pod api-platform et api-agentic, puis téléversez chaque
fichier vers orgs/<organizationId>/<key> dans le bucket par défaut. La table
file_metadata de la base auth indique quelle organisation possède chaque clé.
Services applicatifs
Les applications produit — auth (api-platform), platform, cortex, horizon, analytics, apiOntology, apiTable, agentic (app + realtime). Chaque bloc partage une forme commune (horizon est l'exception sans état : pas de base de données, pas de sidecar Dapr, toujours dans le namespace de la plateforme, et horizon.copEnabled ne conditionne que ses surfaces de situation tactique) :
| Clé (par application) | Rôle / justification |
|---|---|
<app>.enabled | Générer l'application. La plupart restent activées ; analytics.enabled: false supprime l'interface analytique + marimo (charge de travail optionnelle la plus lourde). |
<app>.replicas | Échelle horizontale. |
<app>.image.tag | Par défaut Chart.AppVersion — laisser vide pour suivre le chart. |
<app>.resources | Requêtes/limites. Les valeurs par défaut sont ajustées d'après les incidents OOM en production (limite agentic : 4Gi, applications SSR : 2Gi) ; ne réduire que sur des clusters d'évaluation. |
<app>.databasePool.max | Limite de pool Postgres par pod, rendue comme la variable d'environnement générique DATABASE_POOL_MAX. Chaque pool du pod la respecte. Un pool ouvre toutes ses connexions d'un coup — à sa première requête, puis de nouveau après qu'elles ont toutes été fermées pour inactivité — si bien qu'une limite correspond à ce que le pod occupe lorsqu'il est actif, et non à un plafond vers lequel il croît. Les pods multi-bases (auth, apiTable) ajoutent authMax, rendue comme la surcharge AUTH_DATABASE_POOL_MAX de leur pool d'authentification. Les clés de platform sont inertes : il ne reçoit aucune URL de base de données et lit les données d'authentification via API Platform. Réduisez-les pour les petits tiers Postgres managés ; augmentez-les seulement si max_connections dispose de la marge correspondante. |
<app>.gateway.{enabled,hostname} | Nom d'hôte par application (mode sous-domaine uniquement — ignoré en sous-chemin). Les annotations et blocs TLS par application ont disparu : une seule Gateway possède tous les listeners, et les noms de Secret par application conservent leurs valeurs par défaut tls-<app>. |
<app>.corsOrigins | Origines navigateur autorisées. |
<app>.secrets | Secrets par application (voir ci-dessous). |
<app>.dapr.appApiToken | Token sidecar-vers-application par application, unique par application. Vide → généré automatiquement et préservé lors des mises à jour. BYO : openssl rand -base64 32. |
Clés notables spécifiques aux applications :
auth:
secrets:
AUTH_SECRET: REPLACE-WITH-AUTH-SECRET # session signing — openssl rand -hex 32
auditLog:
enabled: true # SIEM forwarding + retention crons (ADR 2026-04-16)
chain:
enabled: false # chaîne de hachage infalsifiable — optionnel, coût de signature
maxInFlight: 64 # appels ouverts par pod, partagés par le routeur, l'API et MCP (429 au-delà)
bodyRead: # un corps de requête doit continuer d'arriver (400 body_read_too_slow)
graceMs: 10000 # avant que le débit minimal ne s'applique
minBytesPerSecond: 65536 # abaissez les deux pour des clients sur des liens lents
analytics:
marimoDocument:
enabled: true # private, compute-free document renderer
marimoRuntime:
startupDeadlineMs: 300000 # Connect/Run preparation deadline
appRevalidation:
enabled: false # ré-épingler les apps publiées après une mise à niveau du runtime (staging d'abord)
secrets:
MARIMO_RUNTIME_HMAC_SECRET: "" # blank → generated and reused across upgrades
apiOntology:
secrets:
APP_PUBLICATION_SIGNING_SECRET: "" # vide → généré et réutilisé entre les mises à niveau
apiTable:
starrocks:
host: "" # blank → bundled FE Service; set for external StarRocks
user: root
secrets:
STARROCKS_PASSWORD: REPLACE-WITH-STARROCKS-PW
agentic:
realtime:
gateway:
hostname: ws-agentic.example.com # subdomain mode only
passkey:
rpId: example.com # subdomain mode: required, the domain every app host shares
origin: https://app.example.com # subdomain mode: required. Subpath mode derives both from routing.host
apiOntology.secrets.APP_PUBLICATION_SIGNING_SECRET— signe les sceaux de validation des publications d'app (Analytics signe, api-ontology vérifie). Au moins 32 octets. À définir uniquement ici ; le chart écrit la même valeur dans les deux Secrets. Vide, il réutilise la valeur existante ou en génère une ; avecglobal.requireExplicitSecrets=true, il est obligatoire. La clé se définit uniquement sousapiOntology; la définir sousanalytics.secretsfait échouer le rendu.
Les annotations de cookie sticky du temps réel ont disparu. Elles ne s'appliquaient qu'en mode sous-domaine, et l'affinité de session pour les backends Gateway API ne fait pas partie du canal standard —
agentic-realtimen'a donc aucune affinité si vous l'exécutez avec plus d'un réplica en mode sous-domaine. Il est livré avecreplicas: 1, ce que supposent également les paramètres PodDisruptionBudget ci-dessous.
auth.secrets.SERVICE_ADMIN_TOKENest déprécié — la production utilise Dapr mTLS (SPIFFE). Ne le définir que pour le développement local sans sidecars. Quand les clés avec underscore sont interdites (paramètres protégés Azure Marketplace), utiliserauth.authSecretà la place deauth.secrets.AUTH_SECRET.
executionFabric et runtimePlane
Le plan d'exécution est opt-in jusqu'à qualification de Kata/KVM et des contrôles réseau.
Il possède les pods Agent éphémères, les sessions Marimo de longue durée protégées par
génération et les jobs de notebooks neufs à usage unique. L'ouverture d'un notebook utilise
toujours le moteur de rendu sans calcul ; Connect, Run hors connexion et les jobs refusent si
le plan est indisponible. Le calcul Marimo ne revient jamais à un processus de service
produit. Les backends déployés et leur disponibilité authentifiée par profil
déterminent les niveaux disponibles. Le résolveur essaie toujours microvm d'abord, puis
managed_process uniquement si l'organisation l'autorise. L'hôte d'acteur générique du processus géré est généré
par défaut (niveau normal) ; l'activation d'un Runtime Plane qualifié ajoute le niveau
isolé sans autre liste ni préférence. Un administrateur d'organisation active Exiger l'exécution isolée dans
Paramètres → Plateforme → Compute pour imposer la microVM comme plancher strict : les
exécutions de cette organisation refusent alors au lieu d'utiliser le niveau processus géré.
Une exécution liée ne descend jamais de niveau après son démarrage.
Le chart refuse de générer si aucun backend d'exécution n'est déployé. Cette
combinaison s'installait silencieusement et toute exécution échouait ensuite à l'exécution
avec « No permitted … execution tier is currently ready » ; elle échoue désormais dès
helm install en nommant le chemin de valeurs à corriger. Une posture de production stricte
qui veut uniquement la microVM définit explicitement managedProcess.enabled: false —
voir values.production.example.yaml.
Le niveau géré utilise un unique Deployment et une unique image d'hôte d'acteur Dapr. Dapr gère le placement et le routage horizontal ; chaque invocation reçoit un nouvel arbre de processus enfants et un nouvel espace de travail, tout en réutilisant les mêmes runners Agent, implémentation et notebook que le backend microVM. Ce niveau partage le noyau du pod de l'hôte d'acteur et reste explicitement plus faible qu'une microVM.
Les Agents standard utilisent toujours AgentCapabilityContract avec le
protocole fixe agent-capability-contract. Aucun mode de broker d'outils
d'intégration n'est à activer pendant une installation ou une mise à niveau,
et aucune valeur opérateur ne sélectionne une autre architecture Agent. Le
chart épingle le protocole nommé dans Runtime Plane ; une image runner
incompatible est refusée avant la création d'un workload Agent.
Le chart réplique vos global.imagePullSecrets du namespace de la release vers les deux namespaces runtime au moment de l'installation/mise à niveau, donc les registres privés fonctionnent sans étape supplémentaire. (Les pipelines helm template puis apply n'ont pas de cluster à lire — pré-créez les secrets de pull dans les deux namespaces runtime dans ce mode de travail.)
| Clé | Défaut | Rôle / justification |
|---|---|---|
executionFabric.managedProcess.enabled | true | Déploie l'unique hôte d'acteur Dapr générique (niveau normal). Effectif seulement si dapr, agentic et agentic.app.dapr.workflows sont activés (son actor state store). Désactivez-le pour un déploiement physiquement microVM-only. |
executionFabric.managedProcess.replicas | 2 | Réplicas fixes quand HPA est désactivé. Le placement Dapr répartit les acteurs par exécution entre les réplicas. |
executionFabric.managedProcess.enabledProfiles | trois profils | Profils de plateforme fixes : agent_turn, implementation et notebook. Ils ne créent pas d'applications ni d'images distinctes. |
executionFabric.managedProcess.maxConcurrentInvocations | 4 | Nombre maximal d'arbres de processus frais supervisés simultanément par réplique. La saturation produit une erreur de capacité typée ; Dapr et le HPA assurent la mise à l'échelle horizontale. |
executionFabric.managedProcess.autoscaling.* | désactivé, 2–10 réplicas | HPA CPU facultatif de l'hôte générique. |
runtimePlane.enabled | false | Déploie le backend microvm après qualification de Kata/KVM, des chemins de contrôle et de callback, et des contrôles d'egress. Le contrôleur découvre lui-même la RuntimeClass et les nœuds compatibles. Marimo interactif l'exige ; les requêtes Agent, implémentation et jobs notebook sensibles au niveau peuvent utiliser à la place managed_process uniquement si la politique d'organisation l'autorise. |
runtimePlane.namespace | scrydon-runtimes | Namespace du contrôleur. Il doit différer du namespace des charges non fiables. |
runtimePlane.workloadNamespace | scrydon-runtime-workloads | Namespace des charges non fiables. Le RBAC du contrôleur y gère les pods exec et les pods/Services/NetworkPolicies Marimo possédés. Les deux ServiceAccounts de workload ne reçoivent aucun jeton API. |
runtimePlane.replicas | 1 | Topologie à contrôleur unique imposée ; les mises à jour Recreate préservent la propriété exclusive du PVC durable du registre. |
runtimePlane.persistence.* | 1Gi, classe du cluster | Stockage durable obligatoire des revendications d'exécution et des résultats terminaux. Un stockage corrompu ou non inscriptible bloque le démarrage ou la répartition. |
runtimePlane.dapr.enabled | true | Le chemin de contrôle authentifié du plan. Désactiver cette valeur ou dapr.enabled global désactive le plan en échec fermé (rien n'est généré ; les tours Agent refusent avec une erreur typée). |
runtimePlane.image.* | version applicative de la release | Image du contrôleur. Épinglez le tag de release ou canary publié ; ne déployez pas latest. |
runtimePlane.runnerImage | vide | Vide résout scrydon/bundle-runner à la version applicative du chart (même registre que chaque image d'application). Si défini, la valeur doit être un tag ou un digest épinglé — les profils production épinglent registry/repo@sha256:<digest> ; le schéma rejette latest. |
runtimePlane.enforcerImage | vide | Vide résout scrydon/egress-enforcer à la version applicative du chart. Si défini, épinglez le digest examiné ; le schéma rejette latest. |
runtimePlane.marimoRuntimeImage | vide | Le profil Marimo immuable du contrôleur exige une référence par digest sha256 (registry/repo@sha256:<digest>) — une valeur par tag seul (y compris le tag par défaut de la version applicative) fait refuser le démarrage du contrôleur (Marimo runtime image must be pinned by sha256 digest). Toujours définir le digest quand runtimePlane.enabled: true. |
runtimePlane.marimo.* | TTL d'inactivité de 30 minutes, cull de 30 secondes, délai de provisioning de 300 secondes | Borne l'inactivité du runtime interactif, le polling de nettoyage et le provisioning du contrôleur. Analytics possède un délai de préparation de bout en bout distinct. |
runtimePlane.marimo.maxSizeTier | large | Taille maximale d'un runtime Marimo : xsmall, small, medium ou large (définit RUNTIME_PLANE_MAX_SIZE_TIER). Une demande au-dessus est refusée en HTTP 409 runtime_size_tier_unavailable, jamais réduite en silence. Le plafond s'applique à chaque demande, y compris la réutilisation d'un éditeur en cours et la reprise d'une application publiée. Paramètres → Calcul affiche les tailles au-dessus comme indisponibles. Une valeur inconnue échoue à la validation du schéma, et le contrôleur refuse de démarrer avec elle. Ne la descendez sous medium qu'après la mise à niveau d'Analytics : une version antérieure d'Analytics n'envoie aucune taille, que le plan lit comme medium, si bien que chaque runtime qu'elle démarre serait refusé. |
runtimePlane.blockedCidrs | plages RFC1918 | Plancher réseau du déploiement : les plages propres au cluster (pods, services, nœuds). Inclus dans chaque instantané de sortie des workloads isolés, et lu sous le même nom par api-platform, api-ingestion et api-table, qui ne laissent jamais une connexion, un récepteur de logs ni un endpoint de fournisseur OAuth l'atteindre. La politique d'organisation ne peut pas les retirer. Restreignez-le aux plages réelles avant d'ajouter des réseaux privés. |
runtimePlane.upstreamDns | vide | Surcharge facultative du serveur DNS vers lequel la sortie des sandboxes transmet ses requêtes. Vide — le bon choix sur AKS, EKS, GKE, k3s, kind comme sur site — utilise le premier nameserver du /etc/resolv.conf du pod du plan d'exécution lui-même (le DNS du cluster attribué par kubelet ; les adresses de bouclage et IPv6 lien-local sont ignorées), et le tier managed-process utilise de même celui de son propre pod. Sans nameserver utilisable, le plan refuse de démarrer en nommant cette valeur. Ne la définissez que pour épingler un autre résolveur, sous la forme <ip>:53 ou [<ipv6>]:53 ; une valeur erronée casse toute sortie par nom d'hôte. |
runtimePlane.execution.maxConcurrentPerTenant | 8 | Nombre maximal d'exécutions en attente/en cours pour un locataire avant une réponse HTTP 429 typée. |
runtimePlane.execution.maxConcurrentGlobal | 128 | Plafond global de surcharge du contrôleur unique ; doit être supérieur ou égal au plafond par locataire. |
runtimePlane.isolation.microvm.renderRuntimeClass | false | Génère un RuntimeClass Kata autogéré. Laissez false sur AKS Pod Sandboxing, où AKS en est propriétaire. La disponibilité microVM est inférée d'une découverte RuntimeClass réussie et d'un nœud Ready, non cordonné et compatible. |
runtimePlane.execPool.agentSize | 0 | Nombre de pods microVM préchauffés, pas encore attribués, maintenus démarrés pour les étapes d'Agent. Une étape qui en trouve un évite le démarrage d'un pod. Chaque pod du pool réserve 1,1 CPU et 2,125 Gio sur un nœud Kata, qu'il serve ou non, plus le surcoût du RuntimeClass (600 Mio sur AKS Pod Sandboxing). 0 désactive le pool ; 32 au plus. |
runtimePlane.execPool.extensionCodeSize | 0 | Idem pour les exécutions d'outils d'extension (Functions) : 1,35 CPU et 1,375 Gio par pod, plus le surcoût du RuntimeClass. Exige les images fournisseur estampillées (vendorRunnerImage, vendorBrokerImage, vendorCandidateSha) ; sans elles, le chart refuse le rendu. 32 au plus. |
runtimePlane.execPool.maxAgeSeconds | 900 | Un pod préchauffé plus ancien est remplacé, afin que son image et sa politique de sortie ne deviennent jamais obsolètes. Minimum 60. |
runtimePlane.imagePrePull.enabled | false | Déploie sur les nœuds Kata un petit DaemonSet qui télécharge les images du bac à sable avant la première exécution sur un nouveau nœud. Il s'exécute sous le runtime par défaut : il ne raccourcit un démarrage à froid que si le runtime Kata partage le magasin d'images du nœud. Mesurez la première exécution sur un nœud neuf avant de le conserver. imagePrePull.nodeSelector et tolerations ciblent par défaut AKS Pod Sandboxing ; Helm fusionne votre nodeSelector avec celui par défaut, donc mettez la clé AKS à null pour la remplacer. |
networkPolicies.enabled | false | Génère les NetworkPolicies d'entrée/sortie du contrôleur et des charges non fiables. Définissez true avec un CNI qui les applique ; sinon la frontière réseau Kubernetes est absente. |
Tailles des runtimes Marimo
Chaque organisation choisit une taille pour les éditeurs de notebooks (par défaut small)
et pour les applications publiées (par défaut xsmall) dans Paramètres → Calcul. Sur
Kubernetes, une taille ne fixe que les ressources du conteneur marimo ; les sidecars et le
stockage éphémère restent fixes :
| Taille | Limite CPU | Demande CPU | Mémoire |
|---|---|---|---|
xsmall | 250m | 250m | 512Mi |
small | 1 | 250m | 1Gi |
medium | 2 | 500m | 4Gi |
large | 4 | 1 | 8Gi |
Abaisser maxSizeTier prend effet au redémarrage du Runtime Plane avec la nouvelle valeur,
et ce redémarrage arrête chaque runtime en cours au-dessus du nouveau plafond : chacun se
termine avec le code d'échec size_tier_above_ceiling et ses ressources sont supprimées.
Les runtimes au niveau du plafond ou en dessous continuent de tourner. Le premier démarrage
de cette version reconstruit aussi une fois la table du registre des runtimes du plane, en
conservant ses lignes, afin qu'elle puisse enregistrer ce code. Une taille
qu'aucun nœud ne peut planifier n'est pas refusée d'emblée : le pod reste en attente jusqu'à
provisionTimeoutSeconds, puis la tentative échoue par dépassement du délai de démarrage.
Gardez maxSizeTier à une taille que votre pool de nœuds Kata peut placer.
N'abaissez maxSizeTier qu'une fois qu'API Platform et Analytics exécutent tous deux cette
version. Le redémarrage qui arrête un runtime au-dessus du plafond enregistre cet arrêt comme
événement d'audit via API Platform, et une version antérieure d'API Platform rejette le
nouveau motif size_tier_above_ceiling. Le plane ne démarre pas tant que cet événement n'est
pas enregistré : il échoue au démarrage et redémarre en boucle jusqu'à la mise à niveau d'API
Platform. Une version antérieure d'Analytics ne sait pas non plus lire un runtime terminé avec
ce code.
Lors d'une mise à niveau, déployez le Runtime Plane avant Analytics. Analytics n'envoie
une taille qu'à un plane qui annonce sa prise en charge. Si Analytics est mis à niveau en
premier, les runtimes démarrés entre-temps tournent en medium, et après la mise à niveau
du plane, la demande suivante de chacun d'eux, désormais à la taille de l'organisation, peut
échouer une fois avec un conflit d'intention. La mise à niveau d'Analytics change aussi une
fois la clé de demande de chaque runtime, car la politique de taille en fait partie.
Les deux choix de déploiement sont microvm et managed_process. Les anciens champs du
protocole Runtime Plane (require_true_vm, fallback, mediated et hardened) ne sont pas
des contrôles de niveau Helm ou d'organisation. Les adaptateurs sensibles au niveau émettent
une valeur de protocole fixe réservée à la microVM après que le résolveur partagé a sélectionné
microvm, uniquement pour la compatibilité des mises à niveau progressives avec le plan Rust.
networkPolicies:
enabled: true
executionFabric:
managedProcess:
enabled: true
runtimePlane:
enabled: true
namespace: scrydon-runtimes
workloadNamespace: scrydon-runtime-workloads
persistence:
size: 1Gi
runnerImage: registry.example.com/scrydon/bundle-runner@sha256:<digest>
enforcerImage: registry.example.com/scrydon/egress-enforcer@sha256:<digest>
marimoRuntimeImage: registry.example.com/scrydon/marimo-runtime@sha256:<digest>
blockedCidrs:
- "10.0.0.0/8" # replace/extend with the actual pod + service CIDRs
- "172.16.0.0/12"
- "192.168.0.0/16"
# upstreamDns est omis volontairement : chaque pod utilise le DNS du cluster de
# son propre /etc/resolv.conf. Ne le définir que pour épingler un autre résolveur.
isolation:
microvm:
renderRuntimeClass: false # AKS owns kata-vm-isolationLe Deployment du contrôleur et les deux identités de workload consomment
global.imagePullSecrets. Les pods Agent/job de notebook à usage unique utilisent
sa-runtime-exec ; les pods Marimo interactifs utilisent sa-runtime-workload. Les deux
définissent automountServiceAccountToken: false : le code non fiable ne reçoit aucun jeton
d'API Kubernetes, tandis que kubelet peut toujours utiliser l'identifiant de registre
configuré. Ne modifiez pas le ServiceAccount default du namespace. Si le registre exige un
secret d'extraction, créez le Secret portant le même nom dans runtimePlane.namespace,
runtimePlane.workloadNamespace et chaque namespace applicatif activé avant l'installation,
ou fournissez un accès au registre équivalent au niveau des nœuds.
L'enforcer s'exécute avec l'UID 0 et uniquement NET_ADMIN/NET_BIND_SERVICE ; l'application non fiable reste sans root et abandonne toutes les capacités. Un profil Pod Security restricted global rejette l'enforcer. Configurez une exception examinée pour le namespace runtime et validez les pods rendus avec kubectl apply --dry-run=server. Ne désactivez pas les contrôles d'admission à l'échelle du cluster pour permettre l'ordonnancement du plan.
networkPolicies.enabled: true est requis pour la frontière d'entrée entre contrôleur et charges générée par le chart, et ne fonctionne qu'avec un CNI qui applique Kubernetes NetworkPolicy. Une politique rendue sur un CNI qui ne l'applique pas n'est pas un contrôle de sécurité ; prouvez son enforcement pendant la validation du déploiement.
Après le déploiement, vérifiez le rapport de capacités au démarrage et prouvez séparément le niveau choisi pour les profils Agent exec, Marimo interactif et job de notebook. Prouvez également que l'ouverture d'un notebook ne crée aucun runtime, que Connect n'exécute aucune cellule et que Run hors connexion exécute une seule fois la cellule sélectionnée. Un contrôleur Ready ne prouve pas à lui seul Kata, l'extraction des images, les callbacks, le DNS, l'installation des dépendances, le nettoyage ou l'enforcement de sortie.
Valkey managé partagé — événements, cache de modèles et limites Agentic
Le chart fournit un backbone d'événements durable (synchronisation validée de l'éditeur de workflows, flux d'événements d'organisation), un cache de découverte de modèles et des limites durables pour les webhooks et formulaires Agentic. Ces fonctions partagent une seule instance Valkey persistante ; le limiteur ne déploie pas une seconde base de données.
| Clé | Défaut | Rôle / justification |
|---|---|---|
eventBackbone.enabled | true | Backbone d'événements durable de la plateforme. |
eventBackbone.broker.managedValkey | true | Valkey persistant intégré (StatefulSet + PVC). Mettre false pour fournir votre propre composant pub/sub Dapr via broker.componentType/broker.metadata. |
eventBackbone.valkey.password | "" | Vide génère automatiquement 64 caractères lors d'une nouvelle installation, et les mises à niveau suivantes préservent le Secret actif. Voir l'encadré sur la mise à niveau ci-dessous. |
eventBackbone.valkey.storage.size | 2Gi | Taille du PVC du broker. |
modelDiscoveryCache.enabled | true | Snapshots durables des modèles dynamiques ; stateStore.managedValkey: true réutilise le même Valkey et le même mot de passe. |
agentic.rateLimit.stateStore.managedValkey | true | Compartiments durables et sûrs entre réplicas pour les webhooks/formulaires. Mettre à false pour un composant state.redis géré par l'opérateur. |
agentic.rateLimit.stateStore.metadata | [] | Métadonnées Dapr state.redis, obligatoires et transmises telles quelles lorsque managedValkey: false. |
Mise à niveau d'une installation sans Valkey managé : la première mise à niveau qui
active le Valkey managé n'a aucun Secret event-backbone-valkey existant à récupérer, et le
chart refuse délibérément d'inventer un mot de passe en cours de mise à niveau (un rendu
hors ligne/GitOps le ferait tourner silencieusement). Définissez explicitement
eventBackbone.valkey.password avant cette mise à niveau — par ex.
LC_ALL=C tr -dc 'A-Za-z0-9' </dev/urandom | head -c 64 — sinon la mise à niveau s'interrompt
avec cannot recover the managed Valkey password during upgrade. Le rendu GitOps/hors ligne
doit toujours définir cette valeur explicitement. Une seule valeur couvre à la fois le
backbone d'événements, le cache de découverte de modèles et le state store des limites de
débit Agentic.
networkPolicies.providerEgress — HTTPS sortant vers les sources de données
Les sources de données et les points de terminaison de connexion appellent l'adresse du
fournisseur configurée par un administrateur de l'organisation : les outils de point de
terminaison de connexion depuis api-platform, et toutes les sources de données — par
interrogation, à la demande, en flux — depuis api-ingestion. Avec networkPolicies.enabled,
cette règle permet à ces deux services — et à aucun autre — de joindre des adresses HTTPS
publiques. Elle n'autorise jamais les adresses privées (RFC 1918), de NAT de niveau opérateur,
link-local ou loopback, ni l'adresse de plateforme Azure 168.63.129.16, ni aucune autre
plage à usage spécial ; en IPv6, elle n'admet que l'unicast global (2000::/3). L'hôte qu'une
connexion peut joindre reste décidé, pour chaque connexion, par la liste d'autorisation de
sortie de l'organisation.
| Clé | Défaut | Rôle / justification |
|---|---|---|
networkPolicies.providerEgress.enabled | true | false supprime la règle. Le profil NATO UNCLASSIFIED définit false ; pour y admettre des plages de fournisseurs validées, repassez-le à true avec vos propres ipBlocks. |
networkPolicies.providerEgress.ports | [443] | Ports de destination. |
networkPolicies.providerEgress.ipBlocks | 0.0.0.0/0 et ::/0, plages non publiques exclues | Entrées ipBlock Kubernetes. Chaque except doit se trouver dans son cidr et appartenir à la même famille d'adresses (IPv4 ou IPv6) ; le chart refuse une entrée qui les mélange. Ajoutez vos CIDR de pods et de services à l'except IPv4 s'ils se trouvent hors des plages privées et de NAT de niveau opérateur. Remplacez la liste pour restreindre la règle, par exemple aux plages que votre pare-feu autorise. |
Chaque famille d'adresses est générée dans sa propre NetworkPolicy. Azure Network Policy
Manager ne prend en charge que l'IPv4 et rejette une politique qui contient une plage IPv6 ;
sur ces clusters, seule la politique IPv6 est rejetée et tout le reste s'applique. Retirez-y
l'entrée ::/0.
networkPolicies.telemetry — votre collecteur OpenTelemetry
Si vous exploitez un collecteur OpenTelemetry, dapr.tracing.otel.endpointAddress et
observability.otlpHttpEndpoint y dirigent Scrydon. Un collecteur situé dans un namespace que
le chart ne gère pas n'est joignable que par cette route, car aucune des politiques
default-deny n'admet ce namespace. Sans la route, une charge de travail isolée par une
NetworkPolicy ne peut pas exporter sa télémétrie. Avec networkPolicies.enabled: false, il
s'agit de marimo-document, dont la politique propre est toujours générée. Avec
networkPolicies.enabled: true, il s'agit de toutes les charges de travail Dapr. Il en va de
même pour la collecte des métriques de daprd sur dapr.metricsPort par votre scraper.
networkPolicies:
telemetry:
collectors:
- namespace: observability
podSelector:
app.kubernetes.io/component: otel-collector
ports: [4317, 4318] # OTLP gRPC (daprd), OTLP HTTP (applications)
metricsScrapers:
- namespace: observability
podSelector:
app.kubernetes.io/component: otel-collector| Clé | Défaut | Quoi / pourquoi |
|---|---|---|
networkPolicies.telemetry.collectors | [] | Pods collecteurs vers lesquels les charges de travail Dapr peuvent envoyer de l'OTLP, chacun désigné par namespace, un podSelector non vide et au moins un port. |
networkPolicies.telemetry.metricsScrapers | [] | Pods scrapers autorisés à lire dapr.metricsPort sur les charges de travail Dapr, chacun désigné par namespace et un podSelector non vide. |
La route n'ouvre que les directions que vous configurez. Elle ne sélectionne que des pods qu'une autre politique du chart isole déjà : l'activer ne peut donc pas restreindre une charge de travail qui ne l'était pas. Le profil NATO UNCLASSIFIED laisse les deux listes vides.
global.egress.privateNetworks — réseaux privés
Un endpoint de connexion (une source poll, à la demande ou en flux dont l'URL vient de sa
connexion) n'atteint que des adresses publiques sur le port 443, et la base de données d'une
source de requête n'est joignable par aucun réseau. Deux autres sortes d'adresses qu'un
administrateur d'organisation configure sont appelées depuis les serveurs de Scrydon : l'URL d'un
récepteur de logs, et les endpoints du fournisseur OAuth
d'une extension (ses URL de connexion, de jeton et d'informations utilisateur, que les paramètres
de fournisseur de l'organisation peuvent placer sur son propre hôte). Les deux n'atteignent que des
adresses https:// publiques. Toutes en restent là tant que vous, l'opérateur, n'ouvrez pas un
réseau privé. Un réseau privé désigne des plages d'adresses, leurs ports, ce qui peut les utiliser
et quelles organisations le peuvent :
| Champ | Rôle / justification |
|---|---|
name | Mots en minuscules et tirets. Affiché dans le journal d'audit et dans la disponibilité. |
cidrs | Les plages. Jamais les plages propres au cluster (runtimePlane.blockedCidrs), ni une plage contenant des adresses de loopback, link-local, de métadonnées, partagées (CGNAT), de documentation ou réservées. |
ports | Les ports sur ces plages. Il n'y a pas de liste de ports globale : chaque réseau porte les siens. |
uses | http pour les endpoints de connexion, les récepteurs de logs, les endpoints de fournisseurs OAuth et les extensions qui appellent des services auto-hébergés (Ollama, vLLM, compatible OpenAI, SigNoz, l'outil HTTP Request) ; query pour les bases de données derrière la passerelle de requêtes. |
organizations ou allOrganizations: true | Exactement l'un des deux. Un réseau ne s'ouvre qu'aux organisations qu'il désigne ; sans cela, n'importe quelle organisation pourrait autoriser le même nom et atteindre votre réseau. |
caRef (http) | Une clé de global.egress.trustAnchors.existingSecret. Un socket vers ce réseau vérifie le serveur avec ces ancres de confiance uniquement ; les endpoints publics gardent les racines du système. Sans lui, les racines du système s'appliquent. |
trustedCaRefs (query, obligatoire) | Les ancres de confiance des drivers (clés des trustedCaPaths des profils de drivers de requête) qu'une connexion vers ce réseau peut désigner. Une connexion ne peut pas en choisir une autre. |
| Clé | Valeur par défaut | Rôle / justification |
|---|---|---|
global.egress.privateNetworks | [] | Les réseaux, ci-dessus. |
global.egress.trustAnchors.existingSecret | "" | Un Secret avec un fichier PEM d'ancres de confiance par caRef, monté en lecture seule dans api-platform et api-ingestion. Les faire tourner est un déploiement. |
Seul l'opérateur ouvre un réseau : aucun paramètre d'organisation n'en élargit un. Pour un endpoint de connexion ou une source de requête, l'organisation décide aussi pour elle-même : sa liste d'autorisation de sortie doit désigner l'hôte (une adresse IP exactement), et un réseau situé dans une plage privée exige aussi son interrupteur Réseaux privés (Paramètres → Gouvernance → Egress). Un récepteur de logs ou un paramètre de fournisseur OAuth n'exige qu'un réseau ouvert à son organisation. Le loopback, le link-local, les métadonnées et les autres adresses réservées ne peuvent jamais être ouverts, et chaque adresse vers laquelle un nom se résout est vérifiée à nouveau à chaque connexion d'une source, à chaque livraison et à chaque appel au fournisseur. Sans réseau, les récepteurs de logs et les endpoints de fournisseurs restent limités au public.
Avec networkPolicies.enabled, le chart produit une NetworkPolicy par workload et par famille
d'adresses : les plages de chaque réseau sur ses propres ports, pour api-platform et
api-ingestion quand il sert http, et pour api-table quand il sert query. La règle HTTPS
large (providerEgress)
et le palier d'exécution managée excluent à la fois les plages privées et
runtimePlane.blockedCidrs : restreindre le plancher n'ouvre jamais d'espace privé hors d'un réseau.
Restreignez d'abord runtimePlane.blockedCidrs. Sa valeur par défaut est tout le RFC 1918,
qui chevauche n'importe quel réseau privé, et api-platform, api-ingestion et api-table
refusent de démarrer tant qu'un réseau le chevauche — l'erreur nomme le réseau et la plage du
plancher. Réglez-le sur les plages de pods, de services et de nœuds du cluster. Cette liste borne
aussi les notebooks : pour une organisation dont Réseaux privés est activé, un notebook peut
atteindre l'espace privé que vous n'y listez plus, comme auparavant.
queryJdbc.remoteCidrs et queryJdbc.remotePorts ont été supprimés : le rendu échoue tant que
l'un des deux est défini. Déplacez chaque plage de bases de données vers un réseau avec
uses: [query], ses ports et ses trustedCaRefs. La passerelle de requêtes exige au moins un tel
réseau, et chaque entrée de trustedCaRefs doit être distribuée par un profil de driver de requête.
Exemple : Azure Private Link sur AKS
Un cluster AKS avec Azure CNI overlay : VNet 10.224.0.0/12, nœuds 10.224.0.0/16, pods
10.244.0.0/16, services 10.0.0.0/16 (lisez les vôtres avec
az aks show -g <rg> -n <cluster> --query networkProfile). Les private endpoints de Contoso sont
dans le sous-réseau snet-pe, 10.225.8.0/24, dans le même VNet ou un VNet appairé — pas une
plage de pods, de services ou de nœuds. Le fournisseur d'identité auquel toutes les organisations
se connectent se trouve dans 10.225.9.0/28.
runtimePlane:
# The floor: the cluster's own ranges. 168.63.129.16 is always refused already.
blockedCidrs: [10.224.0.0/16, 10.244.0.0/16, 10.0.0.0/16]
global:
egress:
trustAnchors:
existingSecret: scrydon-egress-trust # key: contoso-internal
privateNetworks:
- name: contoso-pg
cidrs: [10.225.8.0/28]
ports: [5432]
uses: [query]
organizations: [<identifiant de l'organisation Contoso>]
trustedCaRefs: [azure-db]
- name: contoso-api
cidrs: [10.225.8.16/28]
ports: [443, 8443]
uses: [http]
organizations: [<contoso organization id>]
caRef: contoso-internal
- name: corporate-idp
cidrs: [10.225.9.0/28]
ports: [443]
uses: [http]
allOrganizations: true- Base de données (Azure Database for PostgreSQL, private endpoint). L'administrateur de
l'organisation saisit le nom public du serveur,
contoso-pg.postgres.database.azure.com. Dans le cluster, CoreDNS transmet à Azure DNS, et la zoneprivatelink.postgres.database.azure.comliée au VNet répond10.225.8.4; le driver vérifie le certificat par rapport au nom saisi. Ne saisissez jamais le nomprivatelink.: le certificat du serveur ne le porte pas. - API HTTP (Private Link Service). Contoso publie son API derrière un Private Link Service ;
son private endpoint reçoit
10.225.8.20. Ajoutez un enregistrement A pourapi.contoso.internaldans une zone DNS privée liée au VNet, et placez l'autorité de certification qui signe le certificat de l'API dans le Secret des ancres de confiance, sous la clécontoso-internal. - Récepteur de logs. Le collecteur SIEM de Contoso a un private endpoint dans la même plage,
10.225.8.21, avec un certificat émis par l'autorité interne de Contoso. L'administrateur de Contoso enregistrehttps://siem.contoso.internal:8443/ingestcomme récepteur de logs (une zone DNS privée liée au VNet répond10.225.8.21). Un récepteur de logs n'exige ni entrée dans la liste d'autorisation ni interrupteur. - Fournisseur d'identité. Toute organisation peut régler le domaine du fournisseur d'identité
de son extension sur l'hôte de l'IdP, que
corporate-idpouvre à toutes les organisations. - L'organisation. Activez Réseaux privés et ajoutez
contoso-pg.postgres.database.azure.cometapi.contoso.internalà la liste d'autorisation.
AWS PrivateLink (endpoints d'interface dans vos sous-réseaux) et Google Private Service Connect (une adresse du sous-réseau consommateur ; retirez le point final du nom DNS) fonctionnent de la même manière : le sous-réseau de l'endpoint est le réseau, et les plages propres au cluster restent dans le plancher. Les installations sur site et isolées listent le propre sous-réseau de la base de données, de l'API, du collecteur ou de l'IdP.
ingestBuffer — tampon durable des sources en flux et en push
Les sources de données en flux (stream) et en push acceptent leurs entrées dans un tampon
dédié avant de les valider dans leur table, et le bail d'un flux y est aussi conservé : aucune
des deux ne s'exécute sans lui. Les sources planifiées (poll) n'en ont pas besoin : le bail qui
garde chacune sur un seul réplica est conservé dans la base de données de la plateforme.
ingestBuffer.enabled (défaut false) l'active.
Par défaut, le chart l'exécute comme un Valkey unique dans le cluster, qui écrit chaque entrée
acceptée sur disque avant de répondre (ingestBuffer.existingSecret et
ingestBuffer.tls.existingSecret sont alors obligatoires). Pour utiliser à la place un
service Redis ou Valkey managé, pointez ingestBuffer.external vers celui-ci :
| Clé | Défaut | Rôle / justification |
|---|---|---|
ingestBuffer.external.urlSecret | "" | Nom d'un Secret contenant la clé url : rediss://[utilisateur]:motdepasse@hôte:port. TLS et un mot de passe sont obligatoires. Le définir remplace le Valkey du cluster pour tous les composants qui utilisent le tampon. |
ingestBuffer.external.caSecret | "" | Nom d'un Secret contenant la clé ca.crt, uniquement lorsque le service utilise une autorité de certification privée (Google Memorystore en émet une par instance). |
ingestBuffer.external.durability | replicated | replicated : une entrée n'est acceptée qu'une fois acquittée par chaque réplica du service. aof-always : un serveur unique autogéré qui écrit chaque entrée sur disque ; les services managés ne peuvent pas l'exécuter. |
ingestBuffer.external.replicas | 1 | Le nombre de réplicas du service. Le tampon le compare à ce que le service déclare. |
ingestBuffer.external.cidrs | [] | Obligatoire avec networkPolicies.enabled : les plages d'adresses vers lesquelles se résout le point de terminaison du service, par exemple le sous-réseau de son point de terminaison privé. Les deux services qui utilisent le tampon peuvent joindre ces plages, et aucun autre. |
ingestBuffer.external.port | 6379 | Avec networkPolicies.enabled : le port de l'url. Azure Managed Redis utilise 10000, Memorystore for Redis 6378, ElastiCache et Memorystore for Valkey 6379. |
Le service doit être non clusterisé et utiliser maxmemory-policy noeviction, et le mode
replicated exige au moins un réplica. Configurations prises en charge : Azure Managed Redis
avec la stratégie Non-clustered et la haute disponibilité ; Amazon ElastiCache avec le mode
cluster désactivé et Multi-AZ ; Google Memorystore for Redis (niveau Standard) ou Memorystore
for Valkey avec le mode cluster désactivé ; ou votre propre Valkey ou Redis 6.2+ avec
réplicas. Azure Cache for Redis (Basic, Standard, Premium), ElastiCache Serverless, Amazon
MemoryDB et tout service en mode cluster ne sont pas pris en charge. Les services qui utilisent
le tampon refusent de démarrer, avec un message indiquant le paramètre à modifier, lorsque le
service ne remplit pas ces exigences.
Passer du tampon du cluster à un tampon externe ne déplace pas les entrées encore en
attente de validation. Effectuez la bascule lorsqu'aucune source en flux ou en push n'a
d'entrée en attente. Avec networkPolicies.enabled, le chart refuse le rendu tant que
ingestBuffer.external.cidrs n'est pas défini.
apiIngestion — le service d'ingestion
Toute source de données qui récupère ou reçoit des données s'exécute dans son propre service,
api-ingestion : la récupération à la demande et le téléversement de fichier d'une personne,
ainsi que les sources planifiées (poll), en flux et en push. Il est déployé sur chaque
installation (tant que dapr, auth et platform gardent leurs valeurs par défaut), et
exécute les sources planifiées sur chaque installation. Les sources en flux et en push exigent
en plus le tampon d'ingestion :
avec ingestBuffer.enabled désactivé, api-ingestion exécute les sources planifiées, les
récupérations à la demande et les téléversements, et l'URL de push n'est pas publiée. Il ne possède aucune base de données et
ne stocke aucun identifiant : la plateforme lui délivre l'identifiant de la connexion d'une
source à chaque exécution, tentative de connexion ou livraison, et il ne le conserve que pour
cette tentative.
| Clé | Défaut | Rôle / justification |
|---|---|---|
apiIngestion.enabled | true | false n'exécute aucune source qui récupère ou reçoit des données : à la demande, téléversement, planifiée, en flux ou en push. La disponibilité des sources de données l'indique alors pour chacune. |
apiIngestion.replicas | 2 | Chaque réplica accepte toutes les livraisons push ; deux réplicas gardent le push disponible pendant une mise à jour. Un flux ou une source planifiée s'exécute sur un réplica et passe à un autre lorsque celui-ci s'arrête. |
apiIngestion.autoscaling.* | désactivé, 2–6 | Mise à l'échelle automatique facultative sur le CPU. Les flux déjà en cours ne migrent pas vers les nouveaux réplicas. |
apiIngestion.gateway.enabled | true | Publie l'URL de push. false garde le push privé, pour les installations qui n'utilisent que des sources en flux. |
apiIngestion.desiredPullIntervalMs | 60000 | Fréquence à laquelle chaque réplica actualise la liste des sources à exécuter. Au plus 60000. |
apiIngestion.shadowSources | [] | Sources planifiées qui exécutent aussi leur profil de connecteur compilé sur chaque réponse, pour le comparer à la définition de la source. Clés de source, ou * pour toutes les sources planifiées. Vide, rien n'est ajouté à la release. |
apiIngestion.cutOverSources | [] | Sources planifiées qui s'exécutent à partir de leur profil de connecteur compilé au lieu de leur définition. Une source dont le format de réponse est encore auto garde sa définition. Retirez une clé pour revenir en arrière sur cette source. Vide, rien n'est ajouté à la release. |
apiIngestion.retainSources | [] | Sources dont les entrées sont conservées pour la relecture et la quarantaine : la réponse d'une source planifiée, une livraison push authentifiée, la réponse d'une récupération à la demande, un fichier téléversé. Clés de source, ou *. Rendu dans api-ingestion, API Platform et Platform, pour que chaque service qui reçoit une entrée lise une seule liste. Rien n'est conservé si platform.retainedInputs.ceilingDays n'est pas aussi défini. Vide, rien n'est ajouté à la release. |
platform.retainedInputs.ceilingDays | null | Le nombre maximal de jours pendant lesquels une entrée conservée est gardée, quoi qu'autorisent sa classe, son étiquette ou sa table (1–365). null ne garde rien : la rétention est désactivée. Les entrées expirées sont supprimées par le cycle de réconciliation de Platform. |
apiIngestion.resources | 256Mi / 100m demandés | Pas encore dimensionné sous charge ; augmentez-le avec replicas. |
L'URL à laquelle un fournisseur livre est
https://<routing.host>/api/platform/data-sources/push/<binding id> en mode subpath et
https://<auth.gateway.hostname>/api/platform/data-sources/push/<binding id> en mode
subdomain. gateway.publicAuthRateLimit ne s'y applique jamais ; chaque source a sa propre
limite de livraison.
Le binding id est une adresse, pas un secret. Une source push qui ne déclare aucune
authentification des livraisons (auth.mode: "none") refuse toute livraison tant qu'un
administrateur de l'organisation n'a pas activé cette source ; ensuite, quiconque peut
joindre son URL peut livrer des lignes. Préférez les sources qui signent ou authentifient
leurs livraisons.
Ce que chaque plateforme requiert — aucune de ces combinaisons n'a encore été validée par Scrydon. Du
côté du chart, le HTTPS sortant relève de networkPolicies.providerEgress :
| Plateforme | Stockage du tampon | Entrée | NetworkPolicy | HTTPS sortant vers les fournisseurs |
|---|---|---|---|---|
| AKS | classe Premium SSD (global.storageClass) | Traefik fourni ou Application Gateway for Containers | Azure NPM, Calico ou Cilium | passerelle NAT ou Azure Firewall |
| EKS | classe EBS gp3 | Traefik fourni ou AWS Load Balancer Controller | agent network-policy du VPC CNI ou Calico | passerelle NAT |
| GKE | classe de disque persistant SSD | Traefik fourni ou contrôleur GKE Gateway | Dataplane V2 | Cloud NAT |
| Sur site (kubeadm, k3s), isolé | toute classe CSI RWO avec un fsync fiable | Traefik fourni ou votre contrôleur Gateway API | Calico ou Cilium (k3s : intégré) | une route vers l'adresse publique de chaque fournisseur ; les fournisseurs sur un réseau privé ne sont pas encore pris en charge |
Actions sortantes — dispatcher, clés de mandat et sortie sur liaison
Toute action sortante est désactivée jusqu'à ce que vous l'activiez. Ces valeurs règlent le côté déploiement ; un administrateur d'organisation active toujours chaque action, et un approbateur admet chaque demande qui exige une approbation. Voir Actions sortantes pour le guide.
| Clé | Défaut | Rôle / justification |
|---|---|---|
apiIngestion.actionDispatch.enabled | false | Exécute le dispatcher d'actions sortantes dans api-ingestion. Le chart refuse de le rendre sans les deux Secrets de clés ci-dessous. |
security.actionAuthority.signingKey.existingSecret / .key | "" / jwk | Un Secret que vous créez, contenant la JWK P-256 privée qui signe chaque mandat d'action. Monté dans api-ontology uniquement. |
security.actionAuthority.verificationKeys.existingSecret / .key | "" / jwks | Un Secret contenant le jeu de JWK publiques (clé actuelle et précédente, pendant une rotation). Monté dans API Platform et, avec le dispatcher activé, dans api-ingestion. |
security.actionAuthority.linkEgressEnabled | false | Définit ACTION_LINK_EGRESS_ENABLED=true sur api-ontology, api-ingestion et api-platform, afin qu'une action à destination link puisse être envoyée comme commande MAVLink sur une liaison signée, une fois que api-platform a libéré (consommé une fois et audité) son autorisation. Désactivée, une telle action reste en file, n'envoie rien et expire expirySeconds après son admission. Sans effet tant que le dispatcher est désactivé. La modifier redémarre les trois charges de travail. |
Le chart ne rend jamais de clé : nommez des Secrets que vous créez dans l'espace de noms de la plateforme.
opa — point de décision d'autorisation
Chaque décision d'autorisation sur les espaces de travail, workflows et ontologies est évaluée par OPA.
| Clé | Défaut | Rôle / justification |
|---|---|---|
opa.enabled | true | Garder activé. Désactivé (et sans opa.url), ces décisions échouent en mode fermé. |
opa.url | "" | Vide → DNS du Service intra-cluster. Surcharger pour un OPA externe ou un Service non standard. |
opa.logLevel | error | Seuls debug/info/error sont valides — warn fait crashlooper le pod. |
license — posture de validation
| Clé | Défaut | Rôle / justification |
|---|---|---|
license.enabled | true | Flux de licence en ligne — contacte license.scrydon.com toutes les 24h. Les overlays air-gapped mettent false / mode: offline. |
license.mode | online | online contacte le serveur ; offline vérifie uniquement le JWT local et ne signale jamais de statut d'appel au serveur. |
license.gracePeriod | 2592000 | Sans effet. La grâce de 30 jours après expiration est fixée dans le code ; la clé reste pour que les fichiers de valeurs existants restent valides. |
license.diagnostics.enabled | true | Envoie la version Scrydon installée. Désactivez pour refuser les métadonnées facultatives ; la capacité contractuelle reste transmise. |
license.capacity.acceleratorResources | [] | Mappings indépendants du fournisseur entre ressources étendues et VRAM, utilisés par la mesure horaire. Requis lorsque de la VRAM sous licence est déployée. |
license.publicKeys | {} | Sans effet. Les licences sont vérifiées à l'aide des clés de signature Scrydon intégrées à chaque version ; la clé reste pour que les fichiers de valeurs existants restent valides. |
La licence elle-même se saisit dans l'assistant de configuration et est stockée dans la base de la plateforme ; auth.secrets.LICENSE ne fait que la pré-renseigner. Scrydon doit s'exécuter sur un cluster dédié, car la capacité inclut tous les nœuds workers planifiables. Voir Licences et Rapport de capacité de licence.
Lorsque networkPolicies.enabled=true, définissez networkPolicies.kubernetesApiEgress.enabled=true et son cidr sur le point de terminaison de l'API Kubernetes tel que votre CNI le voit. cidr n'a pas de valeur par défaut — l'adresse diffère d'un cluster à l'autre — et le chart refuse le rendu tant qu'elle est vide et que cette sortie est activée. Utilisez l'adresse prête de l'EndpointSlice kubernetes plutôt que le ClusterIP du Service, car la politique est évaluée après le DNAT du Service. Trois politiques sélectionnées par pod réutilisent cette destination : le RBAC limite api-platform à get/list sur les nœuds, le labeler PSS à get/patch sur l'unique espace de noms de la release Helm et, en isolation stricte, le contrôleur Runtime Plane à ses propres pods.
kubectl get endpointslice -n default -l kubernetes.io/service-name=kubernetes \
-o jsonpath='{range .items[*].endpoints[?(@.conditions.ready==true)].addresses[*]}{.}{"\n"}{end}'| Cluster | Ce que renvoie la commande | cidr |
|---|---|---|
| AKS, GKE, k3s, kubeadm avec un seul nœud de plan de contrôle | une adresse | cette adresse avec /32 |
| EKS, kubeadm avec plusieurs nœuds de plan de contrôle | deux adresses ou plus ; une bascule déplace l'API de l'une à l'autre | le plus petit CIDR qui les couvre toutes |
packSources — distribution de packs gérée par le chart
| Clé | Défaut | Rôle / justification |
|---|---|---|
auth.enforceProcessFlowRequirements | true | Refuser l’activation d’un flux de processus dans un espace de travail tant qu’une extension nécessaire à l’un de ses blocs n’y est pas installée, connectée ou activée. Seule la première installation dans un espace de travail est refusée ; les mises à jour et réparations ne font que signaler. Mettre false pour journaliser le manque sans refuser — un interrupteur d’arrêt, pas un réglage. Produit SCRYDON_PROCESS_FLOW_REQUIREMENTS_ENFORCE sur api-platform. Voir Extensions nécessaires à un flux. |
auth.requireSignedExtensionSources | false | Rejeter les politiques de sources d'extensions comportant une branche de succès non signée, aux frontières de CRUD des sources, de sonde, de réconciliation et d'activation d'espace de travail. À activer pour les déploiements réglementés. L'ancien nom de la clé reste pris en compte ; voir Mises à jour. |
packSources.enabled | false | Initialiser les sources de packs depuis les valeurs du chart à chaque mise à jour. |
packSources.sources[] | [] | Liste d'entrées (organization, name, kind, url, …). Les lignes gérées par Helm sont en lecture seule dans l'interface. Les identifiants sont référencés par authSecretRef et provisionnés séparément. Voir Sources de packs. |
responseCompression — pages compressées
Les applications platform, agentic, analytics, cortex et horizon compressent elles-mêmes leurs pages, les données de leurs fonctions serveur et leur JSON : brotli pour un navigateur qui l'accepte, gzip sinon. Cela fonctionne derrière n'importe quelle périphérie : vous n'avez pas besoin d'activer la compression sur votre passerelle ou votre équilibreur de charge pour ces applications. Les flux d'événements et les réponses de moins de 1 Ko sont laissés tels quels.
| Clé | Défaut | Quoi / pourquoi |
|---|---|---|
responseCompression.enabled | true | false sert toutes les pages non compressées. À utiliser uniquement si votre périphérie gère mal une réponse encodée. |
responseCompression.maxConcurrent | 32 | Compressions simultanées par pod. Chacune occupe quelques Mo ; au-delà de la limite, la réponse est envoyée non compressée au lieu d'attendre. |
Les réponses de connexion et de session (routing.paths.apiAuth, et le proxy /api/auth de l'application platform) ne sont jamais compressées, car elles contiennent des jetons de session et un secret compressé peut être récupéré (BREACH). Le proxy de platform les marque Cache-Control: no-transform. Si votre propre périphérie compresse, excluez-en routing.paths.apiAuth et respectez no-transform.
Sécurité des pods et budgets de perturbation
| Clé | Défaut | Rôle / justification |
|---|---|---|
podSecurityStandards.hardenAppContainers | true | Appliquer runAsNonRoot, seccompProfile: RuntimeDefault, drop: [ALL] et allowPrivilegeEscalation: false aux charges de travail applicatives Scrydon et à leurs conteneurs d'initialisation utilitaires. Sûr par construction — toutes les images applicatives déclarent déjà un USER non root. readOnlyRootFilesystem n'est délibérément pas défini (les binaires compilés diffusent leur bundle SSR via un fichier temporaire au démarrage à froid). |
podSecurityStandards.enabled | false | Appliquer les labels pod-security.kubernetes.io/* aux namespaces Scrydon. |
podSecurityStandards.enforce | baseline | Profil imposé. Pas restricted, car les services de données intégrés (Postgres, StarRocks, SeaweedFS, Valkey, OPA, Lakekeeper) et les Jobs de migration s'exécutent encore en root, et dans la disposition par défaut à namespace unique, un même niveau PSS les régit en même temps que les applications. Pour imposer restricted, pointez le chart vers des services de données externes ou déplacez les services intégrés dans leur propre namespaces.infra. |
podSecurityStandards.audit / .warn | restricted | Signaler l'écart résiduel sans bloquer. |
podSecurityStandards.labelReleaseNamespace | true | Labelliser le namespace de la release via un Job hook de pré-installation/pré-mise à niveau. Helm possède ce namespace, le chart ne peut donc pas générer d'objet Namespace pour lui — sans cela, activer PSS dans la topologie par défaut (chaque namespaces.* égal au namespace de la release) ne labellisait rien et n'imposait rien. Le ClusterRole du hook est restreint par resourceNames à ce seul namespace, en get/patch uniquement. Mettre false pour le labelliser vous-même ; helm install affiche alors les commandes. |
podDisruptionBudgets.enabled | false | PDB pour les Deployments applicatifs sans état. Désactivés par défaut et générés uniquement pour les Deployments à plus d'un réplica : un PDB sur un Deployment à 1 réplica bloque l'éviction volontaire, ce qui fige kubectl drain, la consolidation de l'autoscaler et les mises à niveau des pools de nœuds managés. À activer conjointement avec replicas > 1. |
podDisruptionBudgets.maxUnavailable | 1 | Ne jamais arrêter plus de N pods applicatifs à la fois. |
Les services de données intégrés sont en pod unique sur des volumes ReadWriteOnce et n'ont
pas de PDB — un PDB transformerait un court redémarrage en drain bloqué sans apporter de
disponibilité. Pour une vraie haute disponibilité, exécutez Postgres, StarRocks, le stockage
objet et le broker en externe (infra.db.external.*, apiTable.starrocks.host, S3/Blob
managé, eventBackbone.broker.managedValkey: false). agentic-realtime est limité à un
réplica tant que la synchronisation de l'éditeur de workflows ou le consommateur realtime
durable est activé, car Socket.IO n'a encore aucun adaptateur de cluster configuré.
Ordonnancement des pods
Les nodeSelector, tolerations et affinity à l'échelle du chart s'appliquent à chaque Deployment, StatefulSet et Job de migration — les pods peuvent ainsi atterrir sur des nœuds dédiés ou marqués avec des teints. Les surcharges par composant ne sont pas exposées.
tolerations:
- { key: workload, operator: Equal, value: scrydon, effect: NoSchedule }
nodeSelector:
workload: scrydon
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- { key: node-role.kubernetes.io/scrydon, operator: Exists }Réduction pour les installations à ressources limitées
Les valeurs par défaut présupposent le cluster minimum (8 vCPU / 40 Go sur au moins deux nœuds). Sur un cluster d'évaluation plus petit, désactivez les composants optionnels les plus lourds. Les trois ci-dessous font passer la mémoire que l'ordonnanceur doit réserver d'environ 24 Gio à environ 14 Gio, ce qui tient dans environ 24 Go de mémoire de nœud :
infra:
starrocks:
enabled: false # 5–8Gi RAM, 20Gi PVC — only Managed Tables + agentic schema-inference affected
apiTable:
enabled: false
analytics:
enabled: false # drops the analytics UI (2 replicas × 1.5Gi) and the marimo-document rendererRecettes de configuration courantes
Personnaliser les chemins de routage
Montez les applications sous des préfixes différents (ex. tout sous /scrydon/...) via routing.paths.* — voir le tableau routing ci-dessus et Modes de routage.
Rendu sans cluster actif (GitOps / hors ligne)
À utiliser chaque fois que le chart est rendu sans connexion au cluster cible —
tout ce qui exécute helm template en coulisse :
- ArgoCD (son moteur de rendu par défaut)
- l'inflateur
helmCharts:de Kustomize helm template … | kubectl apply -f -, le flux hors ligne habituel à travers l'isolementhelm install --dry-run,helm diff
Le HelmRelease de Flux exécute un vrai helm upgrade --install et n'en a pas
besoin. Pas plus qu'un helm install/helm upgrade direct, ni zarf package deploy.
Pourquoi c'est important. Chaque secret géré par le chart se résout ainsi :
Secret actif du cluster → valeur fournie → valeur aléatoire générée. Sans
connexion à l'API, le lookup de Helm ne renvoie rien : la troisième branche
s'exécute et produit une valeur différente à chaque rendu. L'appliquer fait
tourner 38 secrets à chaque synchronisation, et certaines rotations sont
irréversibles :
| Valeur | Effet de sa rotation |
|---|---|
dapr.crypto.masterKey | Racine AES des secrets au repos — chaque identifiant d'intégration stocké devient définitivement indéchiffrable |
infra.lakekeeper.encryptionKey | idem, pour les identifiants de l'entrepôt Iceberg |
auth.secrets.AUTH_SECRET | invalide toutes les sessions et la vérification des clés d'API |
| Clés S3 de SeaweedFS | rend orphelin chaque objet déjà stocké |
infra.db.credentials.password | Non généré ici : le rendu utilise votre valeur telle qu'écrite, ou postgres si elle est vide. Mais Postgres garde le mot de passe avec lequel il a été initialisé : une valeur différente fait échouer chaque connexion à la base et chaque migration. Lisez-la dans secrets-infra avant de la définir |
Que faire. Définissez global.requireExplicitSecrets: true. Chaque branche de
génération devient un échec de rendu qui nomme le chemin exact de la valeur : une
entrée manquante est bruyante au lieu d'être destructrice. Partez de
values.gitops.example.yaml,
qui liste le jeu complet requis et les commandes kubectl pour lire les valeurs
actuelles d'une installation existante avant de l'adopter :
helm template scrydon ./helm/scrydon \
-f helm/scrydon/values.yaml \
-f helm/scrydon/values.gitops.example.yaml \
-n scrydon-platformGénérez chaque valeur une fois, stockez-la dans votre gestionnaire de secrets et
injectez-la au rendu (valuesFrom d'ArgoCD, un overlay déchiffré par sops,
--set-file). Gardez les valeurs stables : en changer une ici la change dans le
cluster. L'exemple livre chaque secret sous la forme
REPLACE-ME-WITH-A-REAL-VALUE-FROM-YOUR-SECRET-STORE, et le rendu échoue, en
nommant le chemin de valeur, tant qu'une valeur est encore ce marqueur.
Sur une installation existante, lisez d'abord les valeurs actuelles (les commandes sont dans ce fichier). En inventer de nouvelles fait tourner les identifiants actifs.
agentic.secrets.ENCRYPTION_KEY doit faire 64 caractères hexadécimaux
(générez-la avec openssl rand -hex 32). Tout autre secret d'au moins 32
caractères fonctionne aussi : api-agentic en dérive une clé. Le chart fait
échouer le rendu sur une valeur plus courte, et api-agentic refuse de démarrer
avec une telle valeur, y compris lorsque vous gérez vous-même le Secret
secrets-agentic. Les espaces en début et en fin autour d'une clé de 64
caractères hexadécimaux, comme un saut de ligne final, sont ignorés. Lors d'une
mise à niveau, le chart conserve toute clé existante que l'application peut
utiliser, la clé ne change donc pas. Seule une clé existante de moins de 32
caractères est remplacée par une clé générée. Ce remplacement invalide les jetons
de test de webhook en cours. Aucune donnée chiffrée stockée n'est affectée.
Installations Dapr existantes
Si le cluster exécute déjà Dapr, mettez dapr.installControlPlane: false pour que le chart ne tente pas de le gérer, et pointez dapr.controlPlaneNamespace vers l'emplacement de Dapr :
dapr:
installControlPlane: false
controlPlaneNamespace: dapr-systemDéfinissez les deux. installControlPlane: false seul laisse le chart supposer que Dapr tourne dans le namespace de la release, et l'installation attend un pod marimo-document dont le sidecar n'arrive pas à joindre dapr-sentry. L'installateur (setup.sh) détecte un plan de contrôle existant et passe les deux options pour vous. Le paquet air-gapped (Zarf) installe toujours son propre Dapr : à côté d'un Dapr existant, son preflight échoue et vous oriente vers --backend mirror, qui le réutilise.
Votre Dapr doit satisfaire trois prérequis, faute de quoi la connexion fonctionne mais la création de compte / les appels inter-services échouent avec PermissionDenied :
| Prérequis | Pourquoi |
|---|---|
| Dapr 1.18.9 (version épinglée et testée par le chart) | Les anciennes versions 1.17.3–1.17.6 émettaient des domaines de confiance SPIFFE de workload incorrects ; s'aligner sur la version du chart évite la dérive due à un plan de contrôle mixte. |
Domaine de confiance scrydon sur dapr-sentry (ou définir dapr.trustDomain en conséquence) | Toutes les ACL en dépendent. |
| Injecteur de sidecar opérationnel | Sans lui, les pods démarrent 1/1 (sans daprd) et l'invocation de service court-circuite. |
kubectl -n <dapr-ns> get deploy dapr-sentry \
-o jsonpath='{.spec.template.spec.containers[0].image}' # expect sentry:1.18.9Injection de sidecar en échec fermé (Dapr intégré uniquement). Le plan de contrôle intégré configure le webhook de l'injecteur avec failurePolicy: Fail, limité aux pods applicatifs Scrydon (label scrydon.io/dapr-mesh). Si l'injecteur est brièvement indisponible — typiquement la première minute d'une nouvelle installation — les pods applicatifs Scrydon sont retenus (événements ReplicaSet FailedCreate mentionnant sidecar-injector.dapr.io) puis admis automatiquement dès qu'il est Ready, au lieu de démarrer silencieusement sans leur sidecar et de casser chaque appel inter-services. Une courte rafale de ces événements pendant l'installation est normale ; n'enquêtez que si elle persiste une fois le pod dapr-sidecar-injector en Running. Un Dapr apporté par vos soins conserve sa propre politique de webhook — la valeur amont par défaut est Ignore, donc le mode de défaillance des pods 1/1 décrit ci-dessous reste possible dans ce cas.
Périphérie avancée : derrière un équilibreur de charge qui termine le TLS
Les configurations App Gateway / ALB / GCP LB / F5 nécessitent un ajustement du contrôleur Traefik (trustedIPs, externalTrafficPolicy: Local, la règle de schéma public gateway.tls.enabled, périphérie privée, dépannage 502). Guide complet : TLS Offloading.
Identifiants StarRocks
Le StarRocks intégré est livré avec root sans mot de passe. Si vous définissez une valeur non vide pour apiTable.secrets.STARROCKS_PASSWORD, le chart l'applique pour vous — un sidecar password-reconciler dans le pod starrocks-fe réconcilie le mot de passe root à chaque démarrage, puis le revérifie une fois par minute : il applique le mot de passe sur un root sans mot de passe, ne fait rien s'il correspond déjà, fait tourner root automatiquement lorsque vous changez la valeur (une annotation de checksum redémarre le pod ; le sidecar change la clé à partir du mot de passe précédent qu'il a enregistré sur le PVC StarRocks), et journalise de manière visible — sans rien écraser — si root a été modifié hors bande. Aucune étape manuelle n'est nécessaire ; laissez la valeur vide pour un root sans mot de passe.
Deux comportements à connaître :
- Le premier démarrage avec mot de passe peut redémarrer
starrocks-feune fois. La vérification de démarrage propre à l'image entre en concurrence avec la toute première application du mot de passe et arrête le conteneur si elle perd ; le mot de passe est déjà persisté à ce moment-là, le démarrage suivant est donc propre. Un redémarrage sur une nouvelle installation est bénin — un CrashLoop ou des redémarrages répétés ne le sont pas. - L'ordre de rotation est géré pour vous. Changer la valeur et exécuter
helm upgraderedémarrestarrocks-fe(le sidecar fait tourner root) etapi-table(le checksum de son secret a changé) — aucunSET PASSWORDmanuel.
Automatique sur les charts qui livrent le sidecar password-reconciler. Les charts v1.3.19–v1.3.21 utilisaient à la place un Job hook starrocks-ensure-password de post-installation/post-mise à niveau — il fonctionnait sur un cluster déjà chaud mais pouvait expirer lors d'une nouvelle installation pendant que l'image StarRocks de plusieurs Go était encore en cours de téléchargement, marquant la release failed et laissant root sans mot de passe (le Job se supprime ensuite lui-même, il n'y a donc rien à inspecter — vérifiez helm status). Les charts antérieurs à v1.3.19 n'appliquaient jamais le mot de passe. Dans les deux cas, appliquez-le manuellement :
NEW_PW="<your-starrocks-password>" # same value as apiTable.secrets.STARROCKS_PASSWORD
# StarRocks runs in the release namespace by default (namespaces.infra → scrydon-platform).
kubectl -n scrydon-platform exec -it deploy/starrocks-fe -- \
mysql -h127.0.0.1 -P9030 -uroot -e "SET PASSWORD FOR 'root'@'%' = PASSWORD('${NEW_PW}');"
kubectl -n scrydon-platform rollout restart deployment/api-tableSi le mot de passe n'atteint jamais StarRocks (chart plus ancien dont le Job hook a échoué, ou étape manuelle omise), api-table reste en 1/2 Running — conteneur Ready plus un sidecar, mais l'application échoue à sa sonde de disponibilité (/api/table/health/ready → 503, "starrocks": false). Il n'entre pas en CrashLoop, le pod semble donc sain au premier coup d'œil. Comme un pod non Ready est retiré des endpoints de son service api-table-dapr, tout service qui appelle api-table via Dapr (api-ontology, par exemple) reçoit ERR_DIRECT_INVOKE: failed to resolve address for api-table-dapr…. Voir Dépannage. (replication_num est automatiquement ramené au nombre de BE actifs, de sorte qu'un StarRocks en pod unique ne fait plus échouer à lui seul le provisionnement des tables.)
Le mot de passe root est stocké dans les métadonnées FE sur le PVC StarRocks : il survit donc aux redémarrages du pod, et le sidecar de réconciliation le revérifie en continu.
Pour apporter votre propre StarRocks à la place :
infra:
starrocks:
enabled: false
apiTable:
starrocks:
host: starrocks-fe.starrocks.svc.cluster.local
user: scrydon
secrets:
STARROCKS_PASSWORD: REPLACE-WITH-STARROCKS-PASSWORDVérifier le déploiement
kubectl get pods -n scrydon-platform # all Running, 2/2 with the Dapr sidecar
kubectl get gatewayclass traefik # ACCEPTED=True
kubectl get gateway -n scrydon-platform # PROGRAMMED=True, and an ADDRESS
kubectl get httproute -A # one per enabled app, Accepted by the Gateway
kubectl get certificates -A # cert-manager Certificates READY=TrueLe cas à examiner de près est une Gateway Programmed dont les listeners ne sont pas
Accepted — kubectl describe gateway gateway-frontdoor -n scrydon-platform affiche un bloc
de conditions par listener.
Les données de licence (niveau, droits, jours avant expiration) apparaissent sous Settings → Organization → License après /setup. Connectez-vous sur https://app.example.com/platform et passez d'une application à l'autre via le sélecteur de produit sans vous reconnecter.
Dépannage
| Symptôme | Cause / solution |
|---|---|
Pods 1/1 (pas 2/2) | Le pod a été admis sans son sidecar daprd — l'injecteur du Dapr BYO ne tourne pas (voir Installations Dapr existantes), ou un chart antérieur à l'échec fermé est entré en concurrence avec l'injecteur lors d'une nouvelle installation. Solution : assurez-vous que dapr-sidecar-injector est Ready, puis faites un kubectl rollout restart des déploiements concernés. |
Pods applicatifs non créés ; les événements ReplicaSet affichent FailedCreate … admission webhook "sidecar-injector.dapr.io" … | L'injecteur intégré est arrêté ou encore en cours de démarrage, et l'injection en échec fermé retient les pods Scrydon (voulu — mieux que des pods sans sidecar). Transitoire pendant l'installation ; si cela persiste, vérifiez le pod dapr-sidecar-injector. |
L'inscription échoue avec PermissionDenied depuis agentic | Mauvais domaine de confiance Dapr. kubectl logs deploy/agentic -n scrydon-platform -c daprd | grep spiffe (ou votre surcharge namespaces.agentic) — les ID doivent être spiffe://scrydon/..., pas spiffe://public/.... Passez Dapr en version ≥ 1.17.7. |
Job de migration CrashLoopBackOff | Sur Postgres BYO, une base de données n'a pas été pré-créée — voir BYO Database → Pré-créer les bases. |
Init:ImagePullBackOff avec insufficient_scope (403) | La carte de portée de votre token ACR manque un dépôt miroir tiers (scrydon/busybox, scrydon/pgvector, scrydon/opa). Envoyez à votre équipe l'erreur exacte + le chemin du dépôt — seule la carte de portée est mise à jour, pas le token. |
| Connexion silencieusement cassée derrière un équilibreur de charge | gateway.tls.enabled laissé à false — mettre à true (voir Gateway). |
Listener de Gateway Accepted=False, reason=PortUnavailable | gateway.listenerPorts.* ne correspond à aucun entryPoint réellement écouté par votre contrôleur. Traefik écoute sur :8000/:8443 dans le conteneur alors que son Service publie 80/443 : le chart utilise donc 8000/8443 par défaut, et un listener sur le port 80 est refusé avec no matching entryPoint for port 80 and protocol HTTP. Une implémentation managée qui écoute sur le port public attend 80/443. Voir Ports des listeners. |
helm install échoue avec gateway.publicAuthRateLimit.enabled=true requires gateway.className=traefik | La limitation de débit ne fait pas partie du canal standard de la Gateway API : elle est attachée comme Middleware Traefik. Mettez la valeur à false et appliquez la limite sur votre propre périphérie, ou utilisez la classe traefik. |
kubectl get gatewayclass ne renvoie rien, ou la Gateway n'obtient jamais d'ADDRESS | Le cluster n'a aucune implémentation Gateway API. Installez-en une (traefik.enabled: true fournit les CRD et la GatewayClass traefik), ou pointez gateway.className vers la classe exploitée par votre équipe plateforme. |
L'HTTPRoute d'une application n'est pas Accepted par la Gateway | L'espace de noms de la route n'est pas dans le sélecteur allowedRoutes de la Gateway — que le chart dérive des espaces de noms des applications activées. Relancez helm upgrade après tout changement de namespaces.* pour que le sélecteur et les routes bougent ensemble. |
api-table bloqué en 1/2 Running (jamais Ready, mais pas de CrashLoop) | L'application échoue à sa porte de disponibilité StarRocks. Vérifiez kubectl -n scrydon-platform exec deploy/api-table -c api-table -- wget -qO- localhost:7500/api/table/health/ready — "starrocks": false signifie que le mot de passe root ne correspond pas. Appliquez-le dans StarRocks (Identifiants StarRocks). Confirmez qu'un nouveau mysql -uroot -p"<pw>" se connecte à svc-starrocks-fe:9030. |
Opérations de jour 2
- Renouveler la licence — collez le fichier de licence renouvelé sous Settings → Organization → License → Update license ; pas de redémarrage. Licences.
- Sauvegarde & restauration — CronJob Postgres intégré (
infra.db.backup) ou votre fournisseur managé. Sauvegarde & Restauration. - Mises à jour — Mises à jour.
- Observabilité — Observabilité.