Gestire più filiali in integrazione continua


85

Ho affrontato il problema del ridimensionamento della CI nella mia azienda e allo stesso tempo ho cercato di capire quale approccio adottare quando si tratta di CI e più filiali. C'è una domanda simile a stackoverflow, rami di funzionalità multiple e integrazione continua . Ne ho iniziato uno nuovo perché mi piacerebbe avere maggiori discussioni e fornire alcune analisi sulla domanda.

Finora ho scoperto che ci sono 2 approcci principali che posso adottare (o forse alcuni altri ???).

Quindi sembra che se voglio fornire agli sviluppatori CI per i loro rami personalizzati ho bisogno di strumenti speciali per Jenkins (API o script di shell o qualcosa del genere?) E gestire il ridimensionamento. Oppure posso dire loro di unirsi più spesso a DEV e vivere senza CI su rami personalizzati. Quale sceglieresti o ci sono altre opzioni?

Risposte:


69

Quando parli di scalare CI, stai davvero parlando di ridimensionare l'uso del tuo server CI per gestire tutti i tuoi rami di funzionalità insieme alla tua linea principale. Inizialmente questo sembra un buon approccio in quanto gli sviluppatori di una filiale ottengono tutti i vantaggi dei test automatici inclusi nei lavori CI. Tuttavia, si verificano problemi nella gestione dei lavori del server CI (come hai scoperto) e, cosa più importante, non stai davvero facendo CI. Sì, stai utilizzando un server CI, ma non stai integrando continuamente il codice di tutti i tuoi sviluppatori.

Eseguire un CI reale significa che tutti i tuoi sviluppatori si impegnano regolarmente per la linea principale. Facile a dirsi, ma la parte difficile è farlo senza interrompere l'applicazione. Consiglio vivamente di esaminare la consegna continua , in particolare la sezione Mantenere rilasciabile l'applicazione nel Capitolo 13: Gestione di componenti e dipendenze . I punti principali sono:

  • Nascondi la nuova funzionalità fino al termine (AKA Feature Toggles ).
  • Apporta tutte le modifiche in modo incrementale come una serie di piccole modifiche, ognuna delle quali è rilasciabile.
  • Usa il ramo per astrazione per apportare modifiche su larga scala alla base di codice.
  • Usa i componenti per disaccoppiare parti della tua applicazione che cambiano a velocità diverse.

Sono abbastanza autoesplicativi tranne ramo per astrazione. Questo è solo un termine di fantasia per:

  1. Crea un'astrazione sulla parte del sistema che devi modificare.
  2. Rifattorizza il resto del sistema per usare il livello di astrazione.
  3. Creare una nuova implementazione, che non fa parte del percorso del codice di produzione fino al completamento.
  4. Aggiorna il tuo livello di astrazione per delegare alla tua nuova implementazione.
  5. Rimuovi la vecchia implementazione.
  6. Rimuovere il livello di astrazione se non è più appropriato.

Il paragrafo seguente della sezione Branches, Streams e Continuous Integration nel Capitolo 14: Advanced Version Control riepiloga gli impatti.

L'approccio incrementale richiede sicuramente più disciplina e cura - e in effetti più creatività - che creare una filiale e immergersi nella ri-architettura e nello sviluppo di nuove funzionalità. Tuttavia, riduce in modo significativo il rischio che le modifiche apportate interrompano l'applicazione e consentirà a te e al tuo team di risparmiare molto tempo per l'unione, la correzione dei guasti e lo stato di implementazione dell'applicazione.

Ci vuole un bel cambiamento di mente per rinunciare ai rami delle funzionalità e otterrai sempre resistenza. Nella mia esperienza questa resistenza si basa sul fatto che gli sviluppatori non si sentano sicuri nell'impegnare il codice sulla linea principale e questa è una preoccupazione ragionevole. Questo a sua volta di solito deriva da una mancanza di conoscenza, fiducia o esperienza con le tecniche sopra elencate e forse con la mancanza di fiducia con i tuoi test automatizzati. Il primo può essere risolto con la formazione e il supporto degli sviluppatori. Quest'ultimo è un problema molto più difficile da affrontare, tuttavia la ramificazione non fornisce alcuna sicurezza extra reale, si limita a rimandare il problema fino a quando gli sviluppatori non si sentono abbastanza sicuri con il loro codice.


4
Tom, funziona bene solo se 1) sia il rilascio che l'aggiornamento sono relativamente facili 2) la maggior parte delle tue modifiche sono ben isolate. Questo è vero per lo sviluppo web, ma se stai realizzando versioni di prodotti in scatola, le versioni stabili devono rimanere stabili a tutti i costi, perché gli hotfix sono davvero costosi o addirittura impossibili in un grande ambiente aziendale.
Jevgeni Kabanov

13
La vera CI non riguarda solo l'integrazione, ma anche il feedback
Anton Arhipov

3
Ho scelto questo come risposta (almeno ho dato la taglia, per favore fammi sapere se in qualche modo ho ancora bisogno di contrassegnarlo come corretto) ma penso che questa non sia una soluzione per il mio problema. Ho scritto un seguito su zeroturnaround.com/blog/…
toomasr

1
@Jevgeni Kabanov e @toomasr Sembra che entrambi pensiate che fare un vero CI significhi rinunciare alla qualità e funziona solo per gli sviluppatori Web, perché è così facile eliminare le correzioni. Immagino che ciò di cui sei preoccupato sia un impegno rischioso appena prima del rilascio. Sì, questo può comportare un cattivo rilascio che può essere costoso da correggere. Tuttavia, un commit improprio su un ramo di funzionalità appena prima del rilascio è altrettanto negativo. Se ritieni che ci sia una differenza, condividi il tuo ragionamento. Un modo per contrastare questo problema (se il commit era per la linea principale o un ramo di funzionalità) è utilizzare l'approccio di consegna continua.
Tom Howard

1
Oh, e BTW, negli ultimi 4 anni la mia principale esperienza di sviluppo è stata presso istituzioni finanziarie. L'imperativo di avere versioni stabili e il costo per sbagliare (per non parlare del processo di controllo delle modifiche che è necessario eseguire per inviare un hotfix) non è molto maggiore di quello. Un prodotto in scatola sarebbe un cambiamento rilassante per me.
Tom Howard

4

Stabilirei lavori separati per ogni filiale. L'ho già fatto e non è difficile da gestire e configurare se hai impostato correttamente Hudson / Jenkins. Un modo rapido per creare più lavori consiste nel copiare da un lavoro esistente che ha requisiti simili e modificarli secondo necessità. Non sono sicuro se si desidera consentire a ogni sviluppatore di impostare i propri lavori per i propri rami, ma non è molto lavoro da gestire per una persona (cioè un gestore di build). Una volta che i rami personalizzati sono stati uniti in rami stabili, i lavori corrispondenti possono essere rimossi quando non sono più necessari.

Se sei preoccupato per il carico sul server CI, puoi impostare istanze separate dell'elemento della configurazione o anche slave separati per bilanciare il carico su più server. Assicurati che il server su cui stai eseguendo Hudson / Jenkins sia adeguato. Ho usato Apache Tomcat e dovevo solo assicurarmi che avesse memoria e potenza di elaborazione sufficienti per elaborare la coda di compilazione.

È importante essere chiari su ciò che si desidera ottenere utilizzando CI e quindi trovare un modo per implementarlo senza troppi sforzi manuali o duplicazioni. Non c'è niente di sbagliato nell'usare altri strumenti o script esterni che vengono eseguiti dal tuo server CI che aiutano a semplificare il tuo processo di gestione della build complessivo.


Penso che questa mancanza di strumenti significhi che ci sia spazio per alcuni plugin / prodotti in questo reparto. Non vorrei scrivere il mio.
toomasr

1
C'è un'utilità per Jenkins che crea automaticamente la configurazione di build per ogni ramo: entagen.github.com/jenkins-build-per-branch
kolen

3

Sceglierei dev + rami stabili. E se desideri ancora rami personalizzati e hai paura del carico, perché non spostare questi rami personalizzati nel cloud e lasciare che gli sviluppatori lo gestiscano da soli, ad esempio http://cloudbees.com/dev.cb Questa è l'azienda in cui si trova Kohsuke ora . C'è anche un Eclipse Tooling, quindi se sei su Eclipse, lo avrai strettamente integrato direttamente in dev env.


Scambierò la mancanza di strumenti per la gestione di più rami con lo stesso problema ma sul cloud? Voglio dire che adesso potrò gestire il carico ma ancora non i rami?
toomasr

Intendevo dimenticare gli strumenti e distribuire la gestione tra gli sviluppatori - "se vuoi una build personale personalizzata, ecco il tuo account CB". Senza influire sulle prestazioni di compilazione del server principale. Sebbene la loro API sia piuttosto semplice, quindi la creazione di utilità di gestione sarebbe probabilmente questione di una o due settimane, e poi fai quello che vuoi. Come è normale nella vita, se vuoi qualcosa di speciale è meglio farlo da solo. Allo stesso tempo stanno crescendo rapidamente e ascoltano la community, quindi compila una richiesta di funzionalità e potrebbe apparire presto.
Anton Safonov

Oh, capito. Di 'al proprietario della filiale che sceglie i lavori a cui è interessato e impostali come desidera per la sua filiale personalizzata. Mi piace questa idea.
toomasr

1

In realtà ciò che è veramente problematico è costruire l'isolamento con i rami delle funzionalità. Nella nostra azienda abbiamo una serie di progetti Maven separati che fanno tutti parte di una distribuzione più ampia. Questi progetti sono gestiti da team diversi ma per ogni distribuzione tutti i progetti devono essere rilasciati. Una featurebranch può ora sovrapporsi da un progetto all'altro e questo è il momento in cui l'isolamento della build diventa doloroso. Ci sono diverse soluzioni che abbiamo provato:

  • creare repository di snapshot separati in nexus per ogni feature branch
  • condividere repository locali su slave dedicati
  • usa il plugin repository-server con i repository a monte
  • costruire tutto all'interno di un lavoro con un repository privato

In effetti, l'ultima soluzione è la più promettente. Tutte le altre soluzioni mancano in un modo o nell'altro. Insieme al plugin job-dsl è facile configurare un nuovo ramo di funzionalità. è sufficiente copiare e incollare lo script groovy, adattare i rami e lasciare che il lavoro seme crei i nuovi lavori. Assicurarsi che il lavoro di inizializzazione rimuova i lavori non gestiti. Quindi puoi facilmente ridimensionare con rami di funzionalità su diversi progetti esperti.

Ma come Tom ha detto molto sopra, sarebbe più bello superare la necessità di rami di funzionalità e insegnare agli sviluppatori a integrarsi in modo pulito, ma questo è un processo più lungo e il risultato non è chiaro con molte parti del sistema legacy che non toccherete più.

i miei 2 centesimi

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.