Sziasztok,
root modul:
module "resource_group" {
for_each = var.customers
source = "./modules/resource_group"
customer_name = each.value.name
subscription_location = var.subscription.location
subscription_locationshortname = var.subscription.locationshortname
subscription_environment = var.subscription.environment
tags_owner = var.tags.owner
tags_deployed_by = var.tags.deployedby
tags_deployment_date = var.tags.deploymentdate
tags_cost_center = var.tags.costcenter
tags_snow_fgroup = var.tags.snowfgroup
}module "key_vault" {
for_each = module.resource_group.resource_group_name
source = "./modules/key_vault"
location = module.resource_group.resource_group_location
resource_group_name = module.resource_group.resource_group_name
tenant_id = var.subscription.tenantid
tags_owner = var.tags.owner
tags_deployed_by = var.tags.deployedby
tags_deployment_date = var.tags.deploymentdate
tags_cost_center = var.tags.costcenter
tags_snow_fgroup = var.tags.snowfgroup
depends_on = [
module.resource_group.resource_group_name
]
}
resource_group output.tf-je:
output "resource_group_name" { value = azurerm_resource_group.rg.name }
output "resource_group_location" { value = azurerm_resource_group.rg.location }
plan kimenet:
│ Error: Invalid value for input variable │ │ on main.tf line 24, in module "key_vault": │ 24: location = module.resource_group.resource_group_location │ │ The given value is not suitable for module.key_vault.var.location declared at modules\key_vault\variables.tf:7,1-20: │ string required. ╵ ╷
│ Error: Invalid value for input variable │ │ on main.tf line 25, in module "key_vault": │ 25: resource_group_name = module.resource_group.resource_group_name │
│ The given value is not suitable for module.key_vault.var.resource_group_name declared at │ modules\key_vault\variables.tf:12,1-31: string required.
Mit ronthattam el?
Köszönöm!
Hozzászólások
Ha van for_each a module "resource_group" -on, akkor onnantól kezdve a module.resource_group kifejezés az egy dictionary jellegű dolog lesz. Tehát félrevezető azt leírni, hogy module.resource_group.resource_group_name. Helyette indexelned kell olyan kulccsal, ami volt a for_each -ben. Tehát ha a var.customers-ben mondjuk volt "contoso" nevű customered, akkor később az outputokat is úgy kaphatod vissza, hogy module.resource_group["contoso"].resource_group_name. Lényegében úgy kell elképzelni, hogy a modulod annyiszor lesz külön példányban, ahányszor a for_each végigment. És annyiszor lesz külön egymástól független output-ja.
Ez azt is jelenti, hogy a module "key_vault" blokkon is a for_each máshogy kell hogy kinézzen, valami a location és resource_group_name értéke is. Hogy hogyan, ahhoz jó lenne tudni, hogy a var.customers -nek milyen a struktúrája.
Köszönöm.
Igen, azt szerettem volnam hogy az összes customer esetén végrehajtódjon,
de a modulba ne legyen semmilyen statikus dolog.
Igy néz ki a customers:
Azt gondolom feltételezhetjük, hogy a key_vault -ból pont ugyanannyit akarsz, amennyit a resource_group-ból. Akkor valahogy így csinálnám:
Megjegyzések:
Tipikusan nem jó, ha a customers-ben a key-ek számok, nem tudom most csak a példa kedvéért van-e így, vagy a valóságban is. Jobb valami sztring. De ettől még akár működhet.
A depends_on legtöbb esetben nem kell, ha a key_vault -ban például a resource_group_name= mögött olyan kifejezés van, ami a dependeciát implicit amúgy is kialakítja.
Ha már modulokban szervezed a kódot, akkor célszerűbb és egyszerűbb lehet, ha nem két modult hivatkozol be annyiszor, ahány customered van, hanem csak egy modult hivatkozol be for_each használatával, és azon modulon belül van egymás mellett for_each nélkül egy darab azurerm_resource_group és egy darab azurerm_key_vault.
Ne vedd sértésnek, de ez az egész eléggé átgondolatlannak tűnik, ezért megmutatnék egy másik megközelítést, ami sok hibát ki tud mellőzni és könnyen automatizálható.
Ha minden ügyfélnek ugynanazt kell telepíteni, akkor célszerű lenne egy olyan "playbook"-ot írni, ami leírja, hogy kell kinéznie a teljes deploymentnek.
Majd ez a deploymentet különböző '.tfvars' fájlokkal hívni, ahol egy file az egy ügyfél. Pl. 'customer1.tfvars'
Ha szükséges, akkor bizonyos modulokat ügyfél szinten ki-be lehet kapcsolgatni a playbook okosítással.
A playbookban locals szekcióban kezelném a nevezéktant és a tfvars fileban csak a többi dolgot kérném be. Így lenne egységes a nevezéktan.
Pl.:
Resource group name: aws-rg-customer1
Ebből a tfvars fálban csak a customer1 van átadva, mint az ügyfél neve/kódja bármi.
Minden ügyfél külön fájlban van egymástól függetlenül.
Később ez tök jól automatizálható, hogy ne kézzel kelljen ezeket a parancsokat futtatni.
Terragrunt valo erre,
Masreszrol eleg egyszeruen lehet behivni yaml vagy json allomanyokat, akar a TF_VAR_customer=itt_a_neve parameterrel, ha behuzod mondjuk egy "configs/${var.customer}/" dirbol ahol a teljes config egy "config.yaml"
Tehat mojduk valahogy igy: configuration = yamldecode(file("configs/${var.customer}/config.yaml")), aztan ezt mar hasznalhatod akarhol. Ebben az esetben nem kell torodni a nevezektannal, hogy szetbontsuk a filenevet vagy akarmit.
En ugy epitettem dinamikus infrat, hogy egy ilyen yaml allomanyt beolvastam, amiben minden elem egy arraz volt, tehat mondjuk "aks:" alatt egy vagvy tobb aks-t lehet definialni. Amikor a konfigot atadja az ember, akkor a module for_each-el megy vegig rajta, azaz ha valaki nem rak bele semmit az aks timbbe, nem lesz aks csinalva, ha belerak akkor meg megcsinalja.
jah es a yaml masik nagy elonye az anchor hasznalata. Mondjuk definialom az osszes subnetet, majd a type-ra rateszem az anchort, es kesobb barmelyik resource-nal csak behivatkozom. Igy nem kell mindenhova ugyanazt leirni es szepen olvashato a yaml "code"
Dehogy veszem, köszönöm.
Alapvetően Subscription (valójában ez környezet) alapon szeparáltam, tehát a Subscription-n belül minden ügyfél azonos szolgáltatásokat kap.
Egy ügyfél több Subscription-ben van jelen (dev, testing, prod), egy Subscription-ben pedig több ügyfél van - ez üzleti igény, nem tudom befolyásolni.
Name convention a fenti sniplet-ben nem látszik, az resource szinten van definiálva - lényegében a customer csak ahhoz kell hogy a resource nevéhez ott legyen a neve.
Ha ügyfél szinten szeparálnélnék akkor nem három környezetet kellene definiálnom, hanem annyit ahány customer van (>20).
Ha ilyen tobb szintu fa strukturaban kell definialnod az env-eket akkor tenyleg nezd meg a terragrunt-ot, mert az pont ezt oldja meg.
En peldaul egyetlen composite modult hasznalok minden ugyfel minden rendszerer, ami behuzza az osszes lehetseges modult. Az hogy egy ugyfel milyen rendszereben minek kell lennie egy tfvar vagy config.yaml donti el, ha definial valamit lesz, ha nem nem lesz. A terragrunt konyvtar meg ugy nez, ki, hogy projects/{ugyfel1, ugyfel2, ...ugyfelx}/{dev, uat, prod, whatever}. Ha valaki csinal egy konyvtarat beledob egy config.yaml-t a schemanak megfeleloen mar fel is epul a rendszere.
Ha kell privatban egyszer megmutatom :D
A mostani struktúra jó irány lehet. Sajnos az üzleti igényt, nem ismert így nem lehet megítélni a dolgot .
Inkább térjünk vissza a konkrét esetre. Ha jól értem a struktúrát, akkor egy Subscription, egy környezet (dev,test,stg...).
Minden ügyfél kap egy-egy környezetet a Subscription-ökben. Mondjuk egy vagy több resource group formájában.
Tehát jön egy ügyfél akkor az én példámban egy playbook lefedi az összes környezetet, csak akkor ahány környezet, annyi konfigurációs file kell. Igazából az eltérés csak a könyezet neve adná (dev,test,stg etc....). Ez nem akkora overload így külső szemmel.
Ami problémás lehet, az az ügyfelenkénti költség kimutatása. Ha még ez nem került elő, akkor érdemes észben tartani, mert előbb-utóbb fog érkezni a kérés. Emiatt jobb talán struktúrálisan a Subscription szinten kezelni az ügyfelet. Ezt lehet bontani subscription szinten mondjuk Prod és NonProd környezetekre ügyfelenként. Minden környezetet lehet egy resource group alá rendelni azonos struktúrában. Persze ez csak egy a sok lehetőség közül. Így ha valaki meg fogja kérdezni, hogy mennyi az ügyfél szerinti költség, akkor max. 2 subscription összegéből ez megmondható.
Az Atlantis is jó kiegészítője lehet a Terraform-nak.
A fent említett Terragunt is lehet jó megoldás.
Minden esetben függetlenül melyik szinten, de szükség van ügyfél szintű szeparációra. A PROD környezetben semmiképp se engednék több ügyfelet egy helyre.
Illetve, itt bejöhet az a probléma, amit fentebb írtak.
A Terraform a listákat ilyen szempontból nem kezeli jól, mikor azzal több dolgot konfigurál.
Példa, hogy van 5 ügyfél.
A második úgy dönt, hogy nem kéri a szolgáltatást tovább. Az ügyfél törlésre kerül, az indexelés megváltozik és a harmadik, lesz a második, a negyedik a harmadik, az ötödik meg a negyedik. Ezeket mind törli és újra létre fogja hozni az összeset, ami utána van.
Terraform ezt fogja látni utána:
és nem ezt:
Ezért, ami a törölt elem után lesz, ezért lesz újratelepítve. Tehát egy ügyfél távozása nem független a többi ügyfél deployment-jétől. Ezért nem szoktuk az ügyfeleket listaszerűen kezelni.
A fájlok szerinti válogatás pedig pont ezt oldja meg vagy lehet bonyolult tömbökkel játszani, ami addig jó még nem lesz túl nagy a projekt és nem lesz kezelhetetlen. Erre már most érdemes gondolni, odafigyelni.
igen, pontosan az van amit irsz, ezert hasznalunk dict-eket es nem sima array-ket, amiben az indexek vannak. Minden for_each eseten lehet azt mondnai hogy az elem => join("-",[var.customer,var.resource_name,var.resourcetype,var.wahetever]), stb, ami tetszik
De a koltsegek szempontjabol inkabb erdemes tag-eket kezelni a felhoben costcenter vagy akarmi neven. Ezzel aztan mindegyikben lehet koltsegre szurni, legyen az aws, gcp vagy azure.
Amugy a szeparaciora minden esetben szukseg van, a kerdes hogy hogy csinalja meg az ember, egy subscription + resource group-ok a kornyezeteknek, vagy minden kornyezetnek subscription (enni nem ker :D). Mindegyiknek megvan az elonye, de en inkabb a minden kornyezet egy subscriptionnal mennek, sot inkabb minden ugyfel egy hub subscription es a kornyezetei egy-egy spoke subscription. Neha gazos a cross-subscription resource-ok es kapcsolatok kezelese, de en jobban szeretem ezt a felepitest. :D
Nekem mar megfordult mindenfele a kezem alatt a mindent behanyunk egy subscription-be modtol a szep hub-spoke minden customernek fele is.
Igen, pontosan ez van. Nincs egy pontosan definiált megoldás, ami mindenre jó. Vannak irányok és azokból célszerű kiválasztani az adott feladathoz a legmegfelelőbbet.
Így van ez is egy jó irány.
Ez egy alapvetően hülyén megtervezett platform, ami ideiglenesen fut a jelenlegi infrastruktúrában - nem tudok alapvető változásokat végigvinni benne.
Ez a rész viszont valóban problémás, így tényleg át kell terveznem:
ezt mostanában gyakran megkérdem én is magamtól, a terraform-tól teljesen függetlenül, mondjuk nincs is napirenden mostanában, szóval no offense.