Construirea și administrarea unei infrastructuri serverless cu terraform în Amazon Cloud a presupus întâlnirea cu o serie de obstacole, precum comiterea unor erori. Acest articol își propune să ofere o serie de recomandări, care odată puse în aplicare, vor reduce riscul apariției de erori.
Terraform este instrumentul perfect pentru Infrastructure as Code, folosit atunci când este necesar de furnizat și administrat un serverless stack în Amazon Cloud.
Serverless computing este un model de calcul în care un furnizor de servicii cloud gestionează automat furnizarea și alocarea resurselor.
Această implementare a arhitecturii serverless este numită Functions as a Service (FaaS).
Utilizarea serviciilor serverless a avut o mulțime de avantaje și beneficii datorită faptului că se plătește numai pentru execuție și durată, nu s-a investit timp pentru administrarea de servere, sisteme de operare sau alte aplicații ca dependințe. De asemenea, serviciile serverless oferă o autonomie ridicată, care reduce timpul de lucru pe arhitectură și configurează aceste elemente în mediul AWS.
Un dezavantaj a fost faptul că ne-am confruntat cu unele blocaje de I/O care nu s-au putut replica și cu lipsa de vizibilitate în depanarea fluxurilor aplicației.
Parolele hardcoded nu sunt periculoase doar din cauza hackerilor și a atacurilor de tip DDoS și malware, ci și pentru că îngreunează refolosirea codului sursă.
AWS Secret Manager este un serviciu pentru administrarea credențialelor, stocarea, extragerea și rotarea cheilor de acces între resurse.
Asigurați-vă că stocați credențialele și cheile de access într-un secret manager tool, nu pe laptopul propriu sau hardcoded în codul sursă găzduit în git.
Funcția lambda conține codul sursă și dependințele în format zip, iar arhiva este încărcată într-un S3 bucket pe baza unui indicator de timp.
În cazul de față, indicatorul de timp dă numele versiunii funcției lambda și cheii folosite de terraform pentru a găsi arhiva funcției lambda în bucket:
Pentru o bună gestionare a aplicației, a fost adăugat un fișier de manifest, actualizat automat la fiecare build, cu rolul de a stoca versiunile funcțiilor lambda aferente fiecărui release. Pe baza acestui fișier, aplicația poate fi lansată în mediul de lucru și se poate reveni cu ușurință la o versiune anterioară în caz de nevoie.
Este mai bine să împărțim dependințele pentru o resursă în mai multe părți componente, decât să avem un singur fișier mare de configurare.
În exemplul de mai jos, resursa funcției lambda va lua rolul ce îi dă dreptul de a accesa resurse AWS dintr-un alt fișier de configurare iam.tf (fișier responsabil pentru crearea tuturor rolurilor și permisiunilor pentru resursele AWS) și va prelua definiția de rol dintr-un fișier extern:
Astfel, veți ușura procesul de debugging, iar componentele vor putea fi refolosite și în alte module. Toate acestea vor duce la o vizibilitate sporită asupra funcționalității codului de infrastructură.
După divizarea codului de infrastructură pe componente, e necesar să se folosească terraform remote state pentru a utiliza variabile între module.
În cazul de față, după implementarea unui flux lambda, se vrea atașarea unei notificări pe baza unui eveniment pentru o funcție lambda. Pentru aceasta, luăm din remote state (data store care deține resursele și metadata pentru infrastructura creată) numele resursei create și o atașăm în fluxul curent care va implementa notificările.
Pentru a evita duplicarea codului, utilizați terraform workspace pentru separarea mediilor de lucru.
Toate mediile sunt gestionate ca o bază de cod și sunt găzduite într-un git repo. Există mai multe abordări de împărțire a configurării între mediile de lucru. Se pot utiliza subfoldere, o soluție care îngreunează întreținerea codului din cauza fișierelor duplicate. Începând cu Terraform, versiunea 0.10 se poate utiliza comanda workspace pentru organizarea infrastructurii.
Ambele abordări au compromisuri, dar terraform workspace este o funcție excelentă care poate fi utilizată pentru a separa mediul actual cu scopul de a testa o nouă funcționalitate.
În mod implicit, toate logurile sunt monitorizate cu AWS CloudWatch. Pentru o vizualizare mai bună, se pot crea dashboarduri personalizate cu acest serviciu, dar chiar și așa, există nevoia de a naviga prin mai multe ecrane pentru a obține logurile și valorile dorite, ceea ce creează un dezavantaj în depanarea fluxurilor aplicației. Pentru a evita acest inconvenient, se recomandă serviciul AWS Elasticsearch.
Deoarece grupurile de loguri pentru funcțiile lambda din AWS CloudWatch nu au putut fi manipulate sau îmbinate, s-a folosit CloudWatch ca serviciu de agregare a logurilor, de unde o funcție lambda creată special pentru streaming va prelua logurile și le va transfera în API-ul de import Elasticsearch prin protocolul HTTPS.
Imaginea alăturată arată cum putem căuta eroarea "accessdenied" și numele unei funcții lambda și astfel să descoperim cu ușurință greșeala. În cazul de față, rolul funcției lambda nu are acces la anumite acțiuni în servicul AWS CloudWatch.
O necesitate este testarea infrastructurii. Aceasta poate fi făcută prin utilizarea unei librării scrisă în limbajul ruby, care va testa resursele din AWS pe baza unor specificații. În exemplul de mai jos, testele unitare sunt rulate cu succes pentru o tabelă din baza de date AWS DynamoDB a aplicației.
Un dezavantaj este faptul că nu toate resursele din AWS sunt acoperite de această librărie. Menționăm în acest sens servicii precum cum ar fi AthenaDB sau StepFunctions. Din moment ce librăria e doar cod ruby , se poate scrie propriul cod pentru a testa resursele neacoperite sau alte funcționalități specifice aplicației cum ar fi verificarea unui query în baza de date DynamoDB.
În concluzie, testează totul!