Bender, il bot Slack al centro della nostra CI/CD

Come il team di ingegneria di Join ha costruito Bender, un bot su Slack che porta la nostra pipeline CI/CD dalla pull request alla produzione.

Gli screenshot di questo articolo mostrano i messaggi originali di Slack, in inglese.

Com’è nato

Quasi tutte le aziende moderne si appoggiano a una lunga lista di tecnologie e strumenti per far girare le operazioni, e noi non facciamo eccezione. Il nostro stack comprende CircleCI, GitHub e GitHub Actions, GCP, Kubernetes, Jira e molto altro. Dato che il rilascio di una funzionalità coinvolge strumenti molto diversi che lavorano insieme, ci serviva qualcosa in grado di parlare con tutti, dalla pubblicazione di una pull request fino al deploy in produzione. È lì che ai nostri ingegneri è venuta un’idea: se passiamo già la maggior parte della giornata su Slack, perché non gestire lì anche la pipeline e i deploy?

Così è nato «Bender the Great». È il nostro strumento interno di CI/CD automatizzata: ci semplifica moltissimo la vita e si collega a ogni strumento che serve per portare a termine il lavoro.

Che cos’è Bender

Bender è partito da un bot open source di GitHub, Hubot, collegato a Slack tramite la loro API legacy. Di recente siamo passati a un’app Slack basata su Bolt for JavaScript, e adesso sta con noi su Slack mentre chiacchieriamo e lavoriamo. È collegato ai vari strumenti del nostro stack tramite i loro webhook o le API pubbliche. La memoria di Bender è un datastore su GCP che gestisce tutte le funzioni che stiamo per vedere.

Il codice di Bender vive in un repository dedicato, che il team mantiene e a cui contribuisce.

Perché automatizzare la CI/CD

Senza un sistema così, gli sviluppatori dovrebbero fare a mano quasi tutti questi passaggi. Prima di tutto il team dovrebbe mettersi d’accordo su come segnalare che una PR è pronta per la revisione e su come tracciare feedback e commenti. Le notifiche si perderebbero spesso, e il botta e risposta nei commenti potrebbe allungare i tempi. Una volta unita la PR e avviata la suite di test, lo sviluppatore dovrebbe tenere d’occhio la pipeline a mano e, a test superati, lanciare con ogni probabilità un comando da riga di comando per fare il deploy o caricare l’immagine di build nel cluster Kubernetes. E a ogni passaggio andrebbe aggiornato a mano lo stato del ticket Jira.

Da noi tutti questi problemi li gestisce già Bender. Le comunicazioni sulle PR arrivano su Slack in automatico, con le persone interessate menzionate per ottenere risposte più rapide. GitHub Actions, insieme al sistema di code di Bender, fa in modo che ogni funzionalità sia testata a fondo e rilasciata in staging per i test manuali. Da lì, il deploy in produzione si riduce a un comando pubblico inviato a Bender su Slack.

Vediamo allora un deploy tipico di una funzionalità di un servizio frontend. In media servono circa 35 minuti per arrivare in produzione:

  • Approvazione della PR: da 5 a 15 minuti, secondo la dimensione della PR e la presenza di commenti da gestire
  • Build dell’immagine su GitHub: da 8 a 10 minuti, secondo il servizio rilasciato
  • Esecuzione della suite E2E: da 15 a 20 minuti, a seconda che ci sia un errore e serva rilanciarla

In quei 35 minuti, le uniche azioni dello sviluppatore sono unire la PR e rilasciare in produzione.

Un altro vantaggio importante di un sistema automatico nostro è la possibilità di saltare certi passaggi quando serve, per accelerare un rilascio.

Ora guardiamo da vicino come funziona il processo, passo dopo passo.

Pubblicare una PR

Il percorso parte da una PR. Le aziende hanno molti modi per segnalare che le PR sono pronte per la revisione e per gestire commenti e modifiche necessari all’approvazione.

Noi abbiamo un canale Slack dedicato dove pubblichiamo le PR pronte per la revisione, menzionando le persone del team che devono controllarle. Il bello inizia quando qualcuno commenta la PR pubblicata. Poiché Bender è collegato ai webhook di GitHub e conserva il riferimento al thread Slack associato, può (tra le altre cose):

  • avvisare chi ha creato la PR quando qualcuno commenta;
  • avvisare chi ha commentato se qualcuno usa il suo handle GitHub (teniamo una mappa tra gli handle di GitHub e quelli di Slack);
  • avvisare una persona (o un team) se gli è stata chiesta la revisione;
  • pubblicare gli errori di GitHub Actions con i link al workflow.

Pubblicando una PR nel canale di revisione del codice, hai subito un modo per parlare con il team. Vedi se qualche azione è fallita e blocca l’unione, e sai quando la PR viene unita grazie a emoji dedicate. Tutto questo si lega alla nostra configurazione dei CODEOWNERS di GitHub, per cui Bender può avvisare i team assegnati anche se nessuno li ha menzionati in modo esplicito: le persone giuste restano aggiornate sulle modifiche nel loro ambito, anche quando arrivano da un altro team.

Un messaggio Slack che pubblica una pull request nel canale di revisione del codice, con una spunta e l’emoji di unione aggiunte da Bender.
La PR pubblicata con il team menzionato. Le due emoji aggiunte arrivano da Bender quando la PR viene approvata e unita.

Un’altra funzione comoda: Bender è collegato a Jira. Se crei una PR con un ID ticket valido nel titolo, lo riconosce e sposta il ticket nella fase «Code review». Lo stesso vale per tutti i passaggi successivi del flusso.

Quando la PR viene approvata, Bender menziona l’autore nel thread della PR per avvisarlo.

Un messaggio Slack di approvazione da parte di Bender, con l’emoji di un robot che balla.
Un messaggio di approvazione con l’emoji di Bender che balla.

Per mettere insieme tutto il flusso, ecco il percorso di una PR attraverso i nostri servizi.

Un diagramma di flusso del percorso di approvazione di una PR tra i diversi servizi.
Il percorso di approvazione della PR tra i servizi.

Modificare il codice E2E

Le modifiche al codice E2E sono un caso a parte: non fanno partire il deploy di un servizio, ma vengono raccolte alla partenza della successiva esecuzione E2E. Pubblichiamo nel canale dei deploy un messaggio con l’autore, perché tutti possano seguire le modifiche, inseriamo il link al commit con il titolo del messaggio di squash e portiamo subito a «chiuso» il ticket Jira indicato.

Un messaggio Slack nel canale dei deploy che annuncia modifiche al codice E2E unite, con il link al commit.
Le modifiche al codice E2E unite, nel canale dei deploy.

Deploy negli ambienti dev e staging

Abbiamo anche un canale dedicato agli stati di deploy dei vari servizi, dove possiamo inviare comandi a Bender per gestirli. I nostri servizi hanno tre ambienti:

  • dev: dove eseguiamo l’intera suite E2E
  • staging: dove poi facciamo il QA manuale sulle funzionalità
  • production

A ciascun ambiente è assegnata un’emoji con una lettera, che viene aggiunta ai diversi thread per indicare dove è avvenuta l’azione.

Un thread Slack che mostra un’azione riuscita su dev, staging e production, ciascuna contrassegnata dall’emoji del suo ambiente.
Un’azione riuscita su tutti e tre gli ambienti.

Quando una PR viene unita, nel workflow di rilascio c’è un passaggio «Bender» dedicato: chi ha creato la PR riceve un avviso che il servizio è stato rilasciato o aggiunto alla coda di deploy. Ogni volta che la pipeline di deploy è libera, Bender prende dalla coda i servizi disponibili e fa partire su CircleCI la suite E2E sui servizi rilasciati. Se gli E2E non passano al primo giro, riceviamo un avviso con gli scenari falliti e Bender gestisce il riavvio dei test falliti.

Un messaggio Slack in cui Bender prende dei servizi dalla coda e li rilascia, con l’emoji di un robot che segna l’inizio di un’esecuzione E2E.
Bender che prende dalla coda e rilascia i servizi. L’emoji del robot indica che è partita un’esecuzione E2E.

Una volta rilasciato un servizio, Bender recupera il diff del rilascio, trova tutti i ticket che facevano parte del deploy e li porta alla fase «On dev».

Quando l’esecuzione E2E riesce, Bender sposta tutti i servizi rilasciati sull’ambiente di staging per i test manuali, poi prende il gruppo successivo di servizi disponibili e lo rilascia su dev ♻️. Dopo ogni deploy in staging, i ticket Jira trovati passano alla fase «On staging».

Un messaggio Slack in cui Bender rilascia in staging i servizi che hanno superato gli E2E.
Bender che rilascia in staging i servizi che hanno superato gli E2E.

Il nostro flusso parte qui, a PR unita: finisce la GitHub Action che costruisce l’immagine e chiamiamo l’API di Bender per avviare il deploy.

Raccogliere le approvazioni e rilasciare in produzione

Non facciamo rilasci automatici. Preferiamo che le persone gestiscano i propri servizi e le proprie funzionalità, e Bender aiuta molto in questo. Poiché può generare i diff tra ambienti, usiamo questa funzione per preparare i rilasci in produzione.

Si parte da un thread di diff nel canale dei deploy, poi si chiede a Bender se il servizio è pronto per il rilascio. Bender trova il diff tra le versioni in produzione e in staging e costruisce una risposta su Slack che menziona tutte le persone con commit in attesa di rilascio. Al messaggio viene aggiunta un’emoji numerica da 1️⃣ a 9️⃣, che indica quante approvazioni servono prima del deploy. Le persone con modifiche mettono un 👍 sullo stesso messaggio e, quando il numero di 👍 corrisponde all’emoji numerica, Bender avvisa chi ha aperto il thread che il servizio è pronto per il rilascio.

Un thread Slack che chiede l’approvazione per più servizi, un avviso su una dipendenza da un altro servizio e la conferma finale quando sono stati raccolti tutti i pollici in su.
La richiesta di approvazione per più servizi, l’avviso su una dipendenza da un altro servizio e la conferma finale quando sono stati raccolti tutti i pollici in su.

Con un altro rapido comando a Bender possiamo rilasciare il servizio (o i servizi) in produzione 🚀. Bender li percorre uno per uno, rilascia ciascuno e, nel messaggio di successo, menziona gli autori che avevano modifiche. Come negli altri ambienti, a deploy concluso Bender porta i ticket Jira alla fase «On production». Da lì scatta un’altra automazione di Jira, che chiude i ticket padre quando serve.

Un thread Slack che mostra più servizi rilasciati in produzione con un solo comando, con gli autori menzionati in ogni messaggio di successo.
Rilasciare più servizi insieme non è mai stato così semplice.

Tenere traccia della cronologia

Un altro aspetto importante di ogni deploy è poter annullare un rilascio andato male. Bender è collegato al cluster Kubernetes e può recuperare le ultime 10 versioni rilasciate di un servizio. Possiamo poi chiedergli di tornare a una versione precisa, e lui rilascia di nuovo quell’immagine. Vale per tutti e tre gli ambienti.

Sovrascrivere al volo le variabili d’ambiente

A volte dobbiamo cambiare le variabili d’ambiente definite nei chart, ma non vogliamo passare per l’intero percorso PR, approvazione e deploy su tre ambienti. Per questo abbiamo un comando con cui Bender imposta la variabile d’ambiente di un servizio e lo riavvia con i nuovi valori, senza toccare il codice.

Lo svantaggio è che ora abbiamo due fonti di verità: il valore originale nel file values.yaml nel codice e, se esiste, quello in Bender. Per tenerle in ordine facciamo pulizie periodiche: inseriamo nel codice i nuovi valori definitivi e li togliamo dal repository di Bender.

Per concludere

Su Bender ci sarebbe molto di più da dire, abbastanza per diversi altri articoli. È stato un vero risparmio di tempo, in modi che non avrei immaginato quando sono entrato nel team. Avere un solo strumento collegato a tutte le tecnologie che usiamo, e capace di agire su ciascuna, rende la vita degli sviluppatori molto più semplice e ci lascia concentrare su ciò che conta davvero: consegnare ai nostri clienti funzionalità di qualità, con velocità.

Inizia oggi

Prova Join gratis per 14 giorni.

Prova Join gratis per 14 giorni5 annunci, accesso completo, senza carta di credito.
Inizia la prova gratuita

Contatta Join