Terraformer — Infrastructuur als Code

Terraformer — Infrastructuur als Code
Ik wil een nieuw CLI-hulpmiddel presenteren dat ik heb geschreven om een oud probleem op te lossen.

Probleem

Terraform is al een tijdje de standaard in de Devops/Cloud/IT-gemeenschap. Het is een zeer handige en nuttige tool voor infrastructuur als code. Er zijn veel voordelen aan Terraform, maar ook veel valkuilen en moeilijkheden.
Met Terraform is het heel gemakkelijk om nieuwe dingen te maken en deze vervolgens te beheren, te wijzigen of te verwijderen. Maar wat moeten degenen doen die een enorme infrastructuur in de cloud hebben die niet met Terraform is gemaakt? Alles herschrijven en opnieuw opzetten is kostbaar en onveilig.
Ik ben dit probleem tegengekomen op twee banen, het meest eenvoudige voorbeeld is wanneer je alles in git wilt hebben in de vorm van Terraform-bestanden, maar je hebt 250+ buckets en het handmatig schrijven van hun configuraties voor Terraform is wel een hele klus.
Er is probleem sinds 2014 in Terraform dat in 2016 is gesloten in de hoop dat er import zou komen.

In wezen is het allemaal zoals op de afbeelding, maar van rechts naar links

Waarschuwingen: De auteur leeft al een half leven niet in Rusland en schrijft zelden in het Russisch. Wees voorzichtig met spelfouten.

Oplossingen

1. Er zijn bestaande en oude oplossingen voor AWS terraforming. Toen ik probeerde mijn 250+ buckets te verkrijgen via dit hulpmiddel, realiseerde ik me dat het niet goed werkte. AWS heeft al veel nieuwe opties toegevoegd, maar terraforming is daar niet van op de hoogte en het gebruikt bovendien Ruby. De sjablonen zien er beperkt uit. Na twee avonden heb ik een Pull request gestuurd om meer mogelijkheden toe te voegen en ik begreep dat zulke oplossingen helemaal niet geschikt zijn.
Hoe werkt terraforming? Het haalt gegevens van de AWS SDK en genereert tf- en tfstate-bestanden via sjablonen.
Hier zijn drie problemen:
1. Er zal altijd vertraging zijn in updates
2. tf-bestanden zijn soms beschadigd
3. tfstate wordt apart van tf verzameld en komt niet altijd overeen
Over het algemeen is het moeilijk om een resultaat te krijgen waarbij `terraform plan` aangeeft dat er geen wijzigingen zijn

2. `terraform import` — een ingebouwd commando in Terraform. Hoe werkt dat?
Je schrijft een leeg TF-bestand met de naam en het type resource, daarna voer je `terraform import` uit en geeft het ID van de resource door. Terraform vraagt de provider om gegevens en maakt het tfstate-bestand aan.
Hier zijn drie problemen:
1. We krijgen alleen het tfstate-bestand en het tf-bestand is leeg; dat moet handmatig worden geschreven of geconverteerd vanuit tfstate.
2. Het kan slechts met één resource per keer werken en ondersteunt niet alle resources. En wat moet ik weer doen met die 250+ buckets?
3. Je moet het ID van de resources kennen; je moet dit dus in code wikkelen die de lijst van resources ophaalt.
Het resultaat is in feite gedeeltelijk en schaalt niet goed.

Mijn oplossing

Vereisten:
1. Mogelijkheid om tf- en tfstate-bestanden te maken op basis van bronnen. Bijvoorbeeld alle buckets/security groups/load balancers downloaden en ervoor zorgen dat `terraform plan` aangeeft dat er geen wijzigingen zijn.
2. Twee clouds GCP + AWS
3. Een globale oplossing die gemakkelijk is bij te werken en waarbij niet elke keer drie dagen werk voor elke bron nodig is.
4. Maak het open source — dit is een probleem dat iedereen heeft.

De taal Go — daarom hou ik ervan, en er is een bibliotheek voor het creëren van HCL-bestanden die wordt gebruikt in terraform + veel code in terraform die nuttig kan zijn.

Pad

Eerste poging
Ik begon met een eenvoudige versie. Het maken van verbinding met de cloud via de SDK voor de benodigde bron en deze converteren naar velden voor terraform. De poging stierf onmiddellijk bij de security group omdat ik het niet leuk vond om 1,5 dag alleen de security group te converteren (er zijn veel bronnen). Het duurt lang en vervolgens kunnen de velden veranderen/toegevoegd worden.

Tweede poging
Gebaseerd op het beschreven idee here. Gewoon het tfstate in tf converteren. Alle gegevens zijn daar en de velden zijn hetzelfde. Hoe krijg je een compleet tfstate voor meerdere bronnen?? Hier kwam het commando `terraform refresh` van pas. Terraform haalt alle bronnen in tfstate op en haalt op basis van ID gegevens op en schrijft alles in tfstate. Dat wil zeggen, maak een leeg tfstate alleen met namen en ID’s, start `terraform refresh` en we ontvangen volledige tfstate. Hoera!
Laten we nu bezig gaan met het recursieve schrijven van een converter van tfstate naar tf. Voor degenen die nog nooit tfstate hebben gelezen, dit is JSON, maar dan speciaal.
Hier is het belangrijke deel attributes

 "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",

Hier zijn:
1. id — string
2. metadata — array van grootte 1 en daarin een object met de velden die hieronder worden beschreven
3. spec — hash van grootte 1 en daarin key,value
Een kort en leuk formaat, alles kan ook diepgaand zijn tot verschillende niveaus.

                   "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",

In het algemeen, wie een programmeeropdracht voor een sollicitatie wil, vraag gewoon om een parser hiervoor te schrijven 🙂.
Na lange pogingen om een parser zonder bugs te schrijven, vond ik een deel ervan in de Terraform-code, en dat was het belangrijkste deel. En alles leek normaal te werken.

Poging drie.
Een Terraform-provider is een binaire versie met code voor alle middelen en logica om met de API's van cloudproviders te werken. Elke cloud heeft zijn eigen provider, en Terraform roept ze aan via zijn RPC-protocol tussen twee processen.
Nu besloot ik rechtstreeks contact op te nemen met Terraform-providers via RPC-aanroepen. Het kwam mooi uit en maakte het mogelijk om Terraform-providers te vervangen door nieuwere versies en nieuwe mogelijkheden te krijgen zonder de code te veranderen. Het bleek ook dat niet alle velden in tfstate in tf moeten zitten, maar hoe kom je daarachter? Alleen door de provider ernaar te vragen. Toen begon er nog een recursieve verwarring bij het samenstellen van reguliere expressies met het zoeken naar velden binnen tfstate op alle niveaus.

Uiteindelijk is er een nuttige CLI-tool ontstaan met een gemeenschappelijke infrastructuur voor alle terraform providers, en het is eenvoudig om een nieuwe toe te voegen. Ook duurt het toevoegen van bronnen weinig code. Plus allerlei extra's zoals verbindingen tussen middelen. Natuurlijk waren er veel verschillende problemen die niet allemaal te beschrijven zijn.
Ik heb het beestje Terrafomer genoemd.

Eind

Met Terrafomer hebben we 500-700 duizend regels tf + tfstate-code gegenereerd in twee cloudomgevingen. We konden legacy elementen oppakken en ze alleen via terraform aanpakken, zoals het beste idee van infrastructure as code. Het is gewoon magie als je een enorme cloud pakt en deze met een commando in de vorm van werkende terraform-bestanden krijgt. En dan grep/replace/git en zo verder.

Ik heb alles berekend en op orde gebracht, kreeg de juiste machtigingen. Heb het op GitHub uitgegeven voor iedereen op donderdag (02.05.19). github.com/GoogleCloudPlatform/terraformer
Ik heb inmiddels 600 sterren gekregen, 2 pull requests voor de ondersteuning van openstack en kubernetes toegevoegd. Goede feedback. Het project is over het algemeen nuttig voor mensen.
Ik raad het iedereen aan die met Terraform wil beginnen en niet alles opnieuw wil schrijven.
Ik ben blij met pull requests, issues, sterren.

Demo
Terraformer — Infrastructuur als Code

Bron: habr.com

Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers 🔥 Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers | ProHoster