Migrations de base de données
Comment les migrations de schéma sont appliquées lors des mises à jour Scrydon — ce qui s'exécute, comment vérifier et comment gérer les échecs.
Chaque mise à jour Scrydon peut inclure des migrations de base de données. Ce runbook couvre ce qui s'exécute, comment vérifier et comment gérer une migration échouée.
Fonctionnement des migrations
Chaque base de données a exactement un Job de migration, et le chart Helm l'exécute pour vous :
| Job | Base | Contenu |
|---|---|---|
auth-migration | auth | Utilisateurs, organisations, espaces de travail, journal d'audit, configuration de la plateforme dont la licence |
events-migration | events | Le backbone d'événements : flux d'événements, points de reprise des consommateurs, tâches de rejeu |
agentic-migration | agentic | Workflows, automatisations, bases de connaissances, publications A2A |
analytics-migration | analytics | Catalogue des tables gérées, profils, bundles de politiques |
cortex-migration | cortex | Conversations, messages, tables et tâches planifiées de Cortex |
api-ontology-migration | ontology | Schéma d'ontologie, liaisons, branches |
collaboration-migration | collaboration | Métadonnées de collaboration Matrix détenues par API Platform (uniquement avec collaboration.enabled) |
La base lakekeeper appartient au catalogue Iceberg intégré, qui migre son propre schéma au démarrage.
Lors d'une mise à jour, chaque Job s'exécute comme hook pre-upgrade, nommé <job>-<revision>, avant le démarrage de tout nouveau pod ; Mises à jour donne l'ordre. Lors de la première installation, chaque Job s'exécute comme Job ordinaire, sans hook, nommé <service>-bootstrap-1, afin qu'aucun schéma n'attende qu'une charge de travail soit Ready. Le Job du schéma de collaboration garde son nom, collaboration-migration-1.
Avec collaboration.enabled, collaboration-migration-1 est un Job ordinaire lors de la première installation, car les homeservers ne deviennent Ready qu'une fois leurs organisations provisionnées par API Platform sur son schéma : un hook post-install ne s'exécute qu'après que helm install --wait (ou un déploiement Zarf) a vu tous les pods Ready, il ne s'exécuterait donc jamais. Sur le PostgreSQL intégré, le premier démarrage de la base crée aussi les rôles scrydon_tenant et scrydon_system qu'exige le Job. API Platform peut démarrer avant que le Job ait créé le schéma collaboration. Il ne l'attend pas : il relance le provisionnement des organisations de collaboration avec un délai croissant et les provisionne dès que le Job se termine, sans redémarrage. Il n'abandonne jamais : une fois le délai arrivé à cinq minutes, il continue de réessayer toutes les cinq minutes tant que le schéma est absent. Il suffit donc de corriger et de relancer le Job, sans redémarrer API Platform. Tant qu'une organisation continue d'échouer, API Platform journalise Chart Matrix tenant still refused ensure_failed; retrying au plus une fois par heure pour elle.
Les migrations sont conçues pour être unidirectionnelles. Aucune migration inverse n'est fournie ; si vous devez revenir en arrière, restaurez depuis une sauvegarde.
Ce que fait une migration
Les migrations consistent généralement à :
- Ajouter une nouvelle colonne (
ADD COLUMN ... NULL). - Remplir des données dérivées en arrière-plan.
- Ajouter un index en mode
CONCURRENTLY. - Déprécier doucement une colonne (renommée, puis lue depuis la nouvelle + l'ancienne, puis lue uniquement depuis la nouvelle, puis supprimée).
Les migrations qui bloqueraient les écritures pendant plus de quelques secondes sont découpées en plusieurs versions — la plateforme ne livre jamais une migration unique qui verrouille toute la table sur une grande table.
Le retrait d'un produit annoncé explicitement peut supprimer une table après l'étape d'export requise pour l'opérateur. Traitez ces migrations comme des exceptions au modèle de déploiement additif habituel et suivez leur procédure propre à la version.
Retrait de l'ancien chat public Agentic
La migration 0102_remove_legacy_chat supprime la table retirée public.chat. Avant l'exécution du Job de migration, consignez le nombre de lignes et créez un export de données protégé :
psql "<agentic-database-url>" \
-c 'SELECT count(*) AS legacy_chat_rows FROM public.chat;'
pg_dump "<agentic-database-url>" \
--data-only --table=public.chat --column-inserts \
> legacy-agentic-chat.sqlTraitez l'export comme une donnée sensible. Les lignes historiques peuvent contenir une configuration d'accès, des adresses e-mail autorisées et des hachages de mots de passe. Chiffrez-le, restreignez et auditez les accès, puis appliquez votre politique de rétention approuvée.
Cet export facilite l'inventaire et l'archivage contrôlé ; ce n'est pas une migration inverse. Le point de restauration pris en charge est un snapshot complet de la base de données Agentic réalisé avant la mise à niveau. La migration est un hook pré-mise à jour : un rollback Helm après sa réussite ne recrée pas la table, et l'ancienne application Agentic ne peut pas servir ses routes publiques de chat avec le nouveau schéma. Restaurez ensemble le snapshot complet et la révision précédente de l'application si un retour arrière complet est nécessaire.
Cette version supprime également le type de bloc de workflow hérité et masqué
chat_trigger. Inventoriez les définitions de workflow avant la mise à niveau :
psql "<agentic-database-url>" \
-c "SELECT count(*) AS legacy_chat_trigger_blocks, count(DISTINCT workflow_id) AS affected_workflows FROM public.workflow_blocks WHERE type = 'chat_trigger';"Si l'un des nombres est différent de zéro, remplacez chaque bloc hérité par le
bloc Start unifié et redéployez le workflow avant la mise à niveau. Ne modifiez
pas directement le type du bloc dans PostgreSQL : les versions de déploiement
immuables et les instantanés d'exécution peuvent contenir des copies distinctes
de la définition du workflow. Après la mise à niveau, Agentic traite
chat_trigger comme un bloc retiré inconnu et le supprime lors de la
sanitisation du workflow.
Le retrait n'affecte pas les tables de conversation Cortex, les publications A2A, les checkpoints de workflow, les retours du copilote ni l'état des conversations de l'éditeur de workflow.
Retrait des publications de formulaire
0141_drop_form_publication supprime public.form_publication et l'enum form_auth_type. Elle exécute DROP TABLE sans CASCADE, volontairement : un objet à vous qui dépend de la table arrête la mise à niveau au lieu d'être supprimé silencieusement. Les deux instructions utilisent IF EXISTS : appliquer de nouveau la migration ne change rien.
Faites l'inventaire des objets dépendants avant la mise à niveau. La requête liste tous les objets qui dépendent de la table ou de son enum : vues, clés étrangères, colonnes (tableaux compris), domaines, fonctions et contraintes. Chaque ligne est la description de l'objet, par exemple column a of table c2 ou rule _RETURN on view v, c'est-à-dire ce que vous supprimez :
SELECT DISTINCT pg_describe_object(d.classid, d.objid, d.objsubid) AS dependent_object
FROM pg_depend d
WHERE d.deptype = 'n'
AND ((d.refclassid = 'pg_class'::regclass AND d.refobjid = to_regclass('public.form_publication'))
OR (d.refclassid = 'pg_type'::regclass AND d.refobjid IN (to_regtype('public.form_auth_type'), to_regtype('public.form_auth_type[]'))))
AND NOT (d.classid = 'pg_class'::regclass AND d.objid = to_regclass('public.form_publication'))
AND NOT (d.classid = 'pg_attrdef'::regclass AND d.objid IN (SELECT oid FROM pg_attrdef WHERE adrelid = to_regclass('public.form_publication')));Aucune ligne signifie que la migration s'appliquera. Sur une base qui n'a plus la table, la requête renvoie aussi zéro ligne, sans erreur. Exportez d'abord les lignes ; Mises à jour → Supprimé : publications de formulaire donne les commandes.
Vérifier qu'une migration a été exécutée
Chaque base enregistre ses migrations appliquées dans drizzle.__drizzle_migrations. Sur le PostgreSQL intégré, listez les cinq plus récentes d'une base :
kubectl exec -it deploy/db -n scrydon-platform -- \
psql -U postgres -d auth \
-c "SELECT id, hash, to_timestamp(created_at / 1000) AS applied_at FROM drizzle.__drizzle_migrations ORDER BY id DESC LIMIT 5;"Remplacez auth par events, agentic, analytics, cortex ou ontology pour les autres. Avec une base externe, exécutez la même requête avec psql sur l'URL de cette base.
Gestion d'un échec de migration
Si une migration échoue, son Job échoue, helm upgrade signale la release comme failed et la version précédente continue de servir le trafic. L'erreur se trouve dans les journaux du Job :
kubectl get jobs -n scrydon-platform | grep -E 'migration|bootstrap'
kubectl logs job/<job-name> -n scrydon-platformLors d'une première installation, un pod qui a besoin du schéma reste en Init ou NotReady jusqu'à la réussite du Job.
Ne relancez pas à l'aveugle, et ne modifiez jamais drizzle.__drizzle_migrations à la main. Marquer comme appliquée une migration qui ne l'est pas fait tourner toutes les migrations suivantes sur un schéma qu'elles n'attendent pas. Lisez d'abord l'erreur.
Choisissez ensuite l'un de ces trois chemins :
- L'erreur désigne une précondition sur les données. Certaines migrations vérifient d'abord vos données et s'arrêtent avec un message qui indique quoi corriger. Corrigez les données, puis relancez le même
helm upgrade. La tentative suivante remplace le Job en échec par un nouveau. - L'erreur est la désynchronisation du suivi ci-dessous. Suivez Désynchronisation du suivi des migrations.
- Tout autre cas. Restaurez les bases depuis le snapshot pris avant la mise à jour, revenez en arrière avec
helm rollbacket envoyez les journaux du Job au support Scrydon.
Prenez toujours un snapshot PostgreSQL avant de démarrer une mise à jour. Le runbook de mise à jour le précise explicitement.
Désynchronisation du suivi des migrations
La tâche de migration vérifie sa table de suivi par rapport au schéma réel de la base de données à chaque exécution. Si la table de suivi prétend que des migrations sont appliquées alors que leurs objets n'existent pas, la tâche échoue avec :
[migrate-bootstrap] FATAL: the migration tracking table is out of sync with
the actual database schema — it claims migrations are applied whose objects
do not exist. This is a tracking desync, not a migration bug.Lorsque le message propose MIGRATE_REPAIR_TRACKING=1 (« Re-run with MIGRATE_REPAIR_TRACKING=1 to rewind tracking from ... »), l'état est réparable automatiquement de manière prouvée : les migrations concernées n'ont laissé aucun objet derrière elles, donc les ré-appliquer ne peut pas entrer en conflit avec des données existantes. Activez la réparation via l'indicateur de values du service concerné :
# surcharge de values pour le service concerné uniquement : auth, agentic,
# analytics, cortex ou apiOntology (events n'a pas d'indicateur de réparation)
analytics:
migration:
repairTracking: trueRelancez ensuite helm upgrade. La tâche de migration rembobine les lignes faussement suivies et ré-applique les migrations dans l'ordre.
repairTracking est un indicateur à usage unique, de dernier recours. Activez-le uniquement pour la mise à jour de réparation, confirmez que la tâche de migration réussit, puis remettez-le à false. Le laisser activé en permanence réduit au silence un contrôle de sécurité qui existe pour détecter bruyamment la dérive base de données/schéma.
Si le message d'échec signale au contraire un état partiel ou non contigu, la réparation automatique refuse de s'exécuter par conception — contactez le support avant de toucher manuellement à la table de suivi.
Ce que helm upgrade ne touche pas
helm upgrade orchestre les Jobs de migration et le déploiement des workloads. Cela signifie que :
- Un rollback Helm ne désapplique pas les migrations.
- Un déploiement échoué peut déjà avoir appliqué ses migrations pré-mise à jour.
- Le propriétaire du schéma et son historique de migrations restent propres au service, même si Helm lance les Jobs.
Migrations jamais exécutées lors d'une nouvelle installation
Lors d'une première installation, les migrations de chaque service s'exécutent dans un Job ordinaire, et non dans un hook Helm : auth-bootstrap-1, events-bootstrap-1, agentic-bootstrap-1, analytics-bootstrap-1, cortex-bootstrap-1 et api-ontology-bootstrap-1. Aucun n'attend qu'une charge de travail soit Ready : un Deployment lent ou en échec ne peut donc pas retenir un schéma. Installez avec --wait --wait-for-jobs et Helm fait aussi échouer la release lorsqu'un Job de bootstrap épuise ses tentatives. En cas d'échec, les services qui lisent sa base restent non prêts ; inspectez directement le Job :
kubectl get jobs -A -l 'app in (auth-bootstrap,events-bootstrap,agentic-bootstrap,analytics-bootstrap,cortex-bootstrap,api-ontology-bootstrap)'
kubectl -n <ns> logs job/<service>-bootstrap-1Jusqu'au chart 1.3.25 inclus, les migrations d'agentic, d'analytics, de
cortex et d'ontology étaient des hooks post-install. Helm ne les exécute
qu'une fois chaque charge de travail Ready ; or depuis la 1.3.25, la
disponibilité du service d'ingestion dépend du schéma analytics. Une première
installation avec --wait ne pouvait donc jamais aboutir, et ces hooks ne
s'exécutaient jamais. Les journaux affichent alors relation "…" does not exist. Passez à un chart plus récent, ou récupérez comme ci-dessous.
Confirmez que le schéma manque :
kubectl -n <ns> exec deploy/db -c postgres -- psql -U postgres -d auth -c '\dt' | head
# "Did not find any tables." => les migrations n'ont jamais tournéRécupérez. Corrigez d'abord ce qui empêchait un pod de devenir prêt (consultez Dépannage de l'installation). Relancez ensuite les migrations de l'une de ces deux façons :
-
Via Helm (de préférence). Le hook de migration est
pre-upgradeet s'exécute avant l'attente de disponibilité : il se termine même si un service lent n'est pas encore stabilisé.bashhelm -n <ns> upgrade <release> <chart> --reuse-values -
À la main (si vous ne pouvez pas lancer
helm upgrade). Les Jobs de bootstrap se trouvent danshelm get manifest; sur une release 1.3.25 ou antérieure, les migrations d'agentic, d'analytics, de cortex et d'ontology se trouvent plutôt danshelm get hooks. Extrayez uniquement les manifestes des Jobs concernés et appliquez-les comme Jobs ordinaires :bashhelm -n <ns> get manifest <release> > /tmp/manifest.yaml helm -n <ns> get hooks <release> > /tmp/hooks.yaml # extraire les Jobs *-bootstrap-* concernés (ou, en 1.3.25 et avant, *-migration-*), puis : kubectl -n <ns> apply -f /tmp/migrations.yaml kubectl -n <ns> wait --for=condition=complete job/<job-name> --timeout=300s
Les Jobs sont idempotents : sur une base vierge ils appliquent toutes les migrations depuis le début, et ne font plus rien une fois le schéma présent.
Associé
-
Dépannage de l'installation — échecs de première installation et récupération.
-
Runbook de mise à jour — procédure complète de mise à jour.
-
Sauvegarde et restauration — le chemin de retour en arrière.