Terraform variabelen in tfvars files: Een workaround met databags
Armiek Assadourian
Terraform is een krachtig hulpmiddel voor het beheren van infrastructuur als code. Het stelt je in staat om infrastructuurconfiguraties te definiëren, versiebeheer toe te passen en deze gemakkelijk te reproduceren. Echter loop je soms tegen beperkingen aan. Het is niet mogelijk om variabelen binnen variabelen te definiëren. In dit artikel bespreken we dit probleem en introduceren we een oplossing door gebruik te maken van een 'databag' variabele. We illustreren dit met een voorbeeld van een hub-spoke netwerk waarbij we in elke spoke hetzelfde subnet willen definiëren, maar met een verschillend CIDR-blok.
Het probleem: Geen variabelen in variabelen
In Terraform kun je geen variabelen binnen variabelen definiëren in je tfvars
bestanden. Dit betekent dat je geen variabele kunt gebruiken als waarde voor een andere variabele in je configuratiebestanden. Dit kan problematisch zijn wanneer je dezelfde configuratie in meerdere omgevingen wilt gebruiken, maar met kleine variaties, zoals verschillende CIDR-blokken voor subnets.
Stel je voor dat je een hub-spoke netwerk opzet en in elke spoke hetzelfde subnet wilt hebben, maar met een uniek CIDR-blok per spoke. Je zou geneigd zijn om je variabelen als volgt te definiëren in een all-spokes.tfvars
bestand:
1subnet = {
2 "mySubnet" = {
3 cidr = var.dev_cidr
4 }
5}
variables.tf:
1variable "subnet" {
2 type = map(object({
3 cidr = string
4 }))
5}
Echter, je kunt hier geen andere variabele als waarde voor cidr
opgeven binnen het tfvars
bestand. Dit beperkt de flexibiliteit en herbruikbaarheid van je Terraform-configuratie.
De oplossing: Gebruik van een databag variabele
Om dit probleem te omzeilen, kunnen we een 'databag' variabele introduceren. Een databag is een dictionary die je kunt gebruiken om dynamische waarden door te geven aan je configuratie. Door referenties naar deze databag te gebruiken, kun je indirect variabelen binnen variabelen toepassen.
Stap 1: Definieer de databag variabele
Begin met het definiëren van de databag variabele in je variables.tf
bestand:
1variable "databag" {
2 type = map(string)
3 default = {}
4}
Dit creëert een lege map waarin je later per omgeving specifieke waarden kunt zetten.
Stap 2: Pas je subnet variabele aan
Update de subnet
variabele om een referentie naar de databag op te nemen in plaats van directe waarden:
1variable "subnet" {
2 type = map(object({
3 cidr_databag_variable_reference = string
4 }))
5}
Hierdoor kun je een key opgeven die verwijst naar een waarde in de databag.
Stap 3: Verwijs naar de databag in je configuratie
In je all-spokes.tfvars
bestand kun je nu de subnets definiëren met referenties naar de databag:
1subnet = {
2 "someSubnet" = {
3 cidr_databag_variable_reference = "cidrSomeSubnet"
4 }
5}
Hier geef je aan dat voor someSubnet
de CIDR-waarde moet worden opgehaald uit de databag met de key cidrSomeSubnet
.
Stap 4: Definieer de databag per omgeving
In je omgevingsspecifieke tfvars
bestanden, zoals dev.tfvars
en test.tfvars
, vul je de databag met de juiste CIDR-waarden:
1# Bestand: dev.tfvars
2databag = {
3 "cidrSomeSubnet" = "10.0.1.0/24"
4}
5
6# Bestand: test.tfvars
7databag = {
8 "cidrSomeSubnet" = "10.0.2.0/24"
9}
Door dit te doen, kun je per omgeving verschillende CIDR-blokken definiëren zonder de hoofdconfiguratie aan te passen.
Stap 5: Gebruik de waarden in je resources
In je resource-definities haal je de CIDR-waarden op uit de databag:
1resource "azurerm_subnet" "subnet" {
2 for_each = var.subnet
3 name = each.key
4 resource_group_name = var.resource_group_name
5 virtual_network_name = var.virtual_network_name
6 address_prefixes = [var.databag[each.value.cidr_databag_variable_reference]]
7}
Voordelen van deze benadering
Flexibiliteit
Deze methode biedt meer flexibiliteit omdat je per omgeving verschillende waarden kunt instellen zonder de hoofdconfiguratie te wijzigen. Dit is vooral handig in omgevingen waar je met meerdere stages werkt, zoals development, testing en productie.
Herbruikbaarheid
Door het gebruik van databags kun je je Terraform-code herbruikbaarder maken. De hoofdconfiguratie blijft algemeen en de omgevingsspecifieke details worden extern beheerd.
Eenvoudig Beheer
Het centraliseren van omgevingsspecifieke waarden in de databag maakt het beheer eenvoudiger. Je kunt snel waarden aanpassen zonder diep in de configuratiebestanden te duiken.
Nadelen en overwegingen
Complexiteit
Het introduceren van een extra abstractielaag met databags kan de leesbaarheid en begrijpelijkheid van je Terraform-configuratie verminderen, vooral voor nieuwkomers in het team.
Foutgevoeligheid
Als de keys in je databag niet correct overeenkomen met de referenties in je subnet variabelen, kunnen er runtime errors optreden die lastig te debuggen zijn.
Beperkte validatie
Terraform's type-checking en validatie zijn minder effectief wanneer je waarden indirect via een databag doorgeeft. Dit kan leiden tot fouten die pas tijdens het uitvoeren van terraform apply
zichtbaar worden.
Best practices
- Gebruik duidelijke en consistente namen voor je databag keys om verwarring te voorkomen.
- Documenteer het gebruik van databags binnen je team om de leercurve te verlagen.
- Implementeer validatie binnen je Terraform-configuratie om fouten vroegtijdig te detecteren.
Conclusie
Hoewel Terraform standaard ondersteuning biedt voor het gebruik van variabelen binnen variabelen in tfvars
bestanden, kun je met behulp van een databag variabele dit probleem effectief omzeilen. Deze aanpak stelt je in staat om dynamische en omgevingsspecifieke waarden te beheren zonder afbreuk te doen aan de herbruikbaarheid van je code.
Door het implementeren van databags kun je de complexiteit van je infrastructuurconfiguraties beheersen en tegelijkertijd de flexibiliteit vergroten. Het is een krachtige techniek die, mits zorgvuldig toegepast, je Terraform-projecten naar een hoger niveau kan tillen.