Revenir au contenu principal
Industries

Branchage Lakebase pour la CI/CD : les leçons tirées de 100 bases de données PR

Le branching par copie sur écriture (copy-on-write) rend la création de copies isolées de données de production rapide et économique pour les tests CI/CD et les cas d'usage d'agents.

par Yasamin Tari et Kartik Mathur

  • Le pipeline CI/CD de Snorkel AI attribue à chaque pull request ouverte sa propre branche Lakebase Postgres, une copie complète en lecture/écriture des données de production prête en moins d'une minute au lieu de plus de 30 minutes, ce qui les empêchait auparavant d'activer une copie par PR.
  • Les branches Lakebase utilisent la copie sur écriture (copy-on-write), de sorte que 100 bases de données de PR simultanées sur un ensemble de données de production d'environ 2,5 To n'ajoutent du stockage que pour les données modifiées par chaque branche. L'expiration des branches (TTL) nettoie automatiquement chaque branche une fois sa PR terminée, ce qui permet de maintenir le stockage proche de la taille de la production augmentée des modifications des PR actives.
  • La connectivité privée et la prise en charge d'Okta SSO garantissent un environnement sécurisé et gouverné

Le problème : tester avec des données de production ne devrait pas prendre plus de 30 minutes

Snorkel AI crée des outils de développement de données pour les équipes d'IA, utilisés par des annotateurs de données experts et des fournisseurs de modèles de pointe. Dans ce cas d'usage spécifique, Snorkel déploie du code via un pipeline CI construit sur Kubernetes. Chaque pull request ouverte, ainsi que les commits ad hoc, disposent de leur propre namespace Kubernetes éphémère (un « namespace PR »). Les développeurs y déploient leur branche et exécutent la suite de tests complète avant la fusion.

Ces tests sont plus utiles lorsqu'ils s'exécutent sur de vraies données. La base de données de production de Snorkel est un cluster Amazon Aurora PostgreSQL. Fournir à chaque namespace PR sa propre copie de cette base de données était la partie difficile. Restaurer une copie prenait environ 20 minutes par environnement, ce qui est trop lent lorsque les développeurs ouvrent des PR toute la journée et que la file d'attente de fusion a besoin d'un nouvel environnement pour chaque exécution. Les alternatives (bases de données de staging partagées, fixtures réduites ou données synthétiques) recréent les problèmes que les tests de type production sont censés résoudre : des tests qui interfèrent les uns avec les autres, des schémas obsolètes et des bugs qui n'apparaissent qu'avec de vraies formes de données.

Critères de réussite

Snorkel considérerait Lakebase comme un succès pour la CI/CD s'il répondait à ces critères :

  • Mise en service rapide : Une nouvelle branche PR est prête en moins de 60 secondes (p95).
  • Échelle : Environ 100 branches PR simultanées au pic, chacune avec des lectures et des écritures indépendantes.
  • Compatibilité : L'application existante et la suite CI s'exécutent sur Lakebase via Postgres standard, avec des performances comparables à Aurora et un support pour les grandes colonnes JSONB/LOB.
  • Données fraîches : La branche principale reste à environ 2 minutes de la production Aurora grâce à une réplication DMS continue.
  • Sécurité : Les données de production restent sur un réseau privé et ne traversent jamais l'internet public, les développeurs se connectent avec Okta SSO, les pipelines CI s'authentifient en tant que principaux de service.

Pourquoi le branching de base de données s'adapte à la CI/CD

Lakebase est la base de données Postgres serverless de Databricks. Son stockage et son calcul sont séparés, et elle prend en charge le branching : vous pouvez créer une nouvelle branche isolée et inscriptible d'une base de données à partir de n'importe quel point dans le temps, de la même manière que vous créez une branche Git.

Les branches sont en copy-on-write. La création d'une branche est une opération de métadonnées, donc aucune donnée n'est copiée lors de sa création. Une nouvelle branche partage des pages de stockage avec son parent, et seules les pages modifiées par la branche sont écrites comme nouveau stockage. Pour la CI, cela signifie :

  • Créer une branche prend des secondes, pas des minutes. Cela ne dépend pas de la taille de la base de données.
  • Le stockage augmente avec les modifications apportées par chaque branche, et non avec la taille de la base de données. Chacune des branches PR de Snorkel écrit environ 5 à 10 Go de modifications par rapport à une base de ~1 To.
  • Le calcul est par branche et s'adapte à zéro. Chaque branche possède son propre calcul à mise à l'échelle automatique, qui descend à zéro entre les exécutions de CI. Même avec 100 branches provisionnées, Snorkel s'attend à ce que seulement 20 à 30 environ gèrent du trafic en même temps, à environ 5 requêtes par seconde chacune au pic.

L'architecture

image1.png

1. Conserver une copie fraîche de la production sur la branche principale. Lakebase est du Postgres standard, il fonctionne donc comme cible pour AWS DMS sans outils personnalisés. Snorkel pointe une tâche DMS vers sa base de données Aurora de production et la réplique dans la branche principale du projet Lakebase : un chargement complet d'abord, puis une capture continue des données modifiées qui maintient la branche principale à environ 2 minutes de la production. Le mode LOB complet reporte les valeurs JSONB de 10 à 20 Mo. L'équipe exécute déjà DMS, il n'y avait donc aucun nouveau pipeline de réplication à construire ou à maintenir. La branche principale est la « copie dorée » à partir de laquelle chaque branche PR démarre.

2. Créer une branche lorsqu'une PR s'ouvre. Lorsqu'un développeur ouvre une PR, le pipeline CI appelle l'API Lakebase pour créer une branche à partir de la principale, définit un temps d'expiration sur celle-ci et transmet les détails de connexion de la branche au namespace PR. La branche est prête en moins d'une minute.

3. Exécuter les tests sur de vraies données. L'application dans le namespace PR se connecte à sa branche via Postgres standard. Les tests peuvent exécuter des migrations, écrire des données et modifier des schémas sans affecter la production, la branche principale ou toute autre PR.

4. Supprimer la branche lorsque la PR se ferme ou que le test réussit, avec un TTL comme filet de sécurité. Lorsque la PR est fusionnée ou fermée, le pipeline supprime la branche. Si cette étape de nettoyage ne s'exécute pas, la branche expire d'elle-même lorsque son TTL prend fin.

Sécurité : réseau privé et identité pour les humains et les pipelines

Deux exigences de sécurité ont exclu les autres options, elles méritent donc leur propre section.

Connectivité privée. Les données de production se déplacent d'Aurora vers Lakebase, et de Lakebase vers le cluster CI, via un réseau privé au lieu de l'internet public.

Identité. Snorkel a deux types d'utilisateurs de base de données : les développeurs qui se connectent de manière interactive pour déboguer un environnement PR, et les pipelines CI qui s'exécutent sans intervention humaine. Okta SSO est conçu autour de la connexion interactive par navigateur, nous avons donc divisé la conception par type d'utilisateur :

  • Développeurs : Okta est fédéré au compte Databricks, et les utilisateurs sont provisionnés via SCIM. Les développeurs se connectent avec leur identité Okta habituelle.
  • Pipelines CI : Chaque namespace PR s'exécute en tant que principal de service Databricks (délimité par équipe ou par dépôt), également provisionné via SCIM. Le pod PR utilise les identifiants du principal de service pour obtenir des jetons OAuth Lakebase à courte durée de vie via le SDK Databricks, et les rafraîchit lors de longs tests. Il n'y a pas de mots de passe de base de données à longue durée de vie dans la CI.
  • Audit : Les journaux d'audit Postgres enregistrent l'identité du principal de service pour chaque requête, de sorte que chaque requête peut être tracée jusqu'au pipeline qui l'a exécutée.

Pourquoi le copy-on-write et l'expiration des branches gardent la CI rapide et économique

Deux fonctionnalités de Lakebase permettent à ce modèle de fonctionner à grande échelle : le branching en copy-on-write et l'expiration des branches (TTL).

image3.png

Le copy-on-write rend les branches instantanées. Une nouvelle branche ne copie aucune donnée. Elle pointe vers les pages de stockage existantes de son parent, et seules les pages modifiées par la branche sont écrites comme nouveau stockage. Créer une branche à partir d'une copie de production de ~1 To prend à peu près autant de temps que d'en créer une à partir d'une base de données de 1 Go : des secondes, et non les ~20 minutes qu'une restauration complète prenait. Chaque namespace PR obtient immédiatement sa propre copie de production isolée et inscriptible.

Le copy-on-write rend les branches économiques. Chaque branche partage la plupart de ses données avec la branche principale, de sorte que le stockage grandit avec les modifications apportées par chaque branche, et non avec la taille de la base de données. Pour Snorkel, cela représente environ 5 à 10 Go par branche PR en plus de la base partagée. Le calcul est par branche et s'adapte à zéro lorsqu'il est inactif, de sorte que seules les branches qui exécutent activement des tests utilisent du calcul.

L'expiration des branches permet de maintenir les coûts bas au fil du temps. Le copy-on-write est particulièrement avantageux lorsque les branches ont une durée de vie courte. Une branche conserve la version des données qui existait lors de sa création. Comme DMS continue de mettre à jour la branche principale avec les modifications de production, une branche qui persiste continue de retenir ces pages plus anciennes, de sorte que le stockage qu'elle utilise augmente avec le temps. Définir un TTL sur chaque branche CI signifie que chaque branche est supprimée automatiquement une fois sa PR terminée. Cela maintient le stockage proche de la taille de la base de production plus les modifications provenant des PR actives.

Le même modèle fonctionne pour les agents d'IA

Les namespaces PR ne sont pas les seules charges de travail qui ont besoin d'une copie jetable de la production. Les agents d'IA qui écrivent du SQL, exécutent des migrations ou modifient des données ont également besoin d'un endroit sûr pour essayer des choses, et le branching en copy-on-write leur en offre un.

Une branche par tâche d'agent. Chaque exécution d'agent obtient sa propre branche de la principale. L'agent peut lire de vraies données, y écrire et même modifier le schéma sans toucher à la production ni au travail d'aucun autre agent. Créer une branche prend des secondes quelle que soit la taille de la base de données, il est donc pratique d'en créer une pour chaque tâche.

De nombreux agents en parallèle. Le stockage ne grandit qu'avec les pages modifiées par chaque branche, et le calcul de chaque branche s'adapte à zéro lorsqu'il est inactif. Exécuter des dizaines d'agents côte à côte coûte à peu près le prix des modifications qu'ils effectuent, et non des dizaines de copies de la base de données.

Examiner les modifications ou les rejeter. Les équipes peuvent vérifier ce qu'un agent a modifié sur sa branche avant d'appliquer quoi que ce soit à la production. Si le résultat ne convient pas, elles suppriment la branche et il n'y a rien à annuler.

Les TTL nettoient après les agents. Les agents peuvent créer de nombreuses branches éphémères. Une expiration sur chaque branche supprime automatiquement celles qui sont abandonnées, de la même manière que les TTL nettoient les branches CI.

Identité délimitée pour les agents. Tout comme les pipelines CI, les agents peuvent s'exécuter en tant que principaux de service avec des jetons OAuth à courte durée de vie, de sorte que chaque requête exécutée par un agent peut être tracée dans les journaux d'audit.

Résultats

  • Temps de provisionnement : plus de 30 minutes auparavant, moins de 60 secondes avec Lakebase [VERIFY p95 measured]
  • Échelle : Conçu pour environ 100 branches PR simultanées sur un jeu de données de production d'environ 2,5 To
  • Compatibilité : La suite CI s'exécute sur Lakebase sans "problème de compatibilité majeur" / perf comparé à Aurora
  • Adoption : Déploiement auprès de 60 à 70 développeurs dans toutes les équipes
  • Citation de développeur : "Auparavant, nous devions copier physiquement les données et ces tâches de copie prenaient des heures et se heurtaient fréquemment à des problèmes de réseau et à d'autres goulots d'étranglement avec diverses plateformes CI (github actions, circle ci, etc.). Nous recherchions une solution qui réponde à nos exigences de sécurité et de conformité si les données quittent notre VPC"

Bonnes pratiques pour la création de branches Lakebase en CI/CD

  1. Une branche par PR, créée à partir d'une branche principale synchronisée en continu.
  2. Définissez toujours un TTL. Traitez l'expiration comme obligatoire et non optionnelle. Ajustez-la à la durée habituelle d'une PR ou d'un test.
  3. Créez une nouvelle branche au lieu de conserver une ancienne. Si une PR a besoin de données plus fraîches, créez une nouvelle branche à partir de la branche principale. Cela ne prend que quelques secondes.
  4. Laissez le calcul passer à zéro. La plupart des branches provisionnées sont inactives à un moment donné.
  5. Utilisez des principaux de service et des jetons OAuth à courte durée de vie pour les pipelines, et le SSO pour les personnes.
  6. Surveillez le stockage par branche pour détecter rapidement les branches à longue durée de vie.

Prêt à attribuer à chaque demande de tirage (pull request) sa propre base de données de type production ? Commencez avec Lakebase et lisez la documentation sur la création de branches pour configurer l'expiration des branches dans votre pipeline CI.

(Cet article de blog a été traduit à l'aide d'outils basés sur l'intelligence artificielle) Article original

Tags associés:

Technologie

Recevez les derniers articles dans votre boîte mail

Abonnez-vous à notre blog et recevez les derniers articles directement dans votre boîte mail.