Azure Infrastructuur uitrollen, hoe doe je dat?
1 maart 2023, Sander op ‘t Hof
Introductie
De cloud verandert waanzinnig snel en nieuwe functionaliteiten kunnen door de cloud-aanbieders op elk moment worden toegevoegd. Daar komt bij dat het handmatig in elkaar klikken van een cloud omgeving veel tijd kost en foutgevoelig is. Tegenwoordig is het mogelijk om met Infrastructuur as Code (IaC) deze uitdagingen de baas te zijn! Het maken van infrastructuur gaat door middel van het schrijven van code en dat maakt het mogelijk om dit op iedere omgeving makkelijk uit te rollen of dat nu on premise of in de cloud is. De code is relatief beknopt, variabel te maken en uitrolbaar via een automatisch proces, zoals bijvoorbeeld Azure DevOPS. Met IaC versnel je het uitrolproces en maak je inzichtelijk hoe componenten elkaar raken. Daarnaast vergroot je de betrouwbaarheid van je infrastructuur.
Bij OneDNA hebben we OneBase ontwikkeld om snel een solide basisinrichting te hebben in Azure cloud. De eerste ontwikkeling van OneBase was op basis van ARM templates, maar met de mogelijk van IaC, wilden we de stap maken naar Bicep of Terraform.
Terraform vs. Bicep
Terraform en Bicep zijn op dit moment twee populaire tools in de markt om infrastructuur te definiëren en te managen op een declaratieve manier. Deze declaratieve manier houdt in dat met relatief eenvoudige code wordt verklaard hoe je omgeving eruit komt te zien en dat dit ook begrijpelijk is voor iedere ontwikkelaar. Beide tools zijn open source en hebben een actieve community van gebruikers. Deze community draagt bij aan reguliere updates en zorgt dat je op de hoogte bent van de laatste features.
Terraform is een volwassen tool die al meerdere jaren op de markt is met een groot aantal functionaliteiten. Zo worden er meerdere cloud providers ondersteund zoals AWS, Azure en Google Cloud, maar daarnaast kunnen ook on premise omgingen beheerd worden. De gebruikte syntax is HashiCorp Configuration Language (HCL), wat eenvoudig te lezen en te begrijpen is. Verderop zijn een aantal voorbeelden uitgewerkt.
Bicep is een relatief nieuwe tool ontwikkeld door Microsoft. Het is speciaal ontwikkeld voor Azure en maakt gebruik van syntax die erg lijkt op ARM templates. Bicep maakt het gebruiksvriendelijker om Azure resources aan te maken en vereist een stuk minder code dan ARM.
De overeenkomsten op een rij:
- open source;
- actieve community;
- gebruikers kunnen infrastructuur definiëren en beheren;
- verschillende standaard libraries beschikbaar;
- actief updatebeleid.
Keuze maken
Beide tools zijn uitstekend in staat om infrastructuur uit te rollen en te beheren, dus wat dat betreft zijn beide tools een valide keuze. Echter, toen de keuze in 2022 gemaakt moest worden voor onze OneBase oplossing, is de keuze gevallen op Terraform. Belangrijkste redenen zijn dat Terraform langer op de markt is en verschillende platformen ondersteund. Daarnaast zien wij bij onze klanten dat zij hoofdzakelijk Terraform gebruiken. Leren leer je door te doen, dus voor ons was het een eenvoudige keuze.
Hoe te gebruiken?
Doordat we gebruik maken van Terraform, hebben we de mogelijkheid om door middel van Azure DevOps pipelines alle code automatisch uit te rollen. Daarom leggen we alle code vast in een GIT repository binnen Azure DevOps en ontwikkelen we lokaal met VSCode. Doordat we uitrollen met behulp van een pipeline is een ander voordeel dat beheerders/ontwikkelaars van de Azure Portal niet meer alle rechten nodig hebben, wat op het gebied van veiligheid een voordeel is.
In Terraform kun je functionele scheiding aan brengen zodat bijvoorbeeld elk team eigen resources kan beheren. Dit kun je doen door meerdere losse Terraform aan te maken. Daardoor kan je binnen je project het overzicht bewaren. Terraform zorgt er vervolgens voor dat de bestanden automatisch samengevoegd worden waardoor afhankelijkheden automatisch worden opgelost door resources in juiste volgorde aan te maken.
In de code maak je gebruik van omgevingsvariabelen. Met deze variabele kun je snel verschillende omgevingen uitrollen met dezelfde configuratie, denk bijv. aan een OTAP-straat. Hierbij pas je makkelijk verschillende waarden toe per omgeving voor bijv. drempelwaarde.
Nog even op een rij
- Terraform en Bicep zijn beide valide infrastructure as code (IaC) oplossingen voor Azure cloud
- Voor OneBase is gekozen voor Terraform omdat deze langer op de markt is en meerdere platformen ondersteund.
- Terraform scripts blijven beheersbaar met de mogelijkheid van functiescheiding en omgevingsvariabele.
- Met Azure DevOps pipeline is onderhoud makkelijk en snel ui te rollen over één of meerdere cloud omgevingen.
Technische implementatie
Waar begin je?
OneDNA is een gespecialiseerd in Microsoft Azure en om snel een basisinrichting te realiseren in Azure hebben wij OneBase ontwikkeld. OneBase werkt met Terraform en de voorbeelden in dit hoofdstuk zijn hierop gebaseerd.
Leren door te doen werkt vaak het beste, door het opdoen van de ervaring in de praktijk leer je snel de ins en outs van Terraform. In dit hoofdstuk staan praktijkvoorbeelden om je een beeld te geven van een basisconfiguratie.
Starten kan op verschillende manieren, bijvoorbeeld:
- Eerst oefen opdrachten maken via de Terraform site: https://developer.hashicorp.com/Terraform/tutorials/Azure-get-started
- Gelijk in een eigen Azure omgeving beginnen.
Kies je voor de tweede optie, dan kan je het volgende stappenplan hanteren:
- Downloaden van Terraform. (dit kan via de volgende site: https://developer.hashicorp.com/Terraform/downloads)
- Na de installatie kan je starten met jouw favoriete IDE (bijvoorbeeld VSCode).
- Installeer een Terraform extensie in je IDE zodat je optimaal kan ontwikkelen.
- Je bent nu klaar om echt aan de gang te gaan met Terraform!
Link leggen naar een resource group
Voor nu starten we met het aanmaken van een storage account in een bestaande resource group in Azure. We hebben reeds een resourcegroup aangemaakt die “rg-operations-dev-westeurope” heet. Verwijzingen naar resources gebeuren op een andere manier dan resource aanmaken. Voor een verwijzing naar een bestaande resource wordt een data blok gebruikt:
data "azurerm_resource_group" "onedna" {
name = "rg-operations-${var.environment}-westeurope"
}
Binnen bovenstaande code snippet zien we een aantal onderdelen.
- Data: De functie voor een verwijzing naar een bestaande resource.
- Azurerm_resource_group: Het component van een resource group in Azure.
- Onedna: een tag die meegeven dient te worden. De combinatie tussen een component en tag dient ten alle tijden uniek te zijn.
- Name: De naam van de resource group.
- Var.environment: een verwijzingen naar een variabele environment.
Het aanmaken van een storage account
Na het aanmaken van de link naar een resource group, gaan we een storage account aanmaken.
Het aanmaken van een storage account gebeurd in een bestaande resource group. Hier leggen we een verwijzing naar het data component van bovenstaande resource group.
resource "azurerm_storage_account" "onedna" {
name = "stoperations${var.environment}"
resource_group_name = data.azurerm_resource_group.onedna.name
location = data.azurerm_resource_group.onedna.location
account_tier = "Standard"
account_replication_type = "LRS"
account_kind = "StorageV2"
enable_https_traffic_only = true
is_hns_enabled = true
}
Binnen bovenstaande code snippet zien we een aantal onderdelen.
- Resource: De functie voor het aanmaken/beheren van een resource.
- Azurerm_storage_account: Het component van een resource group in Azure.
- Onedna: een tag die meegeven dient te worden. De combinatie tussen een component en tag dient ten alle tijden uniek te zijn.
- Name: de naam voor deze resource.
- Resource_group_name: hier komt de resource group naam. Hier is een verwijzing opgenomen naar bovenstaande resource group. Dit heeft grote voordelen, stel de naam wijzigt van de resource group dan hoeft dat nu maar op 1 plaats gewijzigd te worden.
- Location: Per resource zijn verschillende attributen waarnaar gerefereerd kan worden. Voor een resource group is dit bijvoorbeeld de locatie waarin hij zich bevind. Deze kan dus ook hier gebruikt worden zodat het storage account in dezelfde locatie zit als de resource group.
- Verder zijn een aantal standaard waardes meegeven voor het storage account.
In bovenstaand voorbeeld worden een aantal variabelen meegegeven voor het aanmaken van een storage account. Bij alles wat we niet opgeven worden de default instellingen gebruikt. Denk bijvoorbeeld aan het doorvoeren van de netwerk regels, het toepassen van logging en nog veel meer.
Provider specificeren
Zojuist hebben we de code doorgenomen voor het kunnen maken van een storage account en het verwijzen naar een resource group. Hiermee zijn we er echter nog niet, want de resource group en storage account zijn onderdeel van de Azurerm provider. Deze dienen we met Terraform provider te specificeren.
Terraform {
required_providers {
Azurerm = {
source = "hashicorp/Azurerm"
version = "~> 3.36.0"
}
}
}
In bovenstaande code snippet zien we een aantal onderdelen.
- Azurerm: dit is de module die wordt gebruikt om in Azure resources te maken en te beheren.
- Source: waar de provider te vinden is.
- Version: de versie die benodigd is.
Variabelen declareren
Door middel van het toepassen van variabelen kunnen we een omgeving specificeren. Eerst moeten we een variabele declareren voordat een waarde toegekend kan worden. De declaratie gaat op de volgende manier:
variable "environment" {
type = string
}
In bovenstaande code snippet zien we een aantal onderdelen.
- Environment: de naam van de variabele.
- Type: per variabele dien je het type vast te leggen. Hierbij hebben we gekozen voor een string.
De variabele willen we gebruiken om hier dev, tst, acc en prd in te zetten.
Variabelen invoeren
Het invoeren van variabelen moet in een variables.tfvars bestand, deze is per omgeving aan te maken. Hier kunnen dus onderdelen zoals tags of informatie die je specifiek wilt voor een bepaalde omgeving in opnemen. Per omgeving definieer je dus een los bestand en deze kan dan aangeroepen worden, onderstaand een voorbeeld voor de ontwikkel omgeving:
environment = "dev"
In bovenstaande code snippet zien we een aantal onderdelen.
- Environment: de naam van de variabele, deze dient gelijk te zijn aan de variabelen declareren code snippet.
- Dev: de waarde die we willen geven aan de key, environment.
Backend configuratie voor de state
Terraform werkt met een state file, hierin is opgeslagen wat allemaal is aangemaakt door Terraform. Elke keer als het script draait wordt eerst de state bijgewerkt om vervolgens de vergelijking te maken tussen de aangeleverde code en de state. Hiermee worden alle acties bepaald die uitgevoerd moeten worden, denk aan toevoegen/updaten/verwijderen.
Stel je zou het storage account uit je code verwijderen dan zal met behulp van deze state file vergelijking gedetecteerd worden dat Terraform het storage account dient te verwijderen.
We slaan de statefile op in een bestaand storage account op Azure. Dit bestand dient uniek te zijn voor elk Terraform project en Azure omgeving waar je de uitrol naar toe zet. Anders zal bij een uitgevoerde uitrol naar dev en tst dezelfde state file gebruikt worden. Dit zou bij een uitrol van tst ervoor zorgen dat je dev omgeving verwijderd wordt.
container_name = "terraform-state"
key = "onedna-storage.tfstate"
resource_group_name = "RGbeheer"
storage_account_name = "saterraform"
subscription_id = "####"
tenant_id = "####"
Bovenstaande configuratie is nodig om een connectie te maken met een storage account en hier de state in op te slaan in Azure. De onderdelen die hierin staan zijn:
- Container_name: de naam van de storage account container waar de state file komt.
- Key: de bestandsnaam van de state file, deze moet uniek zijn voor elk project.
- resource_group_name: de naam van de resource group waar de state file komt.
- storage_account_name: de naam van het storage account waar de state file komt.
- subscription_id: de subscription waar de state file staat.
- tenant_id: de tenant waar de state file staat.
Deployen
Dit zijn alle snippets die je nodig hebt om Terraform te kunnen gebruiken. Wil je alle bestanden ontvangen? Stuur dan even een bericht.
Met al deze onderdelen zorgt Terraform ervoor dat een uitrol kan plaatsvinden. Een deployment kan lokaal naar Azure of via een DevOps pipeline gebeuren. Om dit te doen zijn er een aantal commando’s. Hiervoor moet eerst Terraform geïnstalleerd worden. (zie link een stuk verder naar boven).
De commando’s in Terraform om je omgeving neer zetten zijn:
- Init: voor de initialisatie van de omgeving. Hiermee wordt de opgeven versie binnengehaald en geïnstalleerd.
- Plan: hier kan je zien wat Terraform voor acties gaat uitvoeren. De opties zijn toevoegen, aanpassen of verwijderen.
- Apply: om de aanpassingen door te voeren richting de Azure omgeving.
- Destroy: voor het verwijderen van alle componenten die in de state file bekend zijn.
Conclusie
De blog geeft inkijk in het gebruik van Terraform en de toepasbaarheid bij onze klanten. Het is eenvoudig op te zetten voor je eigen omgeving, en het zorgt ervoor dat je aanzienlijk sneller dezelfde omgeving ernaast neer kan zetten. Het viel mij op dat Terraform snel te lezen is, je krijgt een goed overzicht van de omgeving die neergezet wordt en hebt praktisch je documentatie gelijk op orde van de resources.
Doordat we bij steeds meer opdrachten met Terraform gebruikt zien worden is het slim om niet lang te wachten met de adoptie van IaC. Het biedt meer voordelen dan de oude manier van het toepassen van arm templates voor je uitrol. Dit was voor ons de reden om over te stappen met onze OneBase oplossing. Nieuwsgierig naar een verdiepende slag of nog meer ins en outs? Laat het ons weten en dan nemen we contact met je op. We vertellen graag meer over OneBase ofwel de vragen die leven over Terraform of verras ons, we worden graag uitgedaagd! 😉