Update, 17 noiembrie 2016: am luat această serie de postări pe blog, am extins-o și am transformat-o într-o carte numită Terraform: Up& Running!
actualizare, 8 iulie 2019: am actualizat această serie de postări pe blog pentru Terraform 0.12 și am lansat a 2-a ediție a Terraform: Up & rulează!
aceasta este partea 1 a Ghidului cuprinzător pentru seria Terraform. În introducerea seriei, am discutat de ce fiecare companie ar trebui să utilizeze infrastructure-as-code (IAC). În acest post, vom discuta De ce am ales Terraform ca instrumentul nostru iac de alegere.
dacă căutați pe Internet „infrastructură-ca-cod”, este destul de ușor să veniți cu o listă cu cele mai populare instrumente:
- Chef
- Puppet
- Ansible
- SaltStack
- CloudFormation
- Terraform
ceea ce nu este ușor este să vă dați seama care dintre acestea ar trebui să utilizați. Toate aceste instrumente pot fi utilizate pentru a gestiona infrastructura ca cod. Toate acestea sunt open source, susținute de comunități mari de contribuabili și lucrează cu mulți furnizori de cloud diferiți (cu excepția notabilă a CloudFormation, care este doar sursă închisă și AWS). Toate acestea oferă suport pentru întreprinderi. Toate acestea sunt bine documentate, atât în ceea ce privește documentația oficială, cât și resursele comunității, cum ar fi postările pe blog și întrebările StackOverflow. Deci, cum te decizi?ceea ce face acest lucru și mai greu este că majoritatea comparațiilor pe care le găsiți online între aceste instrumente nu fac decât să enumere proprietățile generale ale fiecărui instrument și să sune ca și cum ați putea avea la fel de succes cu oricare dintre ele. Și, deși acest lucru este adevărat din punct de vedere tehnic, nu este util. Este un pic ca și cum ai spune unui începător de programare că ai putea avea la fel de mult succes în construirea unui site web cu PHP, C sau Assembly — o afirmație care este adevărată din punct de vedere tehnic, dar care omite o cantitate imensă de informații care ar fi incredibil de utile în luarea unei decizii bune.
în acest post, vom arunca cu capul în unele motive foarte specifice pentru ce am ales Terraform peste alte instrumente iac. Ca și în cazul tuturor deciziilor tehnologice, este o chestiune de compromisuri și priorități și, deși prioritățile dvs. particulare pot fi diferite de ale noastre, sperăm că împărtășirea procesului nostru de gândire vă va ajuta să luați propria decizie. Iată principalele compromisuri pe care le-am considerat:
- managementul configurației vs provizionare
- infrastructură mutabilă vs infrastructură imuabilă
- Procedural vs declarativ
- Master vs Masterless
- Agent vs Agentless
- comunitate Mare vs comunitate mică
- Matur vs margine de tăiere
- folosind mai multe instrumente împreună
Chef, Puppet, Ansible și SaltStack sunt toate instrumentele de gestionare a configurației, ceea ce înseamnă că sunt concepute pentru a instala și gestiona software-ul pe serverele existente. CloudFormation și Terraform sunt instrumente de aprovizionare, ceea ce înseamnă că sunt concepute pentru a furniza serverele în sine (precum și restul infrastructurii dvs., cum ar fi echilibrele de încărcare, bazele de date, configurația rețelei etc.), lăsând sarcina de a configura aceste servere la alte instrumente. Aceste două categorii nu se exclud reciproc, deoarece majoritatea instrumentelor de gestionare a configurației pot face un anumit grad de provizionare și majoritatea instrumentelor de provizionare pot face un anumit grad de gestionare a configurației. Dar accentul pe gestionarea configurației sau furnizarea înseamnă că unele dintre instrumente vor fi mai potrivite pentru anumite tipuri de sarcini.
în special, am constatat că, dacă utilizați Docker sau Packer, marea majoritate a nevoilor dvs. de gestionare a configurației sunt deja îngrijite. Cu Docker și Packer, puteți crea imagini (cum ar fi containere sau imagini cu mașini virtuale) care au deja instalat și configurat tot software-ul de care are nevoie serverul dvs. Odată ce aveți o astfel de imagine, tot ce aveți nevoie este un server pentru ao rula. Și dacă tot ce trebuie să faceți este să furnizați o grămadă de servere, atunci un instrument de aprovizionare precum Terraform va fi de obicei mai potrivit decât un instrument de gestionare a configurației (iată un exemplu de utilizare a Terraform pentru a implementa Docker pe AWS).
infrastructura mutabilă vs infrastructura imuabilă
instrumentele de gestionare a configurației, cum ar fi Chef, Puppet, Ansible și SaltStack, sunt de obicei implicite la o paradigmă a infrastructurii mutabile. De exemplu, dacă îi spuneți lui Chef să instaleze o nouă versiune de OpenSSL, va rula actualizarea software-ului pe serverele dvs. existente și modificările vor avea loc la fața locului. În timp, pe măsură ce aplicați din ce în ce mai multe actualizări, fiecare server creează un istoric unic al modificărilor. Acest lucru duce adesea la un fenomen cunoscut sub numele de deriva de configurare, în care fiecare server devine ușor diferit de toate celelalte, ducând la erori subtile de configurare dificil de diagnosticat și aproape imposibil de reprodus.
dacă utilizați un instrument de aprovizionare, cum ar fi Terraform, pentru a implementa imagini de mașină create de Docker sau Packer, atunci fiecare „modificare” este de fapt o implementare a unui server nou (la fel ca orice „modificare” la o variabilă în programarea funcțională returnează de fapt o nouă variabilă). De exemplu, pentru a implementa o nouă versiune de OpenSSL, ați crea o nouă imagine folosind Packer sau Docker cu noua versiune de OpenSSL deja instalată, implementați acea imagine pe un set de servere complet noi și apoi desfaceți serverele vechi. Această abordare reduce probabilitatea apariției unor erori de configurare, facilitează cunoașterea exactă a software-ului care rulează pe un server și vă permite să implementați trivial orice versiune anterioară a software-ului în orice moment. Desigur, este posibil să forțați instrumentele de gestionare a configurației să facă și implementări imuabile, dar nu este abordarea idiomatică pentru aceste instrumente, în timp ce este un mod natural de a utiliza instrumentele de aprovizionare.
Procedural vs declarativ
Chef și Ansible încurajează un stil procedural în care scrieți cod care specifică, pas cu pas, cum să pentru a obține o stare finală dorită. Terraform, CloudFormation, SaltStack și Puppet încurajează un stil mai declarativ în care scrieți cod care specifică starea finală dorită, iar instrumentul IAC în sine este responsabil pentru a afla cum să atingă acea stare.
de exemplu, să presupunem că doriți să implementați 10 servere („instanțe EC2” în AWS lingo) pentru a rula v1 a unei aplicații. Iată un exemplu simplificat al unui șablon Ansibil care face acest lucru cu o abordare procedurală:
- ec2:
count: 10
image: ami-v1
instance_type: t2.micro
și aici este un exemplu simplificat al unui șablon Terraform care face același lucru folosind o abordare declarativă:
resource "aws_instance" "example" {
count = 10
ami = "ami-v1"
instance_type = "t2.micro"
}
acum la suprafață, aceste două abordări pot părea similare și când le executați inițial cu Ansible sau Terraform, acestea vor produce rezultate similare. Interesant este ce se întâmplă atunci când vrei să faci o schimbare.
de exemplu, imaginați-vă că traficul a crescut și doriți să creșteți numărul de servere la 15. Cu Ansible, codul de procedură ai scris mai devreme nu mai este util; dacă ați actualizat doar numărul de servere la 15 și reran acel cod, S-ar implementa 15 servere noi, oferindu-vă 25 total! Deci, în schimb, trebuie să fiți conștienți de ceea ce este deja implementat și să scrieți un script procedural complet nou pentru a adăuga cele 5 servere noi:
- ec2:
count: 5
image: ami-v1
instance_type: t2.micro
cu codul declarativ, deoarece tot ce faceți este să declarați starea finală dorită și Terraform își dă seama cum să ajungeți la acea stare finală, Terraform va fi, de asemenea, conștient de orice stare pe care a creat-o în trecut. Prin urmare, pentru a implementa încă 5 servere, tot ce trebuie să faceți este să reveniți la același șablon Terraform și să actualizați numărul de la 10 la 15:
resource "aws_instance" "example" {
count = 15
ami = "ami-v1"
instance_type = "t2.micro"
}
Dacă ați executat acest șablon, Terraform ar realiza că a creat deja 10 servere și, prin urmare, că tot ce trebuia să facă era să creeze 5 servere noi. De fapt, înainte de a rula acest șablon, puteți utiliza Terraform ‘ s plan
comanda pentru a previzualiza ce modificări ar face:
$ terraform plan+ aws_instance.example.11
ami: "ami-v1"
instance_type: "t2.micro"+ aws_instance.example.12
ami: "ami-v1"
instance_type: "t2.micro"+ aws_instance.example.13
ami: "ami-v1"
instance_type: "t2.micro"+ aws_instance.example.14
ami: "ami-v1"
instance_type: "t2.micro"+ aws_instance.example.15
ami: "ami-v1"
instance_type: "t2.micro"Plan: 5 to add, 0 to change, 0 to destroy.
acum ce se întâmplă când doriți să implementați v2 serviciul? Cu abordarea procedurală, ambele șabloane anterioare Ansible nu sunt din nou utile, deci trebuie să scrieți încă un șablon pentru a urmări serverele 10 pe care le-ați implementat anterior (sau a fost 15 acum?) și actualizați cu atenție fiecare la noua versiune. Cu abordarea declarativă a Terraform, te duci înapoi la exact același șablon încă o dată și pur și simplu schimba numărul de versiune ami la v2:
resource "aws_instance" "example" {
count = 15
ami = "ami-v2"
instance_type = "t2.micro"
}
evident, exemplele de mai sus sunt simplificate. Ansible vă permite să utilizați etichete pentru a căuta instanțe EC2 existente înainte de a implementa altele noi (de exemplu, folosind parametrii instance_tags
și count_tag
), dar trebuie să descoperiți manual acest tip de logică pentru fiecare resursă pe care o gestionați cu Ansible, pe baza istoricului trecut al fiecărei resurse, poate fi surprinzător de complicat (de ex. găsirea instanțelor existente nu numai după etichetă, ci și versiunea imaginii, zona de disponibilitate etc.). Acest lucru evidențiază două probleme majore cu instrumentele IAC procedurale:
- atunci când se ocupă de codul procedural, starea infrastructurii nu este pe deplin capturată în cod. Citirea celor trei șabloane Ansible pe care le-am creat mai sus nu este suficientă pentru a ști ce este implementat. De asemenea, trebuie să știți ordinea în care am aplicat aceste șabloane. Dacă le-am fi aplicat într-o ordine diferită, s-ar putea să ajungem cu o infrastructură diferită, și asta nu este ceva ce puteți vedea în baza de cod în sine. Cu alte cuvinte, pentru a raționa despre o bază de cod Ansible sau Chef, trebuie să cunoașteți istoria completă a fiecărei schimbări care s-a întâmplat vreodată.
- reutilizarea codului de procedură este în mod inerent limitată, deoarece trebuie să țineți cont manual de starea actuală a bazei de cod. Deoarece această stare este în continuă schimbare, codul pe care l-ați folosit acum o săptămână poate să nu mai fie utilizabil, deoarece a fost conceput pentru a modifica o stare a infrastructurii dvs. care nu mai există. Drept urmare, bazele codului procedural tind să crească mari și complicate în timp.
pe de altă parte, cu tipul de abordare declarativă utilizată în Terraform, codul reprezintă întotdeauna cea mai recentă stare a infrastructurii dvs. Dintr-o privire, puteți spune ce este implementat în prezent și cum este configurat, fără a fi nevoie să vă faceți griji cu privire la istoric sau sincronizare. Acest lucru facilitează, de asemenea, crearea unui cod reutilizabil, deoarece nu trebuie să țineți cont manual de starea actuală a lumii. În schimb, vă concentrați doar pe descrierea stării dorite, iar Terraform își dă seama cum să ajungeți automat de la o stare la alta. Drept urmare, bazele de cod Terraform tind să rămână mici și ușor de înțeles.
desigur, există și dezavantaje ale limbajelor declarative. Fără acces la un limbaj de programare complet, puterea dvs. expresivă este limitată. De exemplu, unele tipuri de modificări ale infrastructurii, cum ar fi o implementare de rulare, zero-downtime, sunt greu de exprimat în termeni pur declarativi. În mod similar, fără capacitatea de a face „logică” (de exemplu, declarații if, bucle), crearea unui cod generic, reutilizabil, poate fi dificilă (în special în CloudFormation). Din fericire, Terraform oferă o serie de primitive puternice , cum ar fi variabile de intrare, variabile de ieșire, module, create_before_destroy
și count
, care fac posibilă crearea unui cod modular curat, configurabil chiar și într-un limbaj declarativ. Vom discuta aceste instrumente mai mult în partea 4, Cum să creați infrastructură reutilizabilă cu module Terraform și partea 5, Sfaturi Terraform & trucuri: bucle, declarații if și capcane.
Master Versus Masterless
în mod implicit, Chef, Puppet și SaltStack necesită să rulați un server master pentru stocarea stării infrastructurii și distribuirea actualizărilor. De fiecare dată când doriți să actualizați ceva în infrastructura dvs., utilizați un client (de exemplu, un instrument de linie de comandă) pentru a emite noi comenzi către serverul principal, iar serverul principal fie împinge actualizările către toate celelalte servere, Fie acele servere trag cele mai recente actualizări de pe serverul principal în mod regulat.
un server master oferă câteva avantaje. În primul rând, este un singur loc central în care puteți vedea și gestiona starea infrastructurii dvs. Multe instrumente de gestionare a configurației oferă chiar și o interfață web (de exemplu, consola Chef, Puppet Enterprise Console) pentru serverul principal pentru a face mai ușor să vedeți ce se întâmplă. În al doilea rând, unele servere master pot rula continuu în fundal și pot impune configurația. În acest fel, dacă cineva face o modificare manuală pe un server, serverul principal poate reveni la acea modificare pentru a preveni deriva de configurare.
cu toate acestea, având pentru a rula un server de master are unele dezavantaje serioase:
- infrastructură suplimentară: trebuie să implementați un server suplimentar sau chiar un grup de servere suplimentare (pentru disponibilitate ridicată și scalabilitate), doar pentru a rula master.
- întreținere: trebuie să mențineți, să actualizați, să faceți copii de rezervă, să monitorizați și să scalați serverul(serverele) principal (e).
- securitate: trebuie să oferiți clientului o modalitate de a comunica cu serverul principal și o modalitate pentru serverul principal de a comunica cu toate celelalte servere, ceea ce înseamnă de obicei deschiderea de porturi suplimentare și configurarea sistemelor de autentificare suplimentare, toate acestea mărind suprafața atacatorilor.Chef, Puppet și SaltStack au diferite niveluri de suport pentru modurile masterless în care rulați software-ul agent pe fiecare dintre serverele dvs., de obicei pe un program periodic (de exemplu, un job cron care rulează la fiecare 5 minute) și folosiți-l pentru a trage în jos cele mai recente actualizări de la controlul versiunii (mai degrabă decât de la un server master). Acest lucru reduce semnificativ numărul de piese în mișcare, dar, după cum sa discutat în secțiunea următoare, acest lucru lasă încă o serie de întrebări fără răspuns, în special despre modul de furnizare a serverelor și instalarea software-ului agentului pe ele în primul rând.
Ansible, CloudFormation, Heat și Terraform sunt toate fără stăpân în mod implicit. Sau, pentru a fi mai precis, unele dintre ele se pot baza pe un server master, dar este deja parte a infrastructurii pe care o utilizați și nu o piesă suplimentară pe care trebuie să o gestionați. De exemplu, Terraform comunică cu furnizorii de cloud folosind API-urile furnizorului de cloud, astfel încât, într-un anumit sens, serverele API sunt servere principale, cu excepția faptului că nu necesită nicio infrastructură suplimentară sau mecanisme suplimentare de autentificare (adică folosiți doar cheile API). Ansible funcționează conectându-vă direct la fiecare server prin SSH, deci din nou, nu trebuie să rulați nicio infrastructură suplimentară sau să gestionați mecanisme suplimentare de autentificare (adică folosiți doar tastele SSH).
Agent Versus Agentless
Chef, Puppet și SaltStack toate necesită să instalați software agent (de exemplu, Chef Client, Puppet Agent, Salt Minion) pe fiecare server pe care doriți să îl configurați. Agentul rulează de obicei în fundal pe fiecare server și este responsabil pentru instalarea celor mai recente actualizări de gestionare a configurației.
aceasta are câteva dezavantaje:
- Bootstrapping: Cum vă furnizați serverele și instalați software-ul agentului pe ele în primul rând? Unele instrumente de gestionare a configurației lovesc can – ul pe drum, presupunând că un proces extern va avea grijă de acest lucru pentru ei (de exemplu, utilizați mai întâi Terraform pentru a implementa o grămadă de servere cu o imagine VM care are agentul deja instalat); alte instrumente de gestionare a configurației au un proces special de bootstrapping în care executați comenzi unice pentru a furniza serverele folosind API-urile furnizorului de cloud și instalați software-ul agent pe acele servere prin SSH.
- întreținere: Trebuie să actualizați cu atenție software-ul agentului periodic, având grijă să îl păstrați sincronizat cu serverul principal dacă există unul. De asemenea, trebuie să monitorizați software-ul agentului și să îl reporniți dacă se blochează.
- securitate: dacă software-ul agent trage în jos de configurare de la un server de master (sau un alt server, dacă nu utilizați un master), atunci trebuie să deschideți porturi de ieșire de pe fiecare server. Dacă serverul principal împinge configurația către agent, atunci trebuie să deschideți porturile de intrare pe fiecare server. În ambele cazuri, trebuie să vă dați seama cum să autentificați agentul pe serverul cu care vorbește. Toate acestea crește suprafața de atacatori.
încă o dată, Chef, Puppet și SaltStack au niveluri diferite de suport pentru modurile fără agenți (de exemplu, salt-ssh), dar acestea simt adesea că au fost fixate ca o gândire ulterioară și nu acceptă întotdeauna setul complet de caracteristici al instrumentului de gestionare a configurației. De aceea, în sălbăticie, configurația implicită sau idiomatică pentru Chef, Puppet și SaltStack include aproape întotdeauna un agent și, de obicei, și un maestru.
toate aceste piese mobile suplimentare introduc un număr mare de noi moduri de eșec în infrastructura dvs. De fiecare dată când primiți un raport de eroare la ora 3 dimineața, va trebui să vă dați seama dacă este o eroare în codul aplicației dvs. sau în codul IAC sau în clientul de gestionare a configurației sau în serverul principal sau în modul în care clientul vorbește cu serverul principal sau în modul în care alte servere vorbesc cu serverul principal sau…
Ansible, CloudFormation, Heat și Terraform nu necesită să instalați agenți suplimentari. Sau, pentru a fi mai precis, unele dintre ele necesită agenți, dar acestea sunt de obicei deja instalate ca parte a infrastructurii pe care o utilizați. De exemplu, AWS, Azure, Google Cloud și toți ceilalți furnizori de cloud se ocupă de instalarea, gestionarea și autentificarea software-ului agentului pe fiecare dintre serverele lor fizice. Ca utilizator al Terraform, nu trebuie să vă faceți griji cu privire la toate acestea: emiteți doar comenzi și agenții furnizorului de cloud le execută
pentru dvs. pe toate serverele dvs. Cu Ansible, serverele dvs. trebuie să ruleze
daemonul SSH, care este comun pentru a rula pe majoritatea serverelor oricum.comunitate Mare vs comunitate mică
ori de câte ori alegeți o tehnologie, alegeți și o comunitate. În multe cazuri, ecosistemul din jurul proiectului poate avea un impact mai mare asupra experienței dvs. decât calitatea inerentă a tehnologiei în sine. Comunitatea determină câți oameni contribuie la proiect, câte plug-in-uri, integrări și extensii sunt disponibile, cât de ușor este să găsești ajutor online (de exemplu, postări pe blog, întrebări despre StackOverflow) și cât de ușor este să angajezi pe cineva care să te ajute (de exemplu, un angajat, un consultant sau o companie de asistență).
este greu să faci o comparație exactă între comunități, dar poți observa unele tendințe căutând online. Tabelul de mai jos prezintă o comparație a instrumentelor IAC populare, cu datele pe care le-am adunat în Mai 2019, inclusiv dacă instrumentul IAC este open source sau sursă închisă, ce furnizori de cloud acceptă, numărul total de contribuitori și stele pe GitHub, câte comiteri și probleme active au existat pe o perioadă de o lună de la mijlocul lunii aprilie până la mijlocul lunii mai, câte biblioteci open source sunt disponibile pentru instrument, Numărul de întrebări enumerate pentru instrumentul respectiv pe StackOverflow și numărul de locuri de muncă care menționează instrumentul pe Indeed.com.