Pe undeva prin 2019, „infrastructure as code” a devenit sinonim cu Terraform în majoritatea conversațiilor, așa cum „căutare” înseamnă Google. E un default rezonabil. E și unealta greșită pentru o parte semnificativă a echipelor, iar motivul nu sunt funcționalitățile, pe care le au toate cele trei opțiuni serioase, ci cine va scrie și citi codul.
Noi rulăm platformele clienților pe AWS CDK. Am livrat Terraform și Pulumi pentru alți clienți. Asta e comparația pe care ne-ar fi plăcut s-o citim înainte să alegem, organizată în jurul întrebării care decide, cu compromisurile spuse pe șleau și cazurile în care tot Terraform am alege.
Întrebarea
Infrastructura e deținută de echipa de aplicație sau de o echipă de platformă separată?
Dacă oamenii care scriu aplicația Next.js sunt oamenii care scriu infrastructura, ei au deja un limbaj, un package manager, un test runner și un editor configurat pentru TypeScript. Să le dai un al doilea limbaj (HCL) cu semantica lui, sistemul lui de module și povestea lui de testare e un cost plătit în fiecare zi de fiecare om. CDK sau Pulumi îi lasă să definească infrastructura în limbajul în care gândesc deja, în același repository, cu același proces de revizuire, și să împartă tipuri între aplicație și infra.
Dacă infrastructura e deținută de o echipă de platformă care servește multe echipe de aplicație în multe limbaje, calculul se inversează. Echipa aia vrea un singur limbaj pentru toată infrastructura indiferent în ce sunt scrise aplicațiile, un model declarativ ușor de revizuit peste sute de module, un ecosistem uriaș de provideri și un output de plan pe care un ne-programator îl poate citi într-un tichet de schimbare. Ăsta e terenul Terraform, iar limitările HCL sunt o calitate acolo: e greu să fii prea deștept în el.
Tot restul comparației decurge din răspunsul ăsta.
Cele trei, sincer
| Terraform / OpenTofu | AWS CDK | Pulumi | |
|---|---|---|---|
| Limbaj | HCL, declarativ | TypeScript, Python, Java, Go, C#; sintetizează în CloudFormation | TypeScript, Python, Go, C#, Java, YAML; motor propriu |
| Cloud-uri | Toate, prin provideri; cel mai mare ecosistem | Doar AWS (există CDK for Terraform, dar ăla e Terraform) | Toate, prin provideri, mulți învelind provideri Terraform |
| Stare | Un fișier de stare pe care îl gestionezi: S3 + locking, sau Terraform Cloud | CloudFormation o ține; nimic de gestionat, nimic de corupt | Pulumi Cloud, sau S3 auto-gestionat |
| Plan / diff | terraform plan: precis, lizibil, standardul de aur |
cdk diff: bun pentru resurse, slab pentru IAM și unele schimbări de proprietăți |
pulumi preview: bun, între cele două |
| Abstracții | Module; compoziția e verboasă, fără tipuri reale | Construct-uri cu tipuri reale; construct-urile L2 încorporează bune practici (un Queue primește criptare, un Bucket blochează accesul public) |
Componente, tipuri reale, plus poți importa construct-uri CDK |
| Testare | Aserțiuni pe plan, Terratest (Go) | Jest pe template-ul sintetizat; rapid și precis | Teste unitare în limbaj, cu mock-uri |
| Mod de eșec | Drift de stare; un lock uitat; upgrade-uri de provider | Limitele CloudFormation: 500 de resurse per stack, rollback-uri lente, semantica de înlocuire | Bug-urile motorului sunt ale tale de depanat; comunitate mai mică |
| Se citește bine pentru | Revizori care nu programează | Programatori | Programatori |
| Cine plătește | Schimbările de licență HashiCorp din 2023; OpenTofu e fork-ul comunității | Gratuit; problema AWS | OSS gratuit; serviciul cloud e plătit |
Trei lucruri din tabelul ăla decid mai multe alegeri decât tot restul la un loc.
Starea. Fișierul de stare Terraform e sursa majorității incidentelor Terraform la care am fost chemați: o stare coruptă după un apply întrerupt, un lock vechi, o stare care face referire la o resursă ștearsă de mână de cineva, o migrare între backend-uri care a mers prost. CDK n-are fișier de stare; CloudFormation este starea, și e problema AWS s-o țină consistentă. Doar asta elimină o întreagă categorie de muncă operațională. Prețul sunt ciudățeniile proprii ale CloudFormation, care sunt reale, dar cărora nu le-am pierdut niciodată un fișier de stare.
Diff-ul. terraform plan e cu adevărat cea mai bună previzualizare de schimbare din industrie, și e o mare parte din motivul pentru care echipele de platformă îl iubesc. cdk diff e suficient de bun pentru cazul zilnic și prost pentru IAM: arată că o politică s-a schimbat, dar nu arată întotdeauna cum. Compensăm cu cdk-nag și cu o politică de a lipi IAM-ul sintetizat în PR pentru orice schimbare care îl atinge. Dacă procesul tău de revizuire e „cineva care nu scrie cod citește planul”, Terraform câștigă aici și nu e aproape.
Abstracții cu tipuri. În CDK, new sqs.Queue(this, 'Q') îți dă o coadă criptată cu default-uri rezonabile, iar queue.grantConsumeMessages(fn) scrie politica IAM pentru tine, corect, cu ARN-ul exact. Echivalentul în Terraform e un modul scris de cineva, sau douăzeci de linii de JSON de politică pe care le scrii de mână și le greșești o dată. Diferența asta se compune pe o platformă: codebase-ul nostru CDK pentru trei conturi are vreo 6.000 de linii; echivalentul Terraform l-am estimat la cam dublu, înainte de module.
Când tot Terraform am alege
- Multi-cloud cu o echipă de platformă. Un limbaj, un workflow, fiecare provider. Pulumi poate face și asta, dar ecosistemul Terraform de module și provideri e cu un deceniu mai adânc.
- Orice în care revizorul nu e programator. Medii conduse de conformitate unde tichetul de schimbare trebuie să conțină un plan pe care un auditor îl citește. HCL și
terraform planau fost construite pentru asta. - Non-AWS, un singur cloud, echipă mică. Echipele GCP sau Azure fără o identitate TypeScript puternică sunt de obicei mai bine cu Terraform decât cu Pulumi, doar pe mărimea comunității.
- O echipă care îl are deja și funcționează. Migrarea unui Terraform funcțional la CDK din motive estetice e un schimb prost. Am refuzat job-ul ăla de două ori.
Când Pulumi, în locul CDK
Când echipa e nativ TypeScript și proprietatea nu e pur AWS: o zonă Cloudflare, un proiect Vercel, un set de monitoare Datadog, un bucket GCP, alături de resursele AWS. CDK se oprește la granița AWS; Pulumi nu. Pulumi are și diff-ul mai bun dintre cele două și un motor mai rapid decât CloudFormation pentru stack-uri mari. Costul e o comunitate mai mică și un backend de stare pe care fie îl plătești, fie îl rulezi.
Ce rulăm noi, și de ce
CDK, TypeScript, pentru fiecare platformă de client doar pe AWS. Echipele de aplicație sunt echipe TypeScript; infrastructura stă în infra/ în același monorepo cu aplicațiile; tipurile rutelor API-ului și numele variabilelor de mediu ale infra-ului vin din același packages/types; o schimbare la o coadă și la consumatorul ei e un singur PR. Niciun fișier de stare, niciodată. cdk diff lipit în fiecare PR, IAM sintetizat și lipit pentru orice îl atinge, cdk-nag în CI, aserțiuni Jest pe template-uri pentru invarianții la care ținem (fiecare bucket blochează accesul public, fiecare coadă are un DLQ, niciun DESTROY în afara unui stack de demontare numit).
Plătim pentru asta cu limitele și lentoarea CloudFormation, despre care am scris pe larg, și cu golul din diff-ul IAM, pe care regula lipirii în PR îl acoperă. Pentru echipele astea e schimbul corect cu o marjă largă. Pentru o echipă de platformă care servește douăsprezece limbaje pe două cloud-uri, le-am spune Terraform, și am vorbi serios.
Versiunea scurtă
Infrastructure as code e o practică, nu un produs. Practica e: infrastructura e într-un repository, schimbările sunt revizuite, nimic nu se dă click. Produsul e ales de cine deține codul. Echipă de aplicație în TypeScript pe AWS: CDK. Aceeași echipă, mai mult decât AWS: Pulumi. Echipă de platformă, multe limbaje, planuri citite de ne-programatori: Terraform. Terraform funcțional pe care îl ai deja: păstrează-l.
Dacă alegi, sau ai moștenit o alegere care nu se potrivește echipei, noi le-am rulat pe toate trei și îți spunem care se potrivește cu a ta, inclusiv când răspunsul e „cea pe care o ai”.