Terraformer - Infrastruktur att koda

Terraformer - Infrastruktur att koda
Jag skulle vilja berätta om det nya CLI-verktyget som jag skrev för att lösa ett gammalt problem.

problem

Terraform har länge varit en standard inom Devops/Cloud/IT-communityt. Saken är väldigt bekväm och användbar för att hantera infrastruktur som kod. Det finns många läckerheter i Terraform liksom många gafflar, vassa knivar och krattor.
Med Terraform är det väldigt bekvämt att skapa nya saker och sedan hantera, ändra eller ta bort dem. Vad ska de som har en enorm infrastruktur i molnet och inte skapat genom Terraform göra? Att skriva om och återskapa hela molnet är på något sätt dyrt och osäkert.
Jag stötte på det här problemet vid 2 jobb, det enklaste exemplet är när du vill att allt ska finnas i Git i form av terraform-filer, men du har 250+ hinkar och det är mycket att skriva dem i terraform för hand.
Det finns fråga sedan 2014 i terrafom som stängdes 2016 med hopp om att det ska bli import.

I allmänhet är allt som på bilden bara från höger till vänster

Varningar: Författaren bor inte i Ryssland på halva sitt liv och skriver lite på ryska. Se upp för stavfel.

Решения

1. Det finns färdiga och gamla lösningar för AWS terraformning. När jag försökte få igenom mina 250+ hinkar insåg jag att allt var dåligt där. AWS har länge introducerat många nya alternativ, men terraforming känner inte till dem och i allmänhet är det rubin mallen ser gles ut. Efter 2 på kvällen skickade jag Dra begäran att lägga till fler funktioner där och insåg att en sådan lösning inte alls är lämplig.
Hur terraforming fungerar: det tar data från AWS SDK och genererar tf och tfstate genom en mall.
Det finns 3 problem här:
1. Det kommer alltid att finnas en fördröjning i uppdateringar
2. tf-filer kommer ibland ut trasiga
3. tftillstånd samlas in separat från tf och konvergerar inte alltid
Generellt är det svårt att få ett resultat där `terraformplan` säger att det inte är några förändringar

2. `terraform import` är ett inbyggt kommando i terraform. Hur fungerar det?
Du skriver en tom TF-fil med namn och typ av resurs, kör sedan `terraform import` och skickar resurs-ID:t. terraform kontaktar leverantören, tar emot data och gör en tfstate-fil.
Det finns 3 problem här:
1. Vi får bara en tfstate-fil, och tf-filen är tom, du måste skriva den manuellt eller konvertera den från tfstate
2. Kan bara arbeta med en resurs åt gången och stöder inte alla resurser. Och vad ska jag göra igen med 250+ hinkar?
3. Du måste känna till resursernas ID - det vill säga du måste slå in den i kod som får listan över resurser
I allmänhet är resultatet partiellt och skalas inte bra

Mitt val

krav:
1. Möjlighet att skapa tf- och tfstate-filer för resurser. Till exempel, ladda ner alla hinkar/säkerhetsgrupp/lastbalanserare och att "terraform plan" returnerade att det inte finns några ändringar
2. Du behöver 2 GCP + AWS-moln
3. Global lösning som är enkel att uppdatera varje gång och som inte slösar tid på varje resurs under 3 dagars arbete
4. Gör det till öppen källkod – alla har samma problem

Go-språket är därför jag älskar det, och det har ett bibliotek för att skapa HCL-filer som används i terraform + mycket kod i terraform som kan vara användbart

Bana

Första försöket
Jag började med en enkel version. Kontakta molnet via SDK för den nödvändiga resursen och omvandla den till fält för terraform. Försöket dog omedelbart på säkerhetsgruppen eftersom jag inte gillade de 1.5 dagarna för att bara konvertera säkerhetsgruppen (och det finns många resurser). Under lång tid och sedan kan fält ändras/läggas till

Andra försöket
Baserat på idén som beskrivs här. Ta bara och konvertera tfstate till tf. All data finns där och fälten är desamma. Hur får man full tfstate för många resurser?? Det var här kommandot `terraform refresh` kom till undsättning. terraform tar alla resurser i tfstate och, med ID, drar ut data om dem och skriver allt till tfstate. Det vill säga skapa en tom tfstate med bara namn och ID, kör `terraform refresh` och sedan får vi fulla tfstates. Hurra!
Låt oss nu göra den rekursiva pornografin att skriva en omvandlare för tfstate till tf. För dem som aldrig har läst tfstate är det JSON, men speciellt.
Här är dess viktiga delegenskaper

 "attributes": {
                            "id": "default/backend-logging-load-deployment",
                            "metadata.#": "1",
                            "metadata.0.annotations.%": "0",
                            "metadata.0.generate_name": "",
                            "metadata.0.generation": "24",
                            "metadata.0.labels.%": "1",
                            "metadata.0.labels.app": "backend-logging",
                            "metadata.0.name": "backend-logging-load-deployment",
                            "metadata.0.namespace": "default",
                            "metadata.0.resource_version": "109317427",
                            "metadata.0.self_link": "/apis/apps/v1/namespaces/default/deployments/backend-logging-load-deployment",
                            "metadata.0.uid": "300ecda1-4138-11e9-9d5d-42010a8400b5",
                            "spec.#": "1",
                            "spec.0.min_ready_seconds": "0",
                            "spec.0.paused": "false",
                            "spec.0.progress_deadline_seconds": "600",
                            "spec.0.replicas": "1",
                            "spec.0.revision_history_limit": "10",
                            "spec.0.selector.#": "1",

Det finns:
1. id - sträng
2. metadata - en array av storlek 1 och i den ett objekt med fält som beskrivs nedan
3. spec - hash av storlek 1 och nyckel, värde i den
Kort sagt, ett roligt format, allt kan vara flera nivåer djupt

                   "spec.#": "1",
                            "spec.0.min_ready_seconds": "0",
                            "spec.0.paused": "false",
                            "spec.0.progress_deadline_seconds": "600",
                            "spec.0.replicas": "1",
                            "spec.0.revision_history_limit": "10",
                            "spec.0.selector.#": "1",
                            "spec.0.selector.0.match_expressions.#": "0",
                            "spec.0.selector.0.match_labels.%": "1",
                            "spec.0.selector.0.match_labels.app": "backend-logging-load",
                            "spec.0.strategy.#": "0",
                            "spec.0.template.#": "1",
                            "spec.0.template.0.metadata.#": "1",
                            "spec.0.template.0.metadata.0.annotations.%": "0",
                            "spec.0.template.0.metadata.0.generate_name": "",
                            "spec.0.template.0.metadata.0.generation": "0",
                            "spec.0.template.0.metadata.0.labels.%": "1",
                            "spec.0.template.0.metadata.0.labels.app": "backend-logging-load",
                            "spec.0.template.0.metadata.0.name": "",
                            "spec.0.template.0.metadata.0.namespace": "",
                            "spec.0.template.0.metadata.0.resource_version": "",
                            "spec.0.template.0.metadata.0.self_link": "",
                            "spec.0.template.0.metadata.0.uid": "",
                            "spec.0.template.0.spec.#": "1",
                            "spec.0.template.0.spec.0.active_deadline_seconds": "0",
                            "spec.0.template.0.spec.0.container.#": "1",
                            "spec.0.template.0.spec.0.container.0.args.#": "3",

I allmänhet, om någon vill ha ett programmeringsproblem för en intervju, be dem bara att skriva en parser för denna uppgift :)
Efter många försök att skriva en parser utan buggar, hittade jag en del av den i terraform-koden, och den viktigaste delen. Och allt verkade fungera bra

Försök tre
terraform-leverantörer är binärer som innehåller kod med alla resurser och logik för att arbeta med molnets API. Varje moln har sin egen leverantör och terraform själv anropar dem bara genom sitt RPC-protokoll mellan två processer.
Nu bestämde jag mig för att kontakta terraform-leverantörer direkt via RPC-samtal. Det blev vackert och gjorde det möjligt att byta terraform-leverantörer till nyare och få nya funktioner utan att ändra koden. Det visar sig också att inte alla fält i tfstate borde vara i tf, men hur kan man ta reda på det? Fråga bara din leverantör om detta. Sedan började en annan rekursiv pornografi av att sätta ihop reguljära uttryck, och sökte efter fält i tfstate på alla nivåer på djupet.

Till slut fick vi ett användbart CLI-verktyg som har en gemensam infrastruktur för alla terraform-leverantörer och du kan enkelt lägga till en ny. Att lägga till resurser kräver dessutom lite kod. Plus alla möjliga godsaker som kopplingar mellan resurser. Naturligtvis fanns det många olika problem som inte kan beskrivas alla.
Jag döpte djuret till Terrafomer.

finale

Med Terrafomer genererade vi 500-700 tusen rader med tf + tfstate-kod från två moln. Vi kunde ta äldre saker och börja röra dem endast genom terraform, som i den bästa infrastrukturen som kodidéer. Det är bara magi när du tar ett stort moln och tar emot det genom ett team i form av terraform-arbetarfiler. Och sedan grep/replace/git och så vidare.

Jag kammade ut den och gjorde i ordning den, fick tillstånd. Släppt på GitHub för alla på torsdag (02.05.19/XNUMX/XNUMX). github.com/GoogleCloudPlatform/terraformer
Har redan fått 600 stjärnor, 2 pull-förfrågningar för att lägga till stöd för openstack och kubernetes. Bra feedback. I allmänhet är projektet användbart för människor
Jag råder alla som vill att börja arbeta med Terraform och inte skriva om allt för detta.
Jag kommer gärna att dra förfrågningar, frågor, stjärnor.

Демо
Terraformer - Infrastruktur att koda

Källa: will.com

Lägg en kommentar