Déployer la messagerie
Exécuter le serveur de messagerie d’une organisation avec le chart Helm Scrydon, du DNS et des secrets jusqu’à la sauvegarde, la restauration et les messages refusés.
L’espace Matrix nécessite un serveur de messagerie
(un homeserver Matrix) pour chaque organisation qui l’utilise. Le chart Helm en exécute
un par organisation, sous les valeurs collaboration. Cette page explique comment
en ajouter un, comment il est sauvegardé et restauré, et ce que voient vos utilisateurs lorsque
la plateforme refuse l’un de leurs messages.
Le homeserver de chaque organisation :
- sert un nom DNS, par exemple
acme.chat.example.com, sur le port 443 de la Gateway de la plateforme ; - connecte les utilisateurs via Scrydon, son unique fournisseur d’identité ;
- ne fédère pas avec d’autres serveurs Matrix ;
- demande à Scrydon d’admettre chaque message et chaque modification de salon avant de les stocker. Lorsque Scrydon refuse, ou est injoignable, l’événement n’est pas stocké.
Prérequis
Le chart refuse de rendre collaboration.enabled: true à moins que toutes
ces conditions soient réunies :
gateway.enabledetgateway.tls.enabled. Les clients Matrix et la découverte de connexion du homeserver fonctionnent uniquement en https.auth.enabled,dapr.enabledetauth.dapr.enabled. Le homeserver n’atteint Scrydon que via Dapr, en TLS mutuel.- Sur le PostgreSQL intégré (
infra.db.enabled: true),cortex.enabled. - Avec les sauvegardes activées (par défaut), un magasin par défaut du déploiement
(
storage.deploymentDefault, ou le SeaweedFS intégré). Définissezcollaboration.backup.enabled: falsepour fonctionner sans sauvegardes planifiées. - Avec au moins une organisation,
auth.replicas: 1(la valeur par défaut). L’API de la plateforme conserve les appareils de lecture des messages et de Cortex de chaque organisation, ainsi que leurs clés chiffrées, sur un seul volume qu’un seul pod peut monter. - Aucune
auth.secrets.DATABASE_URL_COLLABORATION. Le chart refuse cette clé. Si vous mettez à niveau une release qui la définit, déplacez d’abord le DSN, comme décrit dans Apporter votre propre base de données.
Les volumes de données et de médias sont en ReadWriteOnce. Une classe de stockage ReadWriteOncePod
n’est pas prise en charge, car le job de sauvegarde monte les mêmes volumes.
L’API de la plateforme reçoit un volume ReadWriteOnce supplémentaire,
api-platform-matrix-devices (1Gi ; définissez collaboration.devices.storage.size
et .className pour le modifier). Il contient les clés de chiffrement des
appareils de chaque organisation. Sauvegardez-le : les homeservers connaissent
déjà ces appareils, et un volume perdu ne peut pas les recréer. Comme un seul
pod peut le monter, l’API de la plateforme est remplacée plutôt que mise à jour
progressivement lors d’une mise à niveau : elle est donc brièvement
indisponible. Le chart conserve le volume lorsque vous désinstallez la release.
Ajouter une organisation
1. Choisir un nom de serveur et faire pointer le DNS vers la Gateway
Choisissez un nom DNS par organisation. Il devient le nom de serveur Matrix de l’organisation
et apparaît dans chaque ID utilisateur (@alice:acme.chat.example.com) : il
ne peut donc pas être modifié par la suite. Il doit :
- être en minuscules, sans port ;
- ne pas être un nom d’hôte que le chart sert déjà (la plateforme, Cortex et les autres applications) ;
- se résoudre vers l’adresse externe de la Gateway, la même adresse que le nom d’hôte de votre plateforme.
Le chart ajoute à la Gateway un listener HTTPS par organisation, avec son
propre certificat. cert-manager l’émet dans le Secret
tls-collab-<organizationId> (remplacez-le avec tlsSecret, ou partagez
gateway.tls.existingSecret). Si ce certificat provient d’une CA privée,
définissez aussi collaboration.oidcIssuerCa : voir
Homeservers de collaboration derrière une CA privée.
Le listener ne route que l’API client Matrix, les pages de connexion et
/.well-known/matrix/{client,server}. Les chemins de fédération et d’administration
ne sont jamais routés.
2. Générer le Secret de l’organisation
Chaque homeserver lit ses identifiants dans un Secret Kubernetes. Générez-le avec le script du dépôt Scrydon. Il imprime le Secret sur la sortie standard : aucune valeur n’est donc écrite sur le disque.
Le script nécessite un checkout du dépôt source Scrydon et
Bun sur la machine où vous l’exécutez, ainsi qu’un accès kubectl
au namespace de la release. Le chart ne l’inclut pas. Si vous installez à partir du
chart seul, demandez l’accès au dépôt au support Scrydon.
bun packages/matrix-appservice/scripts/new-org-secrets.ts \
--organization-id <organization uuid> \
--server-name acme.chat.example.com \
--registration-id <new uuid> \
--appservice-url http://svc-api-platform.scrydon-platform.svc.cluster.local \
--namespace scrydon-platform \
| kubectl create -f ---registration-idest un nouvel UUID que vous choisissez pour cette organisation. Utilisez la même valeur dans les valeurs du chart.--appservice-urlest l’adresse interne au cluster de l’API de la plateforme dans le namespace de la release.helm templateimprime la valeur exacte sousSCRYDON_COLLABORATION_APPSERVICE_URLdans le Deployment api-platform.--namevaut par défautcollab-<organization id>.- Le Secret contient le secret client avec lequel les utilisateurs se connectent
(
oidc-client-secret). Vous n’enregistrez de client nulle part : au démarrage, la plateforme enregistre le client de connexion du homeserver pour l’organisation (ID clientcollab-<organization id>, URI de redirectionhttps://<serverName>/_continuwuity/oidc/complete). Ce client est une application système : il n’apparaît pas sousSettings → Organization → Registered Appset ne peut pas y être supprimé.
Redirigez la sortie vers kubectl create -f - ou kubectl apply --server-side -f -.
N’utilisez jamais un simple kubectl apply -f - : il copie chaque valeur dans
l’annotation last-applied-configuration, que kubectl describe imprime.
kubectl create refuse aussi d’écraser un Secret existant : exécuter le
script deux fois ne peut donc pas remplacer les identifiants d’un homeserver en fonctionnement.
Un Secret créé par une ancienne version du script peut avoir une clé
oidc-client-secret vide. Les utilisateurs ne peuvent alors pas se connecter à ce
homeserver, et la plateforme journalise Chart Matrix homeserver has no OIDC client secret
au démarrage. Remplissez cette seule clé, puis redémarrez l’API de la plateforme et le homeserver :
bun packages/matrix-appservice/scripts/new-org-secrets.ts --only-key oidc-client-secret \
| kubectl patch secret collab-<organization id> -n scrydon-platform \
--type merge --patch-file /dev/stdin
kubectl -n scrydon-platform rollout restart deploy/api-platform statefulset/collab-<organization id>Ne remplissez qu’une clé vide. Une fois que la plateforme a stocké un secret client,
une autre valeur est refusée avec secret_mismatch.
3. Ajouter l’organisation aux valeurs
collaboration:
enabled: true
organizations:
- organizationId: 7f9c0d2e-… # UUID en minuscules d’une organisation existante
serverName: acme.chat.example.com # étape 1
existingSecret: collab-7f9c0d2e-… # étape 2
registrationId: 5b0f… # étape 2, le même UUID
instanceGeneration: 1 # à incrémenter uniquement après une restauration
# oauthClientId: "" # par défaut collab-<organizationId>
# tlsSecret: "" # par défaut tls-collab-<organizationId>
# storage: { data: 20Gi, media: 50Gi, className: "" }Les ID d’organisation, noms de serveur, ID d’enregistrement et Secrets doivent chacun être uniques. Le chart refuse un doublon. Deux Secrets ne doivent jamais non plus contenir le même identifiant d’admission. La plateforme le vérifie au démarrage et met hors service toutes les organisations qui en partagent un, jusqu’à ce qu’un administrateur corrige la situation.
4. Mettre à niveau la release
Exécutez helm upgrade. L’ajout d’une organisation :
- redémarre l’API de la plateforme, qui enregistre le homeserver de l’organisation, stocke une copie de ses identifiants et enregistre son client de connexion ;
- démarre le pod du homeserver de l’organisation. Le homeserver attend que la plateforme puisse admettre ses événements, puis démarre. Lors d’une première installation, il attend également la migration de la base de données de collaboration ;
- dès que le homeserver répond, la plateforme crée les appareils de l’organisation : celui qui lit ses salons, et Cortex. D’ici là, le chat n’affiche ni salons ni personnes.
Vérifiez qu’il a démarré :
kubectl -n scrydon-platform get pods -l scrydon.io/collaboration-organization=<organization id>
kubectl -n scrydon-platform logs deploy/api-platform | grep "Chart Matrix tenant"Chart Matrix tenant provisioned nomme l’organisation une fois qu’elle est en
service, et Chart Matrix managed devices provisioned une fois ses appareils
créés. Tant que le homeserver est injoignable, le journal affiche
Chart Matrix managed devices could not be provisioned; retrying, et la
plateforme continue d’essayer. La première fois qu’une personne de l’organisation ouvre le chat de
Cortex, la plateforme enregistre Cortex auprès du homeserver et journalise
Chart Matrix homeserver browser client registered. Si le homeserver n’est pas
encore joignable, le chat indique que la messagerie est indisponible, le journal
affiche Chart Matrix homeserver browser client unavailable, et la visite
suivante réessaie.
Les utilisateurs ne cliquent sur rien côté homeserver. Il les envoie directement vers la connexion de la plateforme et approuve Cortex sans page de consentement. Cette approbation ne vaut que pour l’adresse du chat de Cortex, celle que la plateforme a enregistrée.
Chart Matrix tenant refused indique une reason :
| Raison | Signification | Que faire |
|---|---|---|
secret_missing | Le Secret n’existe pas, ou l’une de ses clés est absente ou mal formée. | Créez ou corrigez le Secret, puis redémarrez l’API de la plateforme. |
secret_mismatch | Les valeurs du Secret diffèrent de la copie que la plateforme a stockée précédemment. Rien n’est modifié. | Contactez le support Scrydon. Ne régénérez pas le Secret : la base de données du homeserver a été construite avec les valeurs stockées. |
credential_shared | Le Secret d’une autre organisation contient le même identifiant d’admission. Toutes les organisations concernées sont mises hors service. | Contactez le support Scrydon. |
credential_unreadable | L’identifiant d’admission est monté mais illisible : son unicité ne peut donc pas être prouvée. L’organisation est mise hors service. | Contactez le support Scrydon. |
invalid_entry | L’entrée des valeurs est mal formée. | Corrigez l’entrée. |
oauth_client_conflict | Une autre organisation possède déjà un client OAuth avec l’oauthClientId de cette entrée. Rien n’est modifié. | Retirez oauthClientId de l’entrée, ou choisissez-en un inutilisé. |
ensure_failed | L’enregistrement n’a pas encore pu être écrit, généralement parce que la migration n’est pas terminée. | Rien. La plateforme réessaie jusqu’à réussir. |
Sauvegarde
Chaque organisation dispose d’un CronJob nocturne, collab-<organization id>-backup.
Il est activé par défaut. Configurez-le sous collaboration.backup :
| Valeur | Défaut | Signification |
|---|---|---|
enabled | true | Nécessite un magasin par défaut du déploiement. |
schedule | "17 3 * * *" | Doit s’exécuter au moins une fois par jour. Le chart refuse une planification moins fréquente. |
activeDeadlineSeconds | 3600 | Au plus 3600. |
retain | 14 | Sauvegardes complètes conservées par organisation. Minimum 1. |
Chaque exécution réalise une sauvegarde en ligne de la base de données du homeserver, puis la copie, avec le volume de médias, vers le magasin par défaut du déploiement sous :
operator/00_organization/collaboration/<organizationId>/<YYYYMMDDTHHMMSSZ>/
database/…
media/…
manifest.jsonLe répertoire lost+found propre au système de fichiers, à la racine du volume de médias,
n’est pas copié : il ne contient rien que le serveur de messagerie ait écrit.
manifest.json est écrit en dernier. Il liste chaque objet de l’exécution avec
sa taille et son SHA-256. Une exécution sans manifest.json est incomplète (l’exécution
s’est arrêtée en cours de route) et ne doit pas être restaurée. La rétention ne la compte jamais comme une
copie conservée.
Une sauvegarde est une copie complète du serveur de messagerie de l’organisation. Restreignez l’accès au magasin en conséquence.
Le chart n’inclut aucune règle d’alerte. Construisez les vôtres à partir de trois métriques, que le
job de sauvegarde et l’API de la plateforme exportent via OTLP
(observability.otlpHttpEndpoint), chacune étiquetée avec organization_id :
| Métrique | Signification |
|---|---|
scrydon_collaboration_backup_failures_total | Compte les exécutions de sauvegarde en échec. |
scrydon_collaboration_backup_successes_total | Compte les exécutions de sauvegarde terminées. |
scrydon_collaboration_backup_expected | 1 pour chaque organisation dont le homeserver doit être sauvegardé. Exportée par l’API de la plateforme. |
Nous recommandons deux alertes :
- Sauvegarde en échec : le compteur d’échecs a augmenté.
- Sauvegarde périmée : une organisation est attendue (
scrydon_collaboration_backup_expectedvaut1maintenant et valait1il y a 27 heures), et son compteur de réussites n’a pas augmenté au cours des 27 dernières heures. Cela détecte aussi une exécution qui ne rend jamais compte, comme un pod tué ou jamais planifié. Elle nécessite les métriques de l’API de la plateforme : elle ne peut donc pas se déclencher tant que celles-ci ne sont pas exportées.
Pour réaliser une sauvegarde maintenant :
kubectl -n scrydon-platform create job \
--from=cronjob/collab-<organization id>-backup collab-<organization id>-backup-manualConservation des tours d’agent
Les réponses d’agent dans les salons de messagerie sont conservées pendant la
durée de conservation des conversations de l’organisation, 180 jours par
défaut, puis supprimées avec leurs fichiers de réponse et de progression
stockés. Un salon ou une organisation sous conservation légale est conservé.
Le chart planifie la suppression toutes les heures ; configurez-la sous
collaboration.turnRetention :
| Valeur | Défaut | Signification |
|---|---|---|
enabled | true | false conserve chaque tour d’agent indéfiniment. |
schedule | @every 1h | Fréquence d’exécution de la suppression. |
Chaque suppression est enregistrée dans le journal d’audit de l’organisation avant toute suppression. Une organisation dont le paramètre de conservation ne peut pas être lu est ignorée, jamais supprimée selon la valeur par défaut.
Restauration
La restauration est une procédure manuelle. Elle remplace le homeserver de l’organisation par l’état d’une sauvegarde. Les messages envoyés après cette sauvegarde sont perdus.
Contactez le support Scrydon avant de restaurer un homeserver de production. Ces étapes suivent la procédure de restauration du homeserver amont, et la restauration d’une sauvegarde du chart n’est pas encore couverte par un test automatisé.
-
Choisir une exécution complète. Choisissez un préfixe d’exécution qui comporte un
manifest.json. Téléchargez le préfixe entier, puis vérifiez chaque objet par rapport au manifeste :bashjq -r '.objects[] | "\(.sha256) \(.key)"' manifest.json | sha256sum -c -Arrêtez-vous si un objet est absent ou échoue à la vérification.
-
Arrêter le homeserver et ses sauvegardes.
kubectl -n scrydon-platform scale statefulset/collab-<organization id> --replicas=0, puis suspendez le CronJob de sauvegarde, qui monte les mêmes volumes :kubectl -n scrydon-platform patch cronjob collab-<organization id>-backup -p '{"spec":{"suspend":true}}' -
Reconstruire la base de données. Montez le claim
data-collab-<organization id>-0dans un pod de maintenance. Déplacez de côté les fichiers actuels de la base de données (tout ce qui se trouve à la racine du volume, saufbackups/). Suivez ensuite la restauration de sauvegarde en ligne amont avec les objetsdatabase/de l’exécution : copiez chaqueshared_checksum/<id>_….sstvers<id>.sstà la racine du volume, puis copiez-y également le contenu deprivate/<n>/. -
Restaurer les médias. Copiez les objets
media/de l’exécution dans le claimmedia-collab-<organization id>-0, en remplaçant son contenu. -
Incrémenter
instanceGenerationpour l’organisation dans vos valeurs, puis exécutezhelm upgrade. La mise à niveau ramène le StatefulSet à une réplique : cette étape démarre donc le homeserver sur les données restaurées. -
Vérifier le homeserver. Confirmez que le pod devient Ready, puis réactivez le CronJob de sauvegarde (
"suspend":false) et réalisez une sauvegarde immédiate, comme ci-dessus.
Ne supprimez pas les claims pour repartir de zéro une fois que l’organisation a de vraies conversations. Ils sont la seule copie en dehors de vos sauvegardes.
Lorsqu’un message est refusé
La plateforme n’admet un message ou une modification de salon que si toutes ces conditions sont réunies :
- le homeserver correspond à une organisation en service ;
- l’expéditeur est membre du salon, sur le serveur propre à cette organisation ;
- le salon porte une classification lisible ;
- l’habilitation de l’expéditeur couvre la classification du salon, ainsi que toute nouvelle classification que l’expéditeur définit.
Les agents et les comptes de service propres à Scrydon sont vérifiés pour l’appartenance et la classification, mais pas pour l’habilitation : leur sortie est conçue pour être vérifiée par rapport à la classification du salon avant d’être envoyée.
Lorsqu’une condition échoue, ou que la plateforme ne peut pas trancher, l’événement est refusé. L’expéditeur voit Message could not be sent avec Try again à côté du message. La raison n’est pas montrée à l’expéditeur. Un message refusé n’est jamais renvoyé automatiquement : seule une défaillance réseau l’est. Réessayer est refusé de la même façon tant que la cause ne change pas, par exemple tant qu’une habilitation n’est pas accordée.
Chaque refus enregistre un événement collaboration.admission.denied dans le
journal d’audit (Settings → Platform → Audit Log). La
ressource de l’événement est le salon, et ses détails portent le code de refus,
l’expéditeur, le type d’événement et le nom du serveur :
| Code | Signification |
|---|---|
POLICY_SENDER_NOT_MEMBER | L’expéditeur n’est pas membre du salon, ou n’est pas un utilisateur du serveur de cette organisation. |
POLICY_CLASSIFICATION_DOMINATED | L’habilitation de l’expéditeur ne couvre pas la classification du salon, ou la classification que l’expéditeur a tenté de définir. |
POLICY_BINDING_INVALID | Le salon n’a pas encore de classification, sa classification est illisible, ou la nouvelle classification est mal formée. |
POLICY_WORKSPACE_BINDING_RESERVED | Quelqu’un d’autre que la plateforme a tenté de définir ou d’effacer l’espace de travail d’un salon. Seule la plateforme le définit. |
POLICY_TENANT_UNKNOWN | Le homeserver n’a pas pu être associé à une organisation en service. |
POLICY_UNAVAILABLE | La plateforme n’a pas pu trancher. Rien n’est stocké tant qu’elle ne le peut pas. |
Un refus que la plateforme n’a pas pu associer à une organisation est enregistré en dehors du journal d’audit de toute organisation : le homeserver d’une organisation ne peut donc jamais écrire dans celui d’une autre.