
Chcel by som sa podeliť o nový CLI nástroj, ktorý som napísal na riešenie starého problému.
Problém
Terraform sa už dávno stal štandardom v DevOps/Cloud/IT komunite. Je to veľmi užitočný a praktický nástroj na správu infraštruktúry ako kódu. Existuje mnoho výhod, ale aj množstvo úskalí, ostrých nožov a pascí.
S Terraformom je veľmi jednoduché vytvárať nové veci a potom ich spravovať, meniť alebo odstraňovať. Ale čo robiť s tými, ktorí majú obrovskú infraštruktúru v cloude, ktorú nezaložili pomocou Terraformu? Prepisovať a znovu vytvárať celé cloudové prostredie je nákladné a riskantné.
Stretol som sa s touto problematikou na dvoch rôznych zamestnaniach. Najjednoduchší príklad je, keď chcete mať všetko uložené v Gite vo forme Terraform súborov, a vy máte 250+ bucketov. Písať ich manuálne pre Terraform je celkom veľa.
Existuje Už od roku 2014 existoval terrafom, ktorý bol uzavretý v roku 2016 s nádejou, že sa objaví import.
V skratke, všetko vyzerá ako na obrázku, len sprava doľava.
Upozornenie: Autor žije väčšinu svojho života mimo Ruska a málo píše v ruštine. Buďte opatrní na pravopisné chyby.
Riešenia
1. Existujú hotové a staré riešenia pre AWS. . Keď som sa snažil získať svojich 250+ bucketov, zistil som, že situácia je katastrofálna. AWS už dávno pridal množstvo nových možností, o ktorých terraforming nevie, navyše je na Ruby. . Po 2 hodinách večer som poslal na pridanie ďalších funkcií a uvedomil som si, že takéto riešenie vôbec nevyhovuje.
Ako funguje terraforming: berie dáta z AWS SDK a generuje tf a tfstate cez šablóny.
Sú tu tri problémy:
1. Vždy tam bude zakaždým meškanie v aktualizáciách.
2. tf súbory občas vychádzajú poškodené.
3. tfstate sa zostavuje oddelene od tf a nie vždy sa zhoduje.
Skutočne je ťažké dosiahnuť výsledok, pri ktorom `terraform plan` povie, že nie sú žiadne zmeny.
2. `terraform import` — zabudovaná funkcia v Terraform. Ako to funguje?
Napíšete prázdny TF súbor s menom a typom zdroja, potom spustíte `terraform import` a zadáte ID zdroja. Terraform sa obracia na poskytovateľa, získa dáta a vytvorí tfstate súbor.
Sú tu tri problémy:
1. Získame len tfstate súbor, zatiaľ čo tf je prázdny a musí sa napísať alebo konvertovať z tfstate.
2. Funguje len s jedným zdrojom naraz a nepodporuje všetky zdroje. A čo mám robiť s 250+ bucketmi?
3. Musíte poznať ID zdrojov — to znamená, že to musíte obaliť do kódu, ktorý získa zoznam zdrojov.
V skutočnosti je výsledok čiastočný a nie je dobre škálovateľný.
Moje riešenie
Požiadavky:
1. Možnosť vytvoriť súbory tf a tfstate na základe zdrojov. Napríklad stiahnuť všetky bucket/?/security group/?/load balancer a čo `terraform plan` vracia, že nie sú žiadne zmeny.
2. Potrebujeme 2 cloudu GCP + AWS.
3. Globálne riešenie, ktoré sa dá ľahko aktualizovať zakaždým a nemusíte na každý zdroj stráviť 3 dni práce.
4. Urobiť to open source – to je problém všetkých.
Jazyk Go – preto ho mám rád, a existuje v ňom knižnica na vytváranie HCL súborov, ktorá sa používa v terraform + množstvo kódu v terraform, ktorý môže byť užitočný.
Cesta.
Prvý pokus.
Začal som jednoduchou verziou. Spojenie s cloudom cez SDK za potrebným zdrojom a jeho konverzia do polí pre terraform. Pokus zomrel hneď na security group, pretože sa mi nepáčilo 1,5 dňa konvertovať iba security group (zdrojov je veľa). Dlho a potom sa polí môžu meniť/pridávať.
Druhý pokus.
Založené na nápade opísanom. Proste vziať a skonvertovať tfstate na tf. Všetky údaje sú tam a polia sú rovnaké. Ako získať plný tfstate pre viac zdrojov? Tu prichádza pomoc s príkazom `terraform refresh`. Terraform vezme všetky zdroje v tfstate a podľa ID získa údaje a zapíše všetko do tfstate. Teda vytvoriť prázdny tfstate len s názvami a ID, spustiť `terraform refresh` a získame plné tfstate. Hurá!
Teraz sa pustíme do recursívneho písania konvertora pre tfstate na tf. Pre tých, ktorí nikdy nečítali tfstate, je to JSON, ale špeciálny.
Tu je jeho dôležitá časť 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",
Tu sú:
1. id – string.
2. metadata – pole veľkosti 1 a v ňom objekt s poľami, ktorý je popísaný nižšie.
3. spec – hash veľkosti 1 a v ňom key,value.
Skrátka zábavný formát, všetko môže byť aj do hĺbky na niekoľko úrovní.
"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", V zásade, kto chce úlohu na programovanie na pohovor, môže jednoducho požiadať, aby napísal parser na toto 🙂
Po dlhých pokusoch napísať parser bez chýb, som našiel časť jeho kódu v terraform-e, a to tú najdôležitejšiu časť. A všetko fungovalo celkom normálne.
Pokús číslo tri
Terraform provider — sú to binárky, v ktorých je kód so všetkými zdrojmi a logikou pre prácu s API cloudov. Každý cloud má svoj vlastný provider a samotný terraform ich volá cez svoj protokol RPC medzi dvoma procesmi.
Teraz som sa rozhodol pristupovať priamo k terraform providerom cez RPC volania. Takto to vyzeralo pekne a umožnilo to meniť terraform providery na novšie a získať nové možnosti bez zmeny kódu. Ešte sa ukázalo, že nie všetky polia v tfstate musia byť v tf, ale ako to zistiť? Iba sa opýtať provider na to. Potom začala ďalšia rekursívna pornografia so zostavovaním regulárnych výrazov s hľadaním polí v tfstate na všetkých úrovniach.
Nakoniec sa z toho stal užitočný CLI nástroj, ktorý má spoločnú infraštruktúru pre všetky terraform providery, a nový sa dá jednoducho pridať. Taktiež pridávanie zdrojov zaberá málo kódu. Plus rôzne výhody, ako spojenie medzi zdrojmi. Samozrejme, bolo veľa rôznych problémov, ktoré sa nedajú všetky opísať.
Nazval som tento projekt Terrafomer.
Finále
S pomocou Terrafomer sme vygenerovali 500-700 tisíc riadkov kódu tf + tfstate z dvoch cloudov. Podarilo sa nám vziať legacy veci a začať ich manipulovať iba cez terraform, ako v najlepších nápadoch infrastructure as code. Je to jednoducho mágia, keď zoberiete obrovský cloud a získate ho prostredníctvom príkazu vo forme fungujúcich terraform súborov. A potom grep/replace/git a tak ďalej.
Opravil a usporiadal som, získal povolenia. Publikoval na GitHub pre všetkých vo štvrtok (02.05.19).
Už získal 600 hviezd, 2 pull requesty na pridanie podpory pre openstack a kubernetes. Dobré recenzie. Všetko je to užitočný projekt pre ľudí.
Odporúčam všetkým, ktorí chcú začať pracovať s Terraform a nemusia všetko prepisovať.
Budem rád za pull requesty, problémy, hviezdy.
Demo
Zdroj: habr.com
