În urma unui studiu realizat de Google Trends, termenul "DevOps" alături de alți termeni asociați, a înregistrat în luna februarie 2019, cel mai mare scor în ceea ce privește interesul manifestat de utilizatori: scorul 100. Majoritatea companiilor au început să adopte o cultură DevOps și practicile tehnice numite Continuous Integration & Continuous Delivery centrate pe automatizarea proceselor de livrare software. Dar adoptarea acestor procese nu este lipsită de provocări. Una dintre acestea este alegerea potrivită a toolurilor folosite pentru a implementa pașii necesari livrării unei aplicații. Scopul acestui articol este de a descrie abordările de tip anti-pattern referitoare la utilizarea unor tooluri des întâlnite în ecosistemul DevOps, cu accent pe Jenkins. De asemenea, luăm în vizor și prezentarea unor idei despre orchestrarea pașilor de livrare.
Imagine dzone.com
O confuzie des întâlnită în contextul DevOps este asocierea termenului cu folosirea toolurilor pentru automatizarea procesului de livrare a aplicațiilor. Această afirmație nu este pe deplin incorectă. Dar, dacă luăm în considerare motivul apariției mișcării DevOps, esența acesteia a fost și va rămâne gândirea orientată spre tratarea eșecurilor ca oportunități de învățare, experimentarea continuă și implementarea de procese care să asigure cicluri rapide de feedback. Definiția acestor procese ar trebui să răspundă la întrebarea "Cum putem livra aplicații software într-un mod eficient, stabil și consistent?", care este de fapt scopul filozofiei DevOps și practicilor tehnice asociate.
Prezentarea practicii numite Continuous Integration în stagiile inițiale, a introdus conceptul de "Build Server". Acesta a fost descris ca un server folosit drept mediu de integrare, cu scopul de a asigura un feedback rapid contribuitorilor, cu privire la integrarea corectă a ceea ce au adăugat în branchul principal. Clar și concis! Aceste tehnici se remarcă prin valoarea adăugată în momentul în care schimbările sunt adăugate incremental și se aplică un set de teste riguroase, iar feedbackul este unul rapid și relevant.
Continuous Delivery a apărut cu scopul de a dezvolta în continuare procesul descris anterior, prin promovarea unor idei care oferă posibilitatea echipelor de development să creeze software. Acesta poate fi livrat într-o variantă de release în orice moment și în manieră stabilă și consistentă în mediul de producție. Rezultatul implicit al acestui proces este apariția așa numitelor delivery pipelines, caracterizate de un set de pași, cu o execuție bine definită, necesari pentru livrarea aplicației. Astfel, apare nevoia utilizării toolurilor pentru generarea artefactelor și asigurarea stării infrastructurii. În acest moment, putem spune că orice proces automat începe prin a replica un proces manual bine documentat în varianta lui sub formă de cod. Acesta este primul și cel mai important pas către delivery pipelines.
În continuare, vom folosi termenul de "deployment pipeline", pentru a defini pașii care trebuie parcurși pentru a compila și genera artefactele și apoi, pentru configurarea și rularea aplicației. Condițiile necesare pentru a implementa un pipeline care să genereze un feedback relevant sunt: practicarea Continuous Integration pentru implementarea aplicațiilor, introducerea testelor automate și managementul configurației. Totuși, acești termeni sunt vagi, iar definiția și implementarea lor depinde în mare măsură de natura proiectelor. Indiferent de context, ideea de bază rămâne aceeași: scopul acestui pipeline este demonstrarea că artefactul generat nu este potrivit pentru a fi utilizat în producție. Acest lucru poate fi realizat prin validarea produsului din mai multe perspective, iar dacă aceste teste trec cu succes, procesul poate continua până în producție.
Provocarea cel mai des întâlnită în mediul IT, este utilizarea acestor practici tehnice și la nivel de infrastructură și configurare. Însă cât de mult poate fi extinsă această automatizare pentru a păstra un cod ușor de menținut și folosit? Care este scopul unui tool ca Jenkins sau a toolurilor asemănătoare de Continuous Integration? Există așa numite "best practices" în ceea ce privește designul acestor pipeline-uri? Nu în ultimul rând, în ce mod putem păstra un echilibru între numărul de tooluri, procesul de învățare asociat și costurile implicite?
În cele ce urmează, vor fi abordate tiparele utilizate în implementarea de delivery pipelines, Jenkins și alte tooluri. De asemenea, vom încerca să răspundem într-un mod subiectiv la întrebările de mai sus.
Jenkins este unul dintre cele mai cunoscute și utilizate tooluri de Continuous Integration, grație naturii open-source a acestuia și a implicării active a comunității. Cele mai comune cazuri de utilizare a Jenkins, împreună cu alte tooluri care alcătuiesc un mod de lucru bazat pe CI (Git, Maven, Nexus, Sonar etc.) , sunt automatizarea compilării, rulării de teste (unit tests) care oferă cel mai rapid feedback și instalarea aplicației. Cu toate acestea, în cele mai multe situații, acest workflow nu este suficient pentru a oferi controlul și vizibilitatea necesară asupra procesului complet.
Capabilitățile lui Jenkins și a altor tooluri asemănătoare s-au extins masiv în decursul timpului, în special datorită oportunității de a crea pipeline-uri sub formă de cod. Unul dintre beneficiile evidente ale acestei implementări este posibilitatea dezvoltatorilor, dar și departamentelor de IT Operations de a-și automatiza activitățile și de a versiona scripturile care definesc acest pipeline împreună cu proiectul și fișierele de configurare. Al doilea beneficiu, deși nu la fel de evident, este opțiunea de a extinde pipeline-urile de la pașii de build până la instalare și rulare a aplicației și orchestrarea flowului end-to-end.
Cele mai comune implementări de pipeline sunt definite ca stagii care execută comenzi într-un "shell step" și, în esență, nu există niciun dezavantaj aparent în acest mod de utilizare. Deși această abordare este una simplă și funcțională de automatizare, valoarea adăugată a toolului este susținută de utilizarea pluginurilor. Limbajul de scriere a pipeline-urilor, Jenkins DSL, împreună cu aceste pluginuri oferă o mare varietate de instrumente pentru a crea vizibilitate și a genera informație despre procese, despre unde și cum rulează. În esență, Jenkins reprezintă rularea unor taskuri într-un mod controlat, declanșate la un moment în timp sau bazat pe valorile unor parametri. Într-adevăr, utilizarea de shell steps este simplă și ușor de folosit, însă beneficiile integrării Jenkins DSL, cum ar fi tratarea erorilor și excepțiilor, codul curat și ușor de menținut, fac să merite prețul investiției în investigarea limbajului de pipeline specific Jenkins (Groovy).
Un pipeline care să definească pașii end-to-end include testarea și validarea codului de pipeline în sine dar și a infrastructurii. Procesele descrise de Continuous Integration sunt potrivite atât pentru cod utilizat pentru configurarea mediilor de instalare a software-ului, dar și pentru validarea pipeline-urilor de build. În acest moment, se poate lua în considerare integrarea altor tooluri a căror scop este să susțină mișcarea DevOps. De asemenea, vizată este și automatizarea proceselor manuale repetitive și susceptibile la erori pentru a permite echipelor să investească mai mult timp în inovație și îmbunătățirea proceselor actuale. Adăugarea de tooluri, cum ar fi Chef, Ansible sau Puppet care au rolul de a oferi Configuration Management pot fi considerate costisitoare pe un termen scurt. Însă, privind dintr-o perspectivă de viitor, beneficiile sunt măsurabile și efectul lor este vizibil și în ceea ce privește satisfacția profesională, deoarece ciclurile de feedback sunt rapide.
Din punctul meu de vedere, există două cazuri extreme în ceea ce privește alegerea de tooluri. În primul rând, utilizarea unui tool sau două care acoperă majoritatea use case-urilor, dar necesită o logică complicată pentru a o implementa nevoilor specifice de orchestrare. Al doilea caz este utilizarea unui număr mare de tooluri, fiecare servind un scop diferit, fapt care rezultă într-un proces lung de învățare.
Costul de integrare a toolurilor există și limita între a alege un număr mare de tehnologii și Acceptarea a ceea ce este deja cunoscut este variabilă. Singura modalitate de a găsi rețeta potrivită este prin experimentare și investirea timpului în Proof of Concepts. Având un mindset orientat spre efectul măsurabil și promovarea unei culturi de shared knowledge și ownership, provocările de a utiliza și integra tooluri se vor diminua substanțial.
O altă consecință a utilizării codului pentru descrierea pipeline-urilor și a toolurilor este repetabilitatea, sau mai exact, evitarea ei. Singura modalitate de a urma acest concept DRY este prin implementarea și promovarea standardizării, utilizarea convențiilor și investirea timpului pentru a crea un ghid pentru proiectele care urmează aceeași schemă de build și deploy. Contraargumentul este deductibil: nu toate cazurile pot fi acoperite. Un mod de a aborda această situație dintr-un punct de vedere al orchestrării este prin implementarea unor pipeline-uri parametrizate, standardizarea infrastructurii și prin aplicarea de principii similare celor de development al aplicației și asupra designului de pipeline (e.g. arhitecturi loosely vs tightly coupled).
A deține un pipeline declarat sub formă de stagii separate are ca avantaj oportunitatea de a paraleliza execuția, reutilizarea codului și simplitatea implementării care este ușor de menținut.
Imagine PagerDuty
Având un ecosistem stabil de tooluri și procese definite, ceea ce rămâne este orchestrarea tuturor componentelor. Această orchestrare poate conține un număr de joburi separate, fiecare deservind taskuri diferite, care sunt înlănțuite cu ajutorul unui engine de orchestrare, de exemplu, Jenkins. Cazurile comune de utilizare ar fi: testarea configurării infrastructurii folosind un mediu de tip sandbox sau posibilitatea ca generarea unui nou artefact să determine configurarea mediului și a aplicației și instalarea efectivă ș.a.m.d.
Obiectivul principal trebuie să fie oamenii și definirea proceselor care să susțină colaborarea eficientă. Designul și implementarea de deployment pipeline trebuie să asigure cel mai rapid feedback indiferent de natura aplicației, configurării sau toolului utilizat. Continuous integration și Contrinuous Delivery nu sunt restricționate developmentului de produs, iar abordarea potrivită poate fi identificată doar prin experimentare și învățare continuă.
de Ovidiu Mățan
de Ovidiu Mățan