Passa al contenuto principale
Settori industriali

Branching di Lakebase per CI/CD: lezioni da 100 database di PR

Il branching copy-on-write rende le copie isolate dei dati di produzione veloci ed economiche per i test CI/CD e i casi d'uso degli agenti.

di Yasamin Tari e Kartik Mathur

  • La pipeline CI/CD di Snorkel AI assegna a ogni pull request aperta il proprio ramo Lakebase Postgres, una copia completa in lettura/scrittura dei dati di produzione pronta in meno di un minuto anziché in oltre 30 minuti, motivo per cui in precedenza non riuscivano ad attivare una copia per PR.
  • I rami Lakebase utilizzano la modalità copy-on-write, quindi 100 database di PR concorrenti su un set di dati di produzione di circa 2,5 TB aggiungono spazio di archiviazione solo per i dati modificati da ciascun ramo. La scadenza dei rami (TTL) pulisce automaticamente ogni ramo quando la PR è completata, mantenendo lo spazio di archiviazione vicino alle dimensioni della produzione più le modifiche delle PR attive.
  • La connettività privata e il supporto per Okta SSO garantiscono un ambiente governato e sicuro

Il problema: i test sui dati di produzione non dovrebbero richiedere più di 30 minuti

Snorkel AI crea strumenti di data development per i team di IA, utilizzati da esperti di annotazione dei dati e fornitori di modelli di frontiera. In questo specifico caso d'uso, Snorkel rilascia codice tramite una pipeline CI basata su Kubernetes. Ogni pull request aperta, oltre ai commit ad-hoc, ottiene il proprio namespace Kubernetes effimero (un "namespace PR"). Gli sviluppatori distribuiscono lì il loro branch ed eseguono l'intera suite di test prima del merge.

Questi test sono più utili quando vengono eseguiti su dati reali. Il database di produzione di Snorkel è un cluster Amazon Aurora PostgreSQL. Fornire a ciascun namespace PR la propria copia di quel database era la parte difficile. Il ripristino di una copia richiedeva circa 20 minuti per ambiente, il che è troppo lento quando gli sviluppatori aprono PR tutto il giorno e la coda di merge necessita di un ambiente nuovo per ogni esecuzione. Le alternative (database di staging condivisi, fixture ridotte o dati sintetici) ripropongono i problemi che i test in stile produzione dovrebbero risolvere: test che interferiscono tra loro, schemi obsoleti e bug che compaiono solo con forme di dati reali.

Criteri di successo

Snorkel considererebbe Lakebase un successo per il CI/CD se soddisfacesse questi criteri:

  • Provisioning rapido: Un nuovo branch PR è pronto in meno di 60 secondi (p95).
  • Scala: Circa 100 branch PR concorrenti al picco, ciascuno con letture e scritture indipendenti.
  • Compatibilità: L'applicazione esistente e la suite CI vengono eseguite su Lakebase tramite Postgres standard, con prestazioni comparabili ad Aurora e supporto per grandi colonne JSONB/LOB.
  • Dati aggiornati: Il branch principale rimane a circa 2 minuti di distanza dal database di produzione Aurora grazie alla replica DMS continua.
  • Sicurezza: I dati di produzione rimangono su rete privata e non attraversano mai la rete pubblica Internet, gli sviluppatori effettuano l'accesso con Okta SSO e le pipeline CI eseguono l'autenticazione come service principal.

Perché il branching del database si adatta al CI/CD

Lakebase è il database Postgres serverless di Databricks. Lo storage e il compute sono separati e supporta il branching: puoi creare un branch di database nuovo, isolato e scrivibile da qualsiasi punto nel tempo, nello stesso modo in cui crei un branch Git.

I branch utilizzano la modalità copy-on-write. La creazione di un branch è un'operazione sui metadati, quindi nessun dato viene copiato al momento della creazione del branch. Un nuovo branch condivide le pagine di storage con il suo parent e solo le pagine modificate dal branch vengono scritte come nuovo storage. Per il CI, questo significa:

  • La creazione di un branch richiede secondi, non minuti. Non dipende dalle dimensioni del database.
  • Lo storage cresce in base alle modifiche apportate da ciascun branch, non alle dimensioni del database. Ognuno dei branch PR di Snorkel scrive circa 5-10 GB di modifiche su una base di circa 1 TB.
  • Il compute è per branch e si riduce a zero. Ogni branch ha il proprio autoscaling di compute, che si riduce a zero tra un'esecuzione CI e l'altra. Anche con 100 branch di cui è stato effettuato il provisioning, Snorkel prevede che solo circa 20-30 gestiranno il traffico contemporaneamente, a circa 5 query al secondo ciascuno al picco.

L'architettura

image1.png

1. Mantieni una copia aggiornata della produzione sul branch principale. Lakebase è Postgres standard, quindi funziona come destinazione per AWS DMS senza strumenti personalizzati. Snorkel punta un task DMS al suo database Aurora di produzione e lo replica nel branch principale del progetto Lakebase: prima un carico completo, poi la cattura continua dei dati modificati (CDC) che mantiene il branch principale a circa 2 minuti dalla produzione. La modalità LOB completa trasferisce i valori JSONB da 10 a 20 MB. Il team utilizza già DMS, quindi non c'è stato bisogno di creare o mantenere una nuova pipeline di replica. Il branch principale è la "copia di riferimento" da cui inizia ogni branch PR.

2. Crea un branch quando si apre una PR. Quando uno sviluppatore apre una PR, la pipeline CI chiama l'API di Lakebase per creare un branch dal branch principale, imposta una scadenza e passa i dettagli di connessione del branch al namespace PR. Il branch è pronto in meno di un minuto.

3. Esegui i test sui dati reali. L'applicazione nel namespace PR si collega al proprio branch tramite Postgres standard. I test possono eseguire migrazioni, scrivere dati e modificare schemi senza influire sulla produzione, sul branch principale o su qualsiasi altra PR.

4. Elimina il branch quando la PR viene chiusa o il test viene superato, con TTL come rete di sicurezza. Quando la PR viene unita o chiusa, la pipeline elimina il branch. Se quel passaggio di pulizia non viene eseguito, il branch scade autonomamente al termine del suo TTL.

Sicurezza: networking privato e identità per utenti umani e pipeline

Due requisiti di sicurezza hanno escluso le altre opzioni, quindi meritano una sezione dedicata.

Connettività privata. I dati di produzione si spostano da Aurora a Lakebase e da Lakebase al cluster CI tramite rete privata anziché tramite internet pubblico.

Identità. Snorkel ha due tipi di utenti di database: sviluppatori che si connettono in modo interattivo per eseguire il debug di un ambiente PR e pipeline CI che vengono eseguite senza intervento umano. Okta SSO è basato sull'accesso interattivo tramite browser, quindi abbiamo suddiviso la progettazione per tipo di utente:

  • Sviluppatori: Okta è federato con l'account Databricks e gli utenti vengono inseriti tramite SCIM. Gli sviluppatori accedono con la loro solita identità Okta.
  • Pipeline CI: Ogni namespace PR viene eseguito come service principal di Databricks (delimitato per team o per repository), anch'esso inserito tramite SCIM. Il pod PR utilizza le credenziali del service principal per ottenere token OAuth di Lakebase a breve scadenza tramite il SDK di Databricks e li aggiorna durante l'esecuzione di test lunghi. Non ci sono password di database a lungo termine nel CI.
  • Auditing: I log di audit di Postgres registrano l'identità del service principal per ogni query, in modo che ogni query possa essere ricondotta alla pipeline che l'ha eseguita.

Perché il copy-on-write e la scadenza dei branch mantengono il CI veloce ed economico

Due funzionalità di Lakebase fanno sì che questo pattern funzioni su scala: il branching copy-on-write e la scadenza dei branch (TTL).

image3.png

Il copy-on-write rende i branch istantanei. Un nuovo branch non copia alcun dato. Punta alle pagine di storage esistenti del proprio parent e solo le pagine modificate dal branch vengono scritte come nuovo storage. Creare un branch da una copia di produzione di circa 1 TB richiede circa lo stesso tempo necessario per crearne uno da un database di 1 GB: pochi secondi, non i circa 20 minuti richiesti da un ripristino completo. Ciascun namespace PR ottiene immediatamente la propria copia di produzione isolata e scrivibile.

Il copy-on-write rende i branch economici. Ciascun branch condivide la maggior parte dei suoi dati con il branch principale, quindi lo storage cresce con le modifiche apportate da ciascun branch, non con le dimensioni del database. Per Snorkel, si tratta di circa 5-10 GB per branch PR oltre alla base condivisa. Il compute è per branch e si riduce a zero quando è inattivo, quindi solo i branch che eseguono attivamente test utilizzano il compute.

La scadenza dei branch mantiene bassi i costi nel tempo. Il copy-on-write offre il massimo risparmio quando i branch hanno una breve durata. Un branch mantiene la versione dei dati esistente al momento della sua creazione. Poiché DMS continua ad aggiornare il branch principale con le modifiche di produzione, un branch che rimane attivo continua a mantenere quelle pagine meno recenti, quindi lo storage utilizzato cresce nel tempo. L'impostazione di un TTL su ogni branch CI fa sì che ciascun branch venga rimosso automaticamente una volta completata la PR corrispondente. In questo modo lo storage rimane vicino alle dimensioni della base di produzione più le modifiche derivanti dalle PR attive.

Lo stesso pattern funziona per gli agenti IA

I namespace PR non sono gli unici carichi di lavoro che richiedono una copia di produzione usa e getta. Anche gli agenti IA che scrivono SQL, eseguono migrazioni o modificano dati hanno bisogno di un luogo sicuro in cui provare le cose, e il branching copy-on-write ne offre uno.

Un branch per ogni task dell'agente. Ogni esecuzione dell'agente ottiene il proprio branch del branch principale. L'agente può leggere dati reali, scrivervi sopra e persino modificare lo schema senza toccare la produzione o il lavoro di qualsiasi altro agente. La creazione di un branch richiede pochi secondi indipendentemente dalle dimensioni del database, quindi è pratico crearne uno per ogni task.

Molti agenti in parallelo. Lo storage cresce solo con le pagine modificate da ciascun branch e il compute di ciascun branch si riduce a zero quando è inattivo. Eseguire decine di agenti fianco a fianco costa all'incirca quanto le modifiche che apportano, anziché richiedere decine di copie del database.

Esamina le modifiche o scartale. I team possono controllare ciò che un agente ha modificato sul suo branch prima di applicare qualsiasi cosa alla produzione. Se il risultato non è corretto, eliminano il branch e non c'è nulla da ripristinare.

I TTL ripuliscono il lavoro degli agent. Gli agent possono creare molti branch a breve termine. La scadenza su ogni branch elimina automaticamente quelli abbandonati, esattamente come i TTL ripuliscono i branch CI.

Identità con ambito per gli agent. Come le pipeline CI, gli agent possono essere eseguiti come service principal con token OAuth a breve termine, in modo che ogni query eseguita da un agent possa essere tracciata nei log di controllo.

Risultati

  • Tempo di provisioning: oltre 30 minuti prima, meno di 60 secondi con Lakebase [VERIFY p95 measured]
  • Scalabilità: Progettato per circa 100 branch PR simultanei su un set di dati di produzione di circa 2,5 TB
  • Compatibilità: La suite CI viene eseguita su Lakebase "senza problemi di compatibilità importanti" / prestazioni rispetto ad Aurora
  • Adozione: Rilascio a 60-70 sviluppatori tra i vari team
  • Citazione di uno sviluppatore: "In passato dovevamo copiare fisicamente i dati e questi processi di copia richiedevano ore, imbattendosi frequentemente in problemi di rete e altri colli di bottiglia con varie piattaforme CI (github actions, circle ci, ecc.). Stavamo cercando una soluzione che superasse i nostri requisiti di sicurezza e conformità se i dati lasciano il nostro VPC"

Procedure consigliate per il branching di Lakebase in CI/CD

  1. Un branch per PR, creato da un branch principale sincronizzato continuamente.
  2. Imposta sempre un TTL. Considera la scadenza come obbligatoria, non facoltativa. Falla corrispondere alla durata tipica di una PR o di un test.
  3. Crea un nuovo branch invece di mantenere uno vecchio. Se una PR ha bisogno di dati più aggiornati, crea un nuovo branch dal branch principale. Ci vogliono pochi secondi.
  4. Consenti alla potenza di calcolo di ridursi a zero. La maggior parte dei branch di cui è stato effettuato il provisioning risulta inattiva in un dato momento.
  5. Usa service principal e token OAuth a breve termine per le pipeline, e l'SSO per le persone.
  6. Monitora lo spazio di archiviazione per branch per individuare tempestivamente i branch a lungo termine.

Pronto a dare a ogni pull request un database simile a quello di produzione? Inizia con Lakebase e leggi la documentazione sul branching per configurare la scadenza dei branch nella tua pipeline CI.

(Questo post sul blog è stato tradotto utilizzando strumenti basati sull'intelligenza artificiale) Post originale

Tag correlati:

Tecnologia

Ricevi gli ultimi articoli nella tua casella di posta

Iscriviti al nostro blog e ricevi gli ultimi articoli direttamente nella tua casella di posta.