Aller au contenu

Installation

graal s’installe chez vous, par un chart Helm, dans deux namespaces d’un cluster Kubernetes que vous administrez. Cette page dit ce qu’il faut avoir avant de commencer, ce que la plateforme attend de votre équipe, et quels objets l’installation crée — ou ne crée pas — dans votre cluster.

Élément Précisions
Kubernetes Une distribution qui fournit un contrôleur d’entrée, la gestion des certificats, la synchronisation des secrets et un opérateur PostgreSQL (voir plus bas). Deux namespaces, fournis par votre équipe plateforme. Les pods respectent le profil PSA restricted
PostgreSQL Une base applicative dédiée. Le déploiement de référence utilise un opérateur qui génère lui-même les mots de passe des rôles
Keycloak 26 Un realm par tenant, plus un realm d’administration. Fédération de votre annuaire possible
Un stockage objet S3 MinIO, Ceph RGW ou équivalent : buckets de données et tables Apache Iceberg
Un relais SMTP Invitations, notifications, réinitialisation de mot de passe. Sans lui, ces fonctions se taisent — la plateforme démarre quand même
Un contrôleur d’entrée et un certificat Un seul nom d’hôte suffit pour la console et l’API, qui le partagent
Un registre d’images Celui que vous contrôlez : images de la plateforme et images de runtime (Python, Spark, Jupyter, VS Code)

Le moteur SQL (Trino) et la façade de suivi d’expériences (compatible avec le client MLflow, dont elle implémente un sous-ensemble) sont déployés par la plateforme, pas à fournir.

Une contrainte à connaître sur le registre : le dépôt des images de runtime doit être accessible en tirage anonyme, parce que le namespace d’exécution ne porte aucun Secret — donc aucun secret de tirage. Les images de la plateforme, elles, peuvent venir d’un dépôt privé. Chaque image de runtime est une valeur du chart : changer de registre, c’est changer ces valeurs, sans toucher au code.

L’installation occupe deux namespaces, et la séparation est structurante :

Namespace Ce qui y vit Pourquoi
namespace applicatif console, API, moteur low-code, services de plateforme c’est la zone de confiance de la plateforme
namespace d’exécution les jobs et les espaces de travail des utilisateurs un espace de travail exécute du code d’utilisateur : rien de confidentiel n’y est monté, et il n’y a aucun secret matérialisé

Dans le déploiement de référence ils s’appellent graal et graal-run. C’est cette séparation qui permet de dire qu’un utilisateur qui exécute du code arbitraire ne lit pas les identifiants de la plateforme : ils ne sont pas dans son namespace.

Les images de runtime sont tirées anonymement depuis un dépôt public de votre registre, sans secret de tirage, pour la même raison. Corollaire : rien de confidentiel, et jamais l’image d’un client, dans ce dépôt-là.

C’est volontaire et c’est vérifié au rendu du chart : l’installation ne crée ni ne demande le droit de créer :

  • aucun namespace — un namespace est une frontière réseau et un plafond de ressources : il ne s’auto-déclare pas ;
  • aucun Secret ;
  • aucun objet cluster-scoped : pas de ClusterRole, pas de ClusterRoleBinding, pas de StorageClass, pas de ClusterIssuer ;
  • aucune CRD installée par graal — le déploiement de référence consomme en revanche les ressources personnalisées de quatre familles fournies par votre plateforme : entrée, certificats, secrets et base de données ;
  • aucun Role, RoleBinding, NetworkPolicy, ResourceQuota ni LimitRange : vos garde-fous restent les vôtres, et un locataire qui écrit son propre RBAC n’a pas de plafond visible.

Ce que votre équipe plateforme fournit donc une fois, avant l’installation : les deux namespaces avec leur quota et leur politique réseau, un ServiceAccount d’exécution dans le namespace d’exécution, et une Role namespacée autorisant le planificateur à y créer des pods. Le planificateur ne crée plus ni ServiceAccount, ni RoleBinding, ni secret de tirage par job.

Conséquence pratique : graal ne peut pas s’installer avec un compte cluster-admin par accident, et un audit de vos habilitations n’a pas à faire confiance à notre documentation — le rendu du chart se relit.

Le chart en expose beaucoup ; six familles décident si l’installation fonctionne.

GRAAL_SECRETS_SALT_KEY — obligatoire, à générer une seule fois

Section intitulée « GRAAL_SECRETS_SALT_KEY — obligatoire, à générer une seule fois »

C’est la clé racine du coffre des locataires : les secrets d’un projet (vos identifiants vers vos systèmes) sont chiffrés au repos en base, en AES-256-GCM, avec une clé dérivée de ce sel par HKDF-SHA256 — une clé distincte par locataire, de sorte qu’une valeur copiée d’un locataire à un autre ne s’ouvre pas.

  • Obligatoire : absente, trop courte ou vide, l’API refuse de démarrer en nommant la variable. C’est le seul réglage dont l’absence arrête le démarrage, et c’est délibéré — un repli silencieux sur une clé par défaut serait pire qu’un refus.
  • Définitive : la changer rend illisible tout ce qui a déjà été scellé. La valeur posée à la première installation est celle de toute la vie de l’installation.
  • À générer une seule fois, avant la première installation, par exemple openssl rand -hex 16 (au moins 32 caractères), puis à sauvegarder comme vous sauvegardez une clé de chiffrement de base de données. La perdre équivaut à perdre les secrets des projets.
Variable Rôle
GRAAL_S3_ENDPOINT_INTERNAL Requis pour créer un locataire : l’adresse par laquelle l’API et les pods joignent le stockage. Absente, la création d’un locataire échoue en TENANT_CONFIGURATION_ERROR
GRAAL_S3_ENDPOINT L’URL publique du stockage, celle qui est donnée aux utilisateurs. À défaut, l’adresse interne est réutilisée
GRAAL_S3_TYPE, GRAAL_S3_REGION, GRAAL_S3_PATH_STYLE_ACCESS, GRAAL_S3_SSL Les défauts posés sur chaque locataire

Les deux adresses sont distinctes parce qu’elles le sont presque toujours en vrai : un pod joint le stockage par un nom de service interne, un utilisateur par un nom public.

L’origine par laquelle un pod du namespace d’exécution rejoint l’API. Elle n’a pas de valeur utile par défaut dans un cluster réel, et son absence ne se voit pas à l’écran : les runs échouent, sans message explicite côté interface. À poser explicitement, et à vérifier par un premier run réel plutôt que par la lecture des sondes de santé.

Variable Rôle
GRAAL_KEYCLOAK_URL L’origine publique de Keycloak. L’émetteur attendu des jetons est <origine>/realms/<realm>
GRAAL_KEYCLOAK_AUTH_ENDPOINT_INTERNAL La même, vue depuis un pod
GRAAL_KEYCLOAK_JWKS_ENDPOINT Où télécharger les clés publiques. Ne change pas l’émetteur accepté
GRAAL_KEYCLOAK_ISSUERS La liste des origines acceptées comme émetteur
GRAAL_KEYCLOAK_ADMIN_REALM, GRAAL_KEYCLOAK_ADMIN_CLIENT_ID, GRAAL_KEYCLOAK_ADMIN_USERNAME, GRAAL_KEYCLOAK_ADMIN_PASSWORD Le compte qui provisionne les realms des locataires
GRAAL_KEYCLOAK_UI_CLIENT_ID, GRAAL_KEYCLOAK_UI_REDIRECT_URIS Le client public de la console et ses URI de redirection autorisées
GRAAL_KEYCLOAK_AGENT_CLIENT_ID L’« Application graal » d’un locataire : l’identité des agents MCP

Le point qui coûte le plus de temps : l’origine publique fige l’émetteur (iss) des jetons. Un jeton pris depuis l’extérieur est rejeté à l’intérieur — et inversement — si les deux vues ne désignent pas le même nom d’hôte. C’est pour cela que l’origine publique et l’origine interne sont deux réglages séparés, et que seule la première décide de ce qui est accepté.

L’hôte, le port et la base ne sont pas trois réglages indépendants mais une seule URL. Le mot de passe, dans le déploiement de référence, vient de l’opérateur PostgreSQL et jamais d’un coffre : deux sources de vérité pour le même secret, dont une ignorée en silence, c’est une rotation qui casse l’application sans que rien ne la relie à sa cause.

Attention au mode TLS : certaines distributions PostgreSQL managées refusent toute connexion en clair. Là où la base est gérée, exiger TLS explicitement.

GRAAL_SMTP_HOST, GRAAL_SMTP_PORT, GRAAL_SMTP_USERNAME, GRAAL_SMTP_PASSWORD, GRAAL_SMTP_AUTH, GRAAL_SMTP_STARTTLS.

Le courrier est optionnel : tant qu’il n’est pas configuré, la plateforme fonctionne et l’indicateur de santé du courrier reste éteint plutôt que de déclarer la plateforme malade. Une fonction non configurée ne doit pas rendre l’ensemble rouge.

Dans cet ordre, parce que chaque étape suppose la précédente :

  1. L’API démarre. Si elle refuse, elle nomme la variable qui manque — lire le journal du pod avant de chercher ailleurs.
  2. Un locataire se crée. C’est ce qui met à l’épreuve le stockage objet et le provisionnement Keycloak.
  3. Un utilisateur se connecte à la console par Keycloak. C’est ce qui met à l’épreuve l’origine publique et les URI de redirection.
  4. Un job s’exécute vraiment, et son journal revient. C’est le seul contrôle qui met à l’épreuve le namespace d’exécution, le ServiceAccount fourni, le tirage d’images et GRAAL_API_INTERNAL_URL. Une plateforme dont les sondes sont vertes peut très bien ne jamais exécuter un run : ne pas s’arrêter avant cette étape.