Terraform vs. CloudFormation: Ghidul definitiv
Publicat: 2022-03-11Dacă, la fel ca mine, ați căutat pe internet pentru a vă ajuta să alegeți între CloudFormation și Terraform ca următorul instrument de infrastructură ca cod (IaC) fără a găsi un răspuns definitiv, v-am împărtășit durerea mult timp. Acum, am o experiență semnificativă cu ambele instrumente și pot lua o decizie informată despre care să folosesc.
TL;DR
Pentru proiectul dvs. IaC pe AWS, alegeți CloudFormation, deoarece:
- CloudFormation face o distincție între cod (adică, șabloane) și instanțierea codului (adică, stive). În Terraform, nu există o astfel de distincție. Mai multe despre asta în secțiunea următoare.
- Terraform nu se descurcă foarte bine cu gestionarea dependenței de bază. Mai multe despre asta într-o secțiune ulterioară.
Diferențierea între cod și instanțieri
O diferență între CloudFormation și Terraform este modul în care codul și instanțiile se relaționează unul cu celălalt în cadrul fiecărui serviciu.
CloudFormation are conceptul de stivă , care este instanțierea unui șablon. Același șablon poate fi instanțiat la infinit de către un anumit client într-un anumit cont, între conturi sau de către diferiți clienți.
Terraform nu are un astfel de concept și necesită o relație unu-la-unu între cod și instanțierea acestuia. Ar fi similar cu duplicarea codului sursă al unui server web pentru fiecare server pe care doriți să-l rulați sau duplicarea codului de fiecare dată când trebuie să rulați o aplicație în loc să rulați versiunea compilată.
Acest punct este destul de banal în cazul unei configurații simple, dar devine rapid un punct de durere major pentru operațiunile la scară medie și mare. În Terraform, de fiecare dată când trebuie să rotiți o stivă nouă din codul existent, trebuie să duplicați codul. Și copierea/lipirea fișierelor script este o modalitate foarte ușoară de a vă sabota și de a corupe resursele pe care nu ați intenționat să le atingeți.
Terraform de fapt nu are un concept de stive precum CloudFormation, care arată clar că Terraform a fost construit de la zero pentru a avea o potrivire unu-la-unu între cod și resursele pe care le gestionează. Acest lucru a fost ulterior rectificat parțial de conceptul de medii (care de atunci au fost redenumite „spații de lucru”), dar modul de utilizare a acestora face incredibil de ușor de implementat într-un mediu nedorit. Acest lucru se datorează faptului că trebuie să rulați terraform workspace select
înainte de implementare, iar uitarea acestui pas va fi implementat în spațiul de lucru selectat anterior, care ar putea fi sau nu cel dorit.
În practică, este adevărat că această problemă este atenuată de utilizarea modulelor Terraform, dar chiar și în cel mai bun caz, ați avea nevoie de o cantitate semnificativă de cod boilerplate. De fapt, această problemă a fost atât de acută încât oamenii au trebuit să creeze un instrument de înveliș în jurul Terraform pentru a rezolva această problemă: Terragrunt.
Management de stat și permisiuni
O altă diferență importantă între CloudFormation și Terraform este modul în care fiecare gestionează starea și permisiunile.
CloudFormation gestionează stările stivei pentru dvs. și nu vă oferă nicio opțiune. Dar stările stivei CloudFormation au fost solide din experiența mea. De asemenea, CloudFormation permite utilizatorilor mai puțin privilegiați să gestioneze stivele fără a avea toate permisiunile necesare cerute de stiva în sine. Acest lucru se datorează faptului că CloudFormation poate obține permisiunile de la un rol de serviciu atașat la stivă, mai degrabă decât permisiunile de la utilizatorul care execută operația de stivă.
Terraform vă cere să îi furnizați câteva back-end-uri pentru a gestiona stările. Implicit este un fișier local, care este total nesatisfăcător, având în vedere:
- Robustețea fișierului dvs. de stare este în întregime legată de robustețea mașinii pe care este stocat.
- Asta face aproape imposibilă munca în echipă.
Deci, aveți nevoie de o stare robustă și partajată, care pe AWS este de obicei obținută prin utilizarea unui bucket S3 pentru a stoca fișierul de stare, însoțit de un tabel DynamoDB pentru a gestiona concurența.
Aceasta înseamnă că trebuie să creați manual o găleată S3 și un tabel DynamoDB pentru fiecare stivă pe care doriți să o instanțiați și, de asemenea, să gestionați manual permisiunile pentru aceste două obiecte pentru a restricționa utilizatorii mai puțin privilegiați să aibă acces la datele la care nu ar trebui să aibă acces. Dacă aveți doar câteva stive, nu va fi o problemă prea mare, dar dacă aveți 20 de stive de gestionat, devine foarte greoaie.
Apropo, atunci când utilizați spații de lucru Terraform, nu este posibil să aveți un tabel DynamoDB per spațiu de lucru. Aceasta înseamnă că, dacă doriți ca un utilizator IAM cu permisiuni minime să efectueze implementări, acel utilizator va putea să se ocupe de blocările tuturor spațiilor de lucru, deoarece permisiunile DynamoDB nu sunt detaliate la nivel de articol.
Managementul Dependenței
În acest punct, atât CloudFormation, cât și Terraform pot fi puțin complicate. Dacă modificați ID-ul logic (adică, numele) unei resurse, ambii vor considera că vechea resursă trebuie distrusă și creată una nouă. Deci, în general, este o idee proastă să schimbați ID-ul logic al resurselor în oricare dintre instrumente, în special pentru stivele imbricate în CloudFormation.
După cum sa menționat în prima secțiune, Terraform nu se ocupă de dependențele de bază. Din păcate, dezvoltatorii Terraform nu acordă multă atenție problemei de lungă durată, în ciuda aparentei lipse de soluții.
Având în vedere că gestionarea adecvată a dependenței este absolut esențială pentru un instrument IaC, astfel de probleme din Terraform pun sub semnul întrebării adecvarea acestuia de îndată ce sunt implicate operațiuni critice pentru afaceri, cum ar fi implementarea într-un mediu de producție. CloudFormation oferă o senzație mult mai profesională, iar AWS este întotdeauna foarte atent să se asigure că oferă clienților săi instrumente de calitate. În toți anii în care am folosit CloudFormation, nu am întâlnit niciodată o problemă cu gestionarea dependențelor.
CloudFormation permite unei stive să exporte unele dintre variabilele sale de ieșire, care pot fi apoi reutilizate de alte stive. Pentru a fi sincer, această funcționalitate este limitată, deoarece nu veți putea instanția mai mult de o stivă per regiune. Acest lucru se datorează faptului că nu puteți exporta două variabile cu același nume, iar variabilele exportate nu au spații de nume.
Terraform nu oferă astfel de facilități, așa că rămâneți cu opțiuni mai puțin dorite. Terraform vă permite să importați starea unei alte stive, dar asta vă oferă acces la toate informațiile din acel stivă, inclusiv la numeroasele secrete care sunt stocate în stare. Alternativ, o stivă poate exporta unele variabile sub forma unui fișier JSON stocat într-o găleată S3, dar din nou, această opțiune este mai greoaie: trebuie să decideți ce găleată S3 să utilizați și să îi acordați permisiunile corespunzătoare și să scrieți toate codificați-vă de instalații atât pe partea scriitorului, cât și a cititorului.
Un avantaj al Terraform este că are surse de date. Terraform poate interoga astfel resursele care nu sunt gestionate de Terraform. Cu toate acestea, în practică, acest lucru are o relevanță mică atunci când doriți să scrieți un șablon generic, deoarece atunci nu veți presupune nimic despre contul țintă. Echivalentul în CloudFormation este să adăugați mai mulți parametri de șablon, ceea ce implică astfel repetiție și potențialul de erori; cu toate acestea, din experiența mea, aceasta nu a fost niciodată o problemă.
Revenind la problema gestionării dependențelor Terraform, un alt exemplu este că obțineți o eroare când încercați să actualizați setările pentru un echilibrator de încărcare și obțineți următoarele:
Error: Error deleting Target Group: ResourceInUse: Target group 'arn:aws:elasticloadbalancing:us-east-1:723207552760:targetgroup/strategy-api-default-us-east-1/14a4277881e84797' is currently in use by a listener or a rule status code: 400, request id: 833d8475-f702-4e01-aa3a-d6fa0a141905
Comportamentul așteptat ar fi că Terraform detectează că grupul țintă este o dependență de o altă resursă care nu este ștearsă și, în consecință, nu ar trebui să încerce să o ștergă, dar nici nu ar trebui să arunce o eroare.
Operațiuni
Deși Terraform este un instrument de linie de comandă, este foarte clar că se așteaptă ca un om să îl ruleze, deoarece este foarte interactiv. Este posibil să-l rulați în modul batch (adică dintr-un script), dar acest lucru necesită câteva argumente suplimentare de linie de comandă. Faptul că Terraform a fost dezvoltat pentru a fi condus de oameni în mod implicit este destul de nedumerit, având în vedere că scopul unui instrument IaC este automatizarea.
Terraform este dificil de depanat. Mesajele de eroare sunt adesea foarte elementare și nu vă permit să înțelegeți ce nu merge bine, caz în care va trebui să rulați Terraform cu TF_LOG=debug
, ceea ce produce o cantitate imensă de ieșire pe care să o căutați. Complicând acest lucru, Terraform face uneori apeluri API către AWS care eșuează, dar eșecul nu este o problemă cu Terraform. În schimb, CloudFormation oferă mesaje de eroare destul de clare, cu suficiente detalii pentru a vă permite să înțelegeți unde este problema.
Un exemplu de mesaj de eroare Terraform:
Error: error reading S3 bucket Public Access Block: NoSuchBucket: The specified bucket does not exist status code: 404, request id: 19AAE641F0B4AC7F, host id: rZkgloKqxP2/a2F6BYrrkcJthba/FQM/DaZnj8EQq/5FactUctdREq8L3Xb6DgJmyKcpImipv4s=
Mesajul de eroare de mai sus arată un mesaj de eroare clar care de fapt nu reflectă problema de bază (care în acest caz a fost o problemă de permisiuni).

Acest mesaj de eroare arată, de asemenea, cum Terraform se poate picta uneori într-un colț. De exemplu, dacă creați o găleată S3 și o resursă aws_s3_bucket_public_access_block
pe acea găleată și dacă, dintr-un motiv oarecare, faceți unele modificări în codul Terraform care distruge acea găleată — de exemplu, în „modificarea implică ștergerea și crearea” gotcha descris mai sus— Terraform va rămâne blocat încercând să încarce aws_s3_bucket_public_access_block
, dar eșuând continuu cu eroarea de mai sus. Comportamentul corect de la Terraform ar fi înlocuirea sau ștergerea aws_s3_bucket_public_access_block
după caz.
În cele din urmă, nu puteți utiliza scripturile de ajutor CloudFormation cu Terraform. Aceasta ar putea fi o enervare, mai ales dacă sperați să utilizați cfn-signal, care îi spune lui CloudFormation că o instanță EC2 s-a inițializat și este gata să răspundă cererilor.
Sintaxă, comunitate și Rolling Back
Din punct de vedere al sintaxelor, Terraform are un avantaj bun în comparație cu CloudFormation - acceptă bucle. Dar, din propria mea experiență, această caracteristică se poate dovedi a fi puțin periculoasă. De obicei, o buclă ar fi folosită pentru a crea un număr de resurse identice; totuși, atunci când doriți să actualizați stiva cu un număr diferit, ar putea exista șansa să fie nevoie să legați resursele vechi și noi (de exemplu, folosind zipmap()
pentru a combina valorile din două matrice care acum se întâmplă să fie de dimensiuni diferite, deoarece o matrice are dimensiunea vechii dimensiuni a buclei, iar cealaltă are dimensiunea noii dimensiuni a buclei). Este adevărat că o astfel de problemă se poate întâmpla fără bucle, dar fără bucle, problema ar fi mult mai evidentă pentru persoana care scrie scenariul. Utilizarea buclelor într-un astfel de caz ofusca problema.
Dacă sintaxa lui Terraform sau sintaxa CloudFormation este mai bună, este în mare parte o chestiune de preferințe. CloudFormation a acceptat inițial doar JSON, dar șabloanele JSON sunt foarte greu de citit. Din fericire, CloudFormation acceptă și YAML, care este mult mai ușor de citit și permite comentarii. Cu toate acestea, sintaxa CloudFormation tinde să fie destul de verbosă.
Sintaxa lui Terraform folosește HCL, care este un fel de derivat JSON și este destul de idiosincratic. Terraform oferă mai multe funcții decât CloudFormation și, de obicei, sunt mai ușor de înțeles. Deci s-ar putea argumenta că Terraform are un ușor avantaj în acest punct.
Un alt avantaj al Terraform este setul său ușor disponibil de module întreținute de comunitate, iar acest lucru simplifică scrierea șabloanelor. O problemă ar putea fi că astfel de module ar putea să nu fie suficient de sigure pentru a se conforma cerințelor unei organizații. Așadar, pentru organizațiile care necesită un nivel ridicat de securitate, revizuirea acestor module (precum și a versiunilor ulterioare pe măsură ce apar) ar putea fi o necesitate.
În general, modulele Terraform sunt mult mai flexibile decât stivele imbricate CloudFormation. O stivă imbricată CloudFormation tinde să ascundă totul sub ea. Din stiva imbricată, o operație de actualizare ar arăta că stiva imbricată va fi actualizată, dar nu arată în detaliu ce se va întâmpla în interiorul stivei imbricate.
Un ultim punct, care ar putea fi de fapt controversat, este că CloudFormation încearcă să anuleze implementările eșuate. Aceasta este o caracteristică destul de interesantă, dar poate fi, din păcate, foarte lungă (de exemplu, ar putea dura până la trei ore pentru ca CloudFormation să decidă că o implementare în Elastic Container Service a eșuat). În schimb, în caz de eșec, Terraform se oprește oriunde ar fi fost. Dacă o caracteristică de rollback este un lucru bun sau nu este discutabil, dar am ajuns să apreciez faptul că o stivă este menținută într-o stare de funcționare cât mai mult posibil atunci când o așteptare mai lungă se întâmplă să fie un compromis acceptabil.
În apărarea Terraform vs. CloudFormation
Terraform are avantaje față de CloudFormation. Cel mai important, după părerea mea, este că atunci când aplicați o actualizare, Terraform vă arată toate modificările pe care urmează să le faceți, inclusiv detalierea tuturor modulelor pe care le folosește. În schimb, CloudFormation, când folosești stive imbricate, îți arată doar că stiva imbricată trebuie actualizată, dar nu oferă o modalitate de a detalia detaliile. Acest lucru poate fi frustrant, deoarece acest tip de informații este destul de important de știut înainte de a apăsa butonul „go”.
Atât CloudFormation, cât și Terraform acceptă extensii. În CloudFormation, este posibil să gestionați așa-numitele „resurse personalizate” folosind o funcție AWS Lambda creată de dvs. ca back-end. Pentru Terraform, extensiile sunt mult mai ușor de scris și fac parte din cod. Deci există un avantaj pentru Terraform în acest caz.
Terraform poate gestiona mulți furnizori de cloud. Acest lucru îl pune pe Terraform într-o poziție de a putea unifica o anumită implementare între mai multe platforme cloud. De exemplu, să presupunem că aveți un singur volum de lucru repartizat între AWS și Google Cloud Platform (GCP). În mod normal, partea AWS a sarcinii de lucru ar fi implementată utilizând CloudFormation, iar partea GCP utilizând Managerul de implementare cloud al GCP. Cu Terraform, puteți folosi un singur script pentru a implementa și a gestiona ambele stive în platformele lor cloud respective. În acest fel, trebuie să implementezi doar o stivă în loc de două.
Non-argumente pentru Terraform vs. CloudFormation
Există destul de multe non-argumente care continuă să circule pe internet. Cel mai mare lucru este că, deoarece Terraform este multi-cloud, puteți folosi un singur instrument pentru a vă implementa toate proiectele, indiferent în ce platformă cloud sunt realizate. Din punct de vedere tehnic, acest lucru este adevărat, dar nu este marele avantaj care poate părea să fie, mai ales atunci când gestionați proiecte tipice single-cloud. Realitatea este că există o corespondență aproape unu-la-unu între resursele declarate în (de exemplu) CloudFormation și aceleași resurse declarate într-un script Terraform. Deoarece trebuie să cunoașteți detaliile resurselor specifice cloud în orice caz, diferența se reduce la sintaxă, care nu este cel mai mare punct de durere în gestionarea implementărilor.
Unii susțin că, folosind Terraform, se poate evita blocarea vânzătorului. Acest argument nu este valabil în sensul că, folosind Terraform, ești blocat de HashiCorp (creatorul Terraform), la fel cum, folosind CloudFormation, ești blocat de AWS și așa mai departe pentru alt cloud platforme.
Faptul că modulele Terraform sunt mai ușor de utilizat este pentru mine de o importanță mai mică. În primul rând, cred că AWS dorește în mod deliberat să evite găzduirea unui singur depozit pentru șabloanele CloudFormation bazate pe comunitate din cauza responsabilității percepute pentru găurile de securitate create de utilizator și încălcările diferitelor programe de conformitate.
La un nivel mai personal, înțeleg pe deplin beneficiile utilizării bibliotecilor în cazul dezvoltării de software, deoarece acele biblioteci pot rula cu ușurință în zeci de mii de linii de cod. În cazul IaC, totuși, dimensiunea codului este de obicei mult mai mică, iar astfel de module sunt de obicei lungi de câteva zeci de linii. Folosirea copy/paste nu este de fapt o idee atât de rea, în sensul că evită problemele legate de menținerea compatibilității și de delegarea securității unor persoane necunoscute.
Utilizarea copierii/lipirii este descurajată de mulți dezvoltatori și ingineri DevOps și există motive întemeiate în spatele acestui lucru. Cu toate acestea, punctul meu de vedere este că utilizarea copierii/lipirii pentru fragmente de cod vă permite să-l adaptați cu ușurință la nevoile dvs. și nu este nevoie să faceți o bibliotecă din ea și să petreceți mult timp pentru a o face generică. Durerea de a menține acele fragmente de cod este de obicei foarte mică, cu excepția cazului în care codul dvs. devine duplicat în, de exemplu, o duzină sau mai multe șabloane. Într-un astfel de caz, însușirea codului și utilizarea lui ca stive imbricate are sens, iar beneficiile de a nu te repeta sunt probabil mai mari decât supărarea de a nu putea vedea ce va fi actualizat în interiorul stivei imbricate atunci când efectuați o actualizare. Operațiune.
Concluzie CloudFormation vs. Terraform
Cu CloudFormation, AWS dorește să ofere clienților săi un instrument solid, care va funcționa conform intenției în orice moment. Echipa Terraform face și ea, desigur, dar se pare că un aspect crucial al instrumentelor lor, gestionarea dependenței, nu este, din păcate, o prioritate.
Terraform ar putea avea un loc în proiectul dvs., mai ales dacă aveți o arhitectură multi-cloud, caz în care scripturile Terraform reprezintă o modalitate de a unifica gestionarea resurselor între diferiții furnizori de cloud pe care îi utilizați. Dar puteți evita totuși dezavantajele Terraform în acest caz utilizând Terraform doar pentru a gestiona stivele deja implementate folosind instrumentele lor IaC specifice cloud.
Sentimentul general Terraform vs. CloudFormation este că CloudFormation, deși imperfect, este mai profesionist și mai de încredere și l-aș recomanda cu siguranță pentru orice proiect care nu este în mod specific multi-cloud.