Imaginează-ți două echipe de dezvoltare software.
Prima pregătește o nouă versiune a aplicației.
Programatorul termină taskul. Cineva verifică codul. Apoi trebuie rulate testele. Cineva pregătește pachetul. Altcineva se conectează la server. După aceea trebuie efectuate câteva acțiuni manuale, verificată configurația și observat sistemul după implementare. Dacă totul merge bine, noua versiune devine disponibilă.
A doua echipă lucrează diferit.
Codul ajunge în repository. Pornește automat testarea, analiza calității și controalele de securitate. Sistemul construiește versiunea aplicației, o implementează în mediul de test, execută verificări suplimentare, iar după îndeplinirea unor condiții stabilite o poate implementa în producție. Dacă ceva nu merge bine, implementarea este oprită sau sistemul poate reveni la versiunea anterioară.
Ambele echipe creează software.
Dar doar una dintre ele a construit un proces repetabil de livrare a software-ului.
Și tocmai despre asta este CI/CD.
"Merge în producție" nu înseamnă încă un proces matur
Multe companii măsoară succesul printr-un criteriu foarte simplu: aplicația funcționează.
Desigur, acesta este un lucru de bază.
Dar odată cu dezvoltarea sistemului apar alte întrebări:
- Cât de repede putem implementa o corecție?
- Cât de des putem publica funcționalități noi?
- Câte acțiuni manuale executăm la fiecare implementare?
- Poate fiecare programator să pornească procesul de implementare după aceleași reguli?
- Știm ce versiune rulează în acest moment?
- Putem reveni la versiunea anterioară?
- După implementare verificăm automat dacă sistemul funcționează corect?
- Avem monitorizare?
- Știm că implementarea a cauzat o problemă înainte să o semnaleze clientul?
Acestea sunt întrebări despre software delivery, nu doar despre programare.
CI și CD - două elemente ale aceluiași proces
CI, adică Continuous Integration, înseamnă integrare continuă a schimbărilor.
În practică, înseamnă ca schimbările să ajungă des în repository-ul comun și să fie verificate automat.
Un pipeline tipic poate rula, printre altele:
-
compilarea sau construirea aplicației,
-
teste unitare,
-
teste de integrare,
-
linting,
-
analiza statică a codului,
-
scanarea dependențelor,
-
controale de securitate,
-
construirea artefactelor de implementare.
Astfel, o problemă poate fi detectată înainte ca codul să ajungă în producție.
CD, adică Continuous Delivery sau Continuous Deployment, se referă la etapa următoare - livrarea schimbărilor.
În funcție de modelul adoptat, sistemul poate pregăti o versiune gata de implementare sau o poate implementa automat după trecerea anumitor controale.
Această distincție este importantă.
Continuous Delivery nu trebuie să însemne implementarea automată a fiecărei schimbări în producție.
Poate însemna pur și simplu că fiecare versiune este pregătită într-un mod repetabil pentru implementare.
De ce implementările manuale devin o problemă?
O implementare manuală nu trebuie să fie neapărat ceva rău.
Într-un proiect mic poate fi complet suficientă.
Problema începe atunci când procesul crește odată cu aplicația.
La început avem o singură persoană care știe cum să implementeze sistemul. Apoi apare al doilea server. Mai târziu mediul de test. După aceea baza de date, cache-ul, cozile, storage-ul, câteva servicii și API-uri externe. În plus apar configurații diferite pentru development, testare și producție.
După câțiva ani, procesul poate arăta cam așa:
"Mai întâi pornește X, apoi schimbă parametrul Y, după aceea repornește serviciul Z, dar înainte fă o copie de rezervă a bazei. Iar dacă apare o eroare, sună persoana care a făcut implementarea data trecută."
Asta nu mai este un proces. Este cunoaștere ascunsă în capul unui om. Și tocmai atunci riscul crește.
Automatizarea nu este utilă doar pentru confortul programatorilor
Adesea CI/CD este prezentat ca un instrument care crește confortul dezvoltatorilor. Este adevărat, dar este doar o parte a imaginii.
Automatizarea delivery-ului crește înainte de toate repetabilitatea procesului.
Dacă implementarea este realizată de un om, există posibilitatea să facă de fiecare dată ceva puțin diferit.
Dacă o face pipeline-ul, poate fi definită exact secvența de pași.
Aceeași versiune.
Aceleași teste.
Aceleași controale.
Aceleași reguli.
Acest lucru este deosebit de important în proiectele dezvoltate de mai multe persoane sau mai multe echipe.
Testele înainte de implementare sunt mai importante decât viteza implementării
Automatizarea fără teste poate doar să facă erorile să apară mai repede.
De aceea, un pipeline bine proiectat nu ar trebui să fie doar un mecanism: "cod → producție".
Ar trebui să fie un sistem de control al calității.
În funcție de proiect, pot exista în el:
- Teste unitare - verifică elemente individuale de logică.
- Teste de integrare - verifică colaborarea componentelor.
- Teste end-to-end - simulează scenarii reale de utilizator.
- Teste de securitate - verifică printre altele dependențele și vulnerabilitățile cunoscute.
- Teste de performanță - necesare acolo unde este importantă gestionarea unei anumite încărcări.
Nu fiecare aplicație are nevoie de toate aceste straturi în aceeași măsură.
Și asta este important.
CI/CD nu înseamnă să arunci în pipeline cât mai multe instrumente posibil.
Este vorba despre alegerea controalelor în funcție de riscul sistemului concret.
Ce se întâmplă când un test nu trece?
Aceasta este una dintre cele mai importante întrebări din întregul proces.
Un pipeline matur ar trebui să aibă reguli clar definite.
Dacă un test critic nu trece, versiunea nu ar trebui să fie considerată gata de implementare.
Dacă scanarea de securitate detectează un anumit nivel de risc, pipeline-ul poate opri procesul.
Dacă build-ul nu se execută, nu există nimic de implementat.
Sună banal. Dar tocmai astfel de "porți" automate fac ca acea calitate să nu depindă exclusiv de memoria și acuratețea omului.
Și dacă implementarea totuși eșuează?
Chiar și cel mai bun proces nu elimină toate erorile. De aceea, al doilea element al unui delivery matur este posibilitatea de reversare controlată a schimbării.
Rollback-ul poate însemna revenirea la artefactul anterior, la imaginea de container sau la versiunea aplicației. Dar aici apare o problemă importantă. Rollback-ul codului nu înseamnă întotdeauna rollback-ul datelor.
Dacă noua versiune a schimbat structura bazei de date, situația devine mai complicată.
Prin urmare, migrațiile bazelor de date ar trebui proiectate astfel încât întregul proces să fie cât mai sigur și reversibil sau, cel puțin, compatibil cu versiunea anterioară a aplicației.
Acesta este unul dintre exemplele care arată că CI/CD profesionist este o problemă de arhitectură, nu doar o configurație a unui instrument.
Blue-green, canary și alte strategii de deploy
În sistemele mai exigente nu este nevoie să se treacă imediat toți utilizatorii pe noua versiune. Se pot folosi diferite strategii de deployment.
Blue-green deployment
Funcționează două versiuni ale mediului.
Una gestionează traficul, cealaltă este pregătită să preia traficul.
După validarea pozitivă are loc comutarea.
Avantajul este posibilitatea de a reveni rapid la mediul anterior.
Dezavantajul poate fi un consum mai mare de infrastructură.
Canary deployment
Noua versiune ajunge mai întâi la o mică parte dintre utilizatori sau din trafic.
Dacă monitorizarea nu indică probleme, aria de implementare poate fi mărită treptat.
Astfel se limitează raza potențială a erorii.
Totuși, aceasta necesită infrastructură adecvată, monitorizare și un mod de gestionare a traficului.
Feature flags
O funcționalitate poate fi implementată în sistem, dar păstrată dezactivată pentru utilizatori.
Astfel, deploy-ul codului și activarea funcționalității devin două procese separate.
Acest lucru oferă un control mai mare, mai ales în cazul schimbărilor mari.
Totuși, asta nu înseamnă că feature flags sunt o soluție pentru orice proiect. Excesul lor poate crește și el complexitatea sistemului.
Monitorizarea după deploy
Poți efectua toate testele. Poți avea un pipeline excelent. Poți implementa noua versiune fără nicio eroare. Iar câteva minute mai târziu aplicația poate începe să se comporte diferit sub încărcarea reală.
De aceea procesul nu ar trebui să se termine odată cu deploy-ul. Este nevoie de observability, adică de posibilitatea de a înțelege ce se întâmplă în interiorul sistemului care rulează.
În funcție de arhitectură, aceasta include printre altele:
-
loguri,
-
metrici,
-
tracing,
-
monitorizarea infrastructurii,
-
monitorizarea aplicației,
-
alerte,
-
informații despre erori,
-
indicatori de business.
Nu este vorba despre a colecta totul. Este vorba despre a putea răspunde la întrebările importante pe baza datelor.
Aplicația funcționează?
Funcționează mai lent decât înainte?
Au crescut numărul de erori?
Care serviciu generează problema?
Problema îi afectează pe toți utilizatorii sau doar pe o parte?
100 de deploy-uri pe zi nu este întotdeauna obiectivul
Titlul acestui articol vorbește despre 100 de deploy-uri pe zi, dar nu este vorba despre stabilirea acestei cifre ca obiectiv.
Într-un sistem intern actualizat o dată pe lună nu are sens să urmărești artificial sute de deploymenturi. Într-un sistem dezvoltat foarte intens, o astfel de frecvență poate însă fi posibilă din punct de vedere tehnic.
Cheia este capacitatea de a livra schimbări în siguranță, nu numărul de deploy-uri în sine. Aceasta este o diferență fundamentală.
Maturitatea procesului nu se măsoară prin cât de des facem deploy, ci prin cât de previzibil și sigur putem să o facem.
Când poate CI/CD să fie prea mult pentru cât valorează?
Nu orice aplicație are nevoie de o infrastructură complexă de deployment.
Dacă avem o aplicație mică, o echipă redusă și câteva deploy-uri pe an, un pipeline elaborat poate costa mai mult decât problemele pe care le rezolvă.
La fel în cazul sistemelor foarte specifice, unde deploy-ul necesită control manual din motive de securitate, reglementare sau din cauza naturii infrastructurii.
De aceea arhitectura de delivery ar trebui să decurgă din nevoile sistemului. Nu din modă.
Când automatizarea deploy-urilor oferă beneficii deosebite?
Merită să o luăm în considerare mai ales atunci când:
-
sistemul este dezvoltat în mod regulat,
-
la cod lucrează mai multe persoane,
-
există mai mult de un mediu,
-
deploy-urile sunt frecvente,
-
deploy-urile manuale generează erori,
-
sistemul are o importanță critică pentru business,
-
avem nevoie de rollback rapid,
-
aplicația are multe componente,
-
sunt necesare audituri sau un istoric al schimbărilor,
-
timpul de livrare a funcționalităților are importanță business.
În astfel de cazuri, un pipeline bine proiectat poate fi unul dintre cele mai importante elemente ale procesului de dezvoltare software.
CI/CD nu repară o arhitectură proastă
Și acest lucru merită subliniat.
Poți crea un pipeline excelent pentru o aplicație slabă.
Să testezi automat cod prost.
Să deployezi automat o arhitectură proastă.
Să scalezi automat un sistem prost proiectat.
Automatizarea nu înlocuiește, așadar, arhitectura, testele sau competențele echipei.
O ea întărește procesul existent.
Dacă procesul este bun, ajută la scalarea lui.
Dacă procesul este prost, poate pur și simplu să execute mai repede lucruri proaste.
Cum arată un proces matur?
Nu există un singur pipeline universal.
Dar un proces matur ar trebui să aibă câteva caracteristici de bază.
Repetabilitate - deploy-ul se realizează conform unor pași definiți.
Automatizare - mașinile execută cât mai mare parte din munca repetitivă.
Testabilitate - schimbările sunt verificate automat.
Securitate - procesul include controale de securitate adecvate.
Observabilitate - după deploy se știe ce se întâmplă cu sistemul.
Reversibilitate - există o modalitate planificată de a reacționa la o schimbare eșuată.
Urmărirea schimbărilor - se știe ce versiune a fost deployată și din ce a fost construită.
Controlul accesului - nu oricine poate face liber orice deploy în producție.
Exact din astfel de elemente se formează un proces profesionist de software delivery.
Cea mai importantă schimbare începe cu o altă întrebare
Companiile întreabă adesea: „Cât de repede putem crea această funcționalitate?”
Merită adăugată o a doua întrebare: „Cât de repede și în siguranță vom putea livra următoarele 50 de funcționalități?”
Pentru că un singur deploy poate fi făcut manual. Poți chiar să deployezi manual o aplicație timp de câțiva ani. Dar odată cu creșterea produsului, a echipei, a numărului de utilizatori și a numărului de schimbări crește și costul unei astfel de abordări.
De aceea CI/CD, testele automate, monitorizarea și deploymenturile controlate nu sunt soluții doar pentru marile corporații.
Sunt elemente ale infrastructurii procesului care permit să dezvolți software fără a adăuga risc inutil fiecărei schimbări următoare.
Și, în cele din urmă, exact despre asta este vorba.
Nu despre 100 de deploy-uri pe zi.
Nu despre instrumente la modă.
Nu despre cel mai complicat pipeline.
Doar despre posibilitatea de a spune:
"Avem o schimbare. Am verificat-o. Știm ce implementăm. Știm cum o monitorizăm. Și știm ce vom face dacă ceva nu merge bine."



