Dit bericht verscheen eerder op BIT
Bij BIT is het mogelijk om een Virtual Datacenter af te nemen. Hiermee beschik je over een bepaalde hoeveelheid dedicated resources zoals processorkracht, geheugen en opslag. Op deze manier hoef je zelf niet te investeren in kostbare hardware. Het is mogelijk om deze digitale omgeving te beheren via een beheeromgeving, waar je eenvoudig kan op- en afschalen door de resources te verdelen over het aantal virtuele servers dat je hebt. Hiermee heb je maximale grip op en flexibiliteit over de inrichting en kosten van je omgeving.
Naast het beheren van de omgeving via een beheeromgeving, is het ook mogelijk om de omgeving te beheren via Terraform. Door hierbij ook gebruik te maken van Ansible is bijvoorbeeld het toevoegen van extra webservers een fluitje van een cent. In dit blog zullen we aan de hand van voorbeelden laten zien hoe je gebruik kan maken van Terraform en Ansible wanneer je een BIT Virtual Datacenter hebt.
Wat houdt Infrastructure as Code (IaC) in?
Waarbij vroeger veel platformen direct draaiden op fysieke hardware, zien we dat er tegenwoordig steeds meer gevirtualiseerd wordt. Dit zorgt er niet alleen voor dat er veel meer (soorten) platformen tegelijk kunnen draaien op fysieke hardware, maar het biedt ook mogelijkheden voor het automatisch provisionen door het op te schrijven als code, ook wel Infrastructure as Code (IaC) genoemd. In een bepaalde programmeertaal wordt dan beschreven welke componenten er zijn, wat hun eigenschappen zijn, en wat het gewenste eindresultaat moet zijn.
Doordat de code eenvoudig opnieuw is uit te voeren, kunnen wijzigingen ook snel en gemakkelijk worden getest. Daarnaast heeft het ook als groot voordeel dat de kans op fouten geminimaliseerd wordt, omdat het proces is geautomatiseerd.
Terraform: de beheerder van jouw infrastructuur
Terraform is een open source project van HashiCorp dat ondersteuning biedt voor meer dan honderd providers. De IaC wordt geschreven in een taal die door HashiCorp zelf is bedacht: HashiCorp Configuration Language (HCL).
Het aantal providers dat Terraform ondersteunt is erg uitgebreid, wat te danken is aan de grote community die Terraform heeft. Op de Providers pagina van Terraform zijn alle beschikbare providers te vinden. Dit zijn niet alleen de bekende public cloud leveranciers, maar bijvoorbeeld ook netwerk devices, monitoring applicaties en communicatiediensten. Je zou kunnen stellen dat alles wat een API heeft gezien kan worden als provider.
Wanneer de infrastructuur is geschreven, kan deze middels één commando worden uitgerold. Naast het aanmaken van de infrastructuur is het ook mogelijk om de omgeving (gedeeltelijk) af te breken. En omdat de gehele omgeving in code geschreven is, heb je ook de mogelijkheid om versiebeheer toe te passen.
Een instance altijd hetzelfde geconfigureerd met Ansible
Nu we het kort hebben gehad over wat IaC en Terraform precies inhouden, moeten we het hebben over Ansible. Ook Ansible is een open-source project. Waar Terraform gericht is op het aanmaken van bijvoorbeeld virtual machines, is Ansible bedoeld voor onder andere het beheer van de omgeving binnen een virtual machine. Met Ansible is het daarnaast ook mogelijk om netwerkapparatuur van bijvoorbeeld F5, Juniper en Fortigate te beheren. Het is dus een tool die op vele plekken kan worden ingezet, dankzij de vele modules die beschikbaar zijn.
Ansible heeft als groot voordeel dat het agentless is. Alleen op de hoost vanaf waar je Ansible wilt draaien moet de software beschikbaar zijn. Bij een Linux of Unix remote hoost maakt Ansible verbinding via SSH, en bij een Windows remote host via WinRM.
Door een remote host volledig te beheren via Ansible, zal elke uitrol (als het goed is) resulteren in hetzelfde resultaat!
Je werkomgeving klaar maken voor Terraform en Ansible
Nadat de installatie voltooid is, zijn de commando’s terraform
en ansible
beschikbaar.
$ ansible –version ansible [core 2.12.2] config file = /etc/ansible/ansible.cfg
|
$ terraform –version Terraform v1.1.9 on linux_amd64 |
De eerste stappen met Terraform
Nu Terraform en Ansible geïnstalleerd zijn, kan er een Terraform project worden gemaakt. We beginnen met het aanmaken van een locatie waar de projectbestanden in opgeslagen worden. In dit voorbeeld is dat in ‘home’, in de folder ‘terraform-blog’.
mkdir ~/terraform-blog cd ~/terraform-blog |
Maak met je favoriete editor het bestand main.tf
aan en zet hier onderstaande code in:
terraform {
required_providers {
opennebula = {
source = “OpenNebula/opennebula”
version = “0.4.1”
}
}
|
Wanneer de benodigde code voor de provider aan het bestand main.tf
is toegevoegd kan deze worden opgeslagen. Het Terraform project kan nu worden geïnitialiseerd, wat ervoor zorgt dat de benodigde OpenNebula bestanden worden gedownload.
Het initialiseren doen we door het commando terraform init
uit te voeren.
$ terraform init
Initializing the backend… Initializing provider plugins… Partner and community providers are signed by their developers. Terraform has created a lock file .terraform.lock.hcl to record the provider Terraform has been successfully initialized! You may now begin working with Terraform. Try running “terraform plan” to see If you ever set or change modules or backend configuration for Terraform, |
Als we nu kijken naar de bestanden in onze project folder, dan zal daar de folder .terraform
bij zijn gekomen, en het bestand .terraform.lock.hcl
. Het is af te raden deze bestanden aan te passen, aangezien deze mogelijk weer worden overschreven door Terraform.
Nu de benodigde bestanden voor de koppeling met OpenNebula aanwezig zijn, gaan we de authenticatie met de OpenNebula-omgeving configureren. Open het bestand main.tf
weer met de editor en voeg onderaan het bestand het volgende toe.
provider “opennebula” {
endpoint = “https://api.example.tld/RPC2”
|
Wanneer je een Virtal Datacenter bij BIT afneemt, worden de juiste inloggegevens aan je doorgegeven. Naast het gebruik van een wachtwoord is het ook mogelijk om gebruik te maken van een login token. Dit token kan je zelf genereren in de OpenNebula webinterface. Als de juiste inloggegevens zijn ingevoegd, kan het bestand worden opgeslagen. De basis is nu klaar, er is een provider geconfigureerd en de authenticatie naar die provider is ingesteld.
We gaan nu de configuratie zo maken dat er daadwerkelijk een instance wordt aangemaakt in OpenNebula.
Maak het bestand server.tf aan en zet de onderstaande code erin:
resource “opennebula_image” “clone_image” { clone_from_image = 424
|
In dit voorbeeld beginnen we met het klonen van een image dat al bestaat in onze OpenNebula omgeving. Dit is een basis Ubintu-installatie en het image id hiervan is 424
. Wanneer je bij BIT een Virtual Datacenter afneemt kan je zelf images aanmaken. Het is ook mogelijk dat wij een basis-image voor je klaarzetten. Voor meer informatie hierover kan je terecht bij onze supportafdeling.
De naam van het gekloonde image moet server1
worden, en deze moet ook persistent zijn. Het datastore_id is in dit geval 100
maar kan per omgeving verschillen.
In hetzelfde bestand, onder het clone_image gedeelte, maken we het gedeelte waar de instance wordt aangemaakt. Per blok zal hierover de nodige informatie worden gezet.
resource “opennebula_virtual_machine” “create_servers” {
name = “server1”
context = {
NETWORK = “YES”
}
|
De instance zal server1
worden genoemd, net als het image. De instance krijgt 3 CPUs, 3 vCPUs, en 1024 MiB werkgeheugen. De instance wordt ook aangemaakt in de group EXAMPLE
. Als je wil weten wat de group is in jouw geval, neem dan contact op met onze supportafdeling.
name
. Ook moet er een public SSH key worden geïmporteerd. Welk netwerk precies gebruikt moet worden, wordt later aangegeven.
Het volgende stuk dat we gaan toevoegen ziet er als volgt uit:
graphics {
type = “VNC”
}
os {
arch = “x86_64”
}
|
Het eerste deel heeft te maken met de mogelijkheid om een console beschikbaar te hebben via de webinterface. Dit kan handig zijn in het geval dat een instance niet meer te benaderen is via SSH. In het tweede deel specificeren we de architectuur en vanaf welke disk er gestart moet worden. IN dit geval is er maar één disk (of image), dus kiezen we disk0
.
In het volgende stuk dat we moeten toevoegen zullen we de disk koppelen en een netwerk configureren.
disk {
image_id = opennebula_image.clone_image.id
}
nic {
model = “virtio”
}
|
Omdat we eerder hebben geconfigureerd dat er een bestaand image moet worden gekloond, geven we met opennebula_image.clone_image.id aan dat deze gebruikt moet worden. Terraform zal dan de juiste image ID pakken die hoort bij het gekloonde image.
Wij hebben al een aantal netwerken gedefinieerd binnen OpenNebula. In dit geval krijgt de instance een IP-adres van het netwerk met ID31. Als je wil weten welk netwerk ID je kan gebruiken, neem dan contact op met onze supportafdeling.
Het laatste wat we gaan toevoegen is dat wanneer de instance voor de eerste keer wordt gestart, het OS ook direct wordt geüpdatet.
provisioner “remote-exec” {
inline = [“sudo apt update”, “sudo apt upgrade -y”]
connection {
host = “${self.ip}”
}
}
|
Als alles samengevoegd is ziet het bestand server.tf
er ongeveer zo uit:
resource “opennebula_image” “clone_image” { clone_from_image = 424
resource “opennebula_virtual_machine” “create_servers” { name = “server1”
context = {
NETWORK = “YES”
}
graphics {
type = “VNC”
}
os {
arch = “x86_64”
}
disk {
image_id = opennebula_image.clone_image.id
}
nic {
model = “virtio”
}
provisioner “remote-exec” { inline = [“sudo apt update”, “sudo apt upgrade -y”] connection { host = “${self.ip}” } } }
|
Sla de wijzigingen op, controleer of er geen fouten in de configuratie zitten, en hoeveel instances Terraform zal aanmaken. Dit doen we met het commando terraform plan
. Dit vertelt precies wat er zal wijzigen binnen OpenNebula.
$ terraform plan
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create
|
Als dit geen fouten of andere meldingen oplevert, kan de wijziging daadwerkelijk worden doorgevoerd. Dit doen we door het commando terraform apply
uit te voeren. Er verschijnt weer een overzicht wat er gaat veranderen, en als je akkoord gaat, typ je het woord yes
.
$ terraform apply
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create
Do you want to perform these actions? Terraform will perform the actions described above.
Only ‘yes’ will be accepted to approve. Enter a value: yes
|
Na het drukken op enter
zal Terraform beginnen met het aanmaken van de instance. Afhankelijk van wat er allemaal moet gebeuren kan dit even duren.
opennebula_image.clone_image: Creating… opennebula_image.clone_image: Still creating… [10s elapsed]opennebula_image.clone_image: Creation complete after 11s [id=437]opennebula_virtual_machine.create_servers: Creating… … opennebula_virtual_machine.create_servers: Creation complete after 5m55s [id=341] Apply complete! Resources: 1 added, 0 changed, 0 destroyed. |
Als de Terraform-run klaar is en er geen problemen zijn gemeld, is de instance aangemaakt en kan hij gebruikt worden. Als je nu naar de bestanden in de project folder kijkt, zul je zien dat één daarvan terraform.tfstate
is. In dit bestand slaat Terraform op hoe de omgeving bij OpenNebula is aangemaakt. Als dit bestand verwijderd wordt, zal Terraform proberen alles opnieuw aan te maken. Echter, omdat de instances al bestaan, zal dit niet lukken en krijg je een foutmelding. Het is daarom belangrijk om nooit zelf aanpassingen in terraform.tfstate
te maken.
De kracht van Ansible toevoegen
Nu het gelukt is om een instance te maken, is het ook handig om Ansible meteen aan te spreken. In dit voorbeeld zullen we een eenvoudig playbook maken dat Apache2 installeert op de instance en tevens een vhost configureert. We maken hier geen gebruik van rollen, maar alleen van losse taken in een playbook.
Maak binnen de bestaande project folder een nieuwe folder genaamd ansible
.
mkdir ansible && cd ansible |
Maak nu het bestand webserver.yaml
aan met een editor. Dit bestand wordt het playbook. We beginnen met 3 streepjes om aan te geven dat dit het begin van het document is. Daaronder beginnen we met - name:
om het playbook een naam te geven. In dit geval kiezen we voor ‘Configure webservers’. Direct daaronder definiëren we op welke hosts/hostgroups het playbook moet worden uitgevoerd. In dit geval zeggen we dat het playbook op alle hosts uitgevoerd moet worden. Als laatste zetten we tasks:
neer. Hiermee geven we aan dat de blokken die eronder komen afzonderlijke taken zijn die moeten worden uitgevoerd. Deze regels samen zien er dan als volgt uit:
—
– name: Configure webserver
hosts: all
|
Nu gaan we de taken eronder definiëren. In dit voorbeeld gaan we Apache2 installeren, een web folder aanmaken, en zorgen dat Apache3 wordt gestart. Ook hier beginnen we met de taken een naam te geven, bijvoorbeeld - name: Install Apache
. Daaronder geven we aan welke module Ansible moet gaan gebruiken. Omdat we een package willen installeren, zullen we de package
module gebruiken. Het is ook mogelijk om de apt
of yum
module te gebruiken om een package te installeren, maar het voordeel van de package module is dat deze werkt op zowel Debian als RedHat systemen. Onder package
geven we aan welk pakket geïnstalleerd moet worden en dat het de laatste versie moet zijn die op dit moment beschikbaar is in de repository. Dit ziet er als volgt uit:
—
– name: Configure webserver
hosts: all
– name: Install Apache2
package:
name: apache2
|
Nu voegen we een nieuwe - name:
toe, alleen dit keer met de tekst Create web directory
. Direct daaronder roepen we de file
module op. Met deze module is het mogelijk on onder andere files, folders of symlinks aan te maken. In dit geval vaan we een folder aanmaken, met path
geven we de locatie op waar de folder moet worden aangemaakt. Met state
geven we aan dat het een folder moet zijn en moet behoren tot de user/group www-data
. Met mode
stellen we de schrijfrechten in voor de betreffende folder.
—
– name: Configure webserver
hosts: all
– name: Install Apache2
package:
name: apache2
– name: Create web directory
file:
path: “/opt/www”
|
Met het laatste blok zorgen we ervoor dat Apache2 wordt gestart, en stellen we het ook zo in dat bij een reboot van de server Apache2 altijd wordt gestart. We beginnen weer met - name:
en nu met de tekst Start and enable Apache2
. Daaronder roepen we de systemd
module aan en geven aan dat Apache2 gestart moet zijn. Door enabled
op true
te zetten zorgen we ervoor dat bij een reboot Apache2 ook wordt gestart.
—
– name: Configure webserver
hosts: all
– name: Install Apache2
package:
name: apache2
– name: Create web directory
file:
path: “/opt/www”
– name: Start and enable Apache2
systemd:
name: apache2
|
Met dit eenvoudige playbook zorgen we ervoor dat Apache2 altijd geïnstalleerd wordt, dat er een folder wordt aangemaakt, en dat Apache2 wordt gestart. Uiteraard kan hier van alles staan. Zo zou je een playbook kunnen maken dat een MySQL cluster inricht, of een email server configureert. The sky’s the limit!
We nemen met Terraform script dat we eerder gemaakt hebben, en we maken een paar aanpassingen. We willen dat er 2 servers worden aangemaakt, en we voegen een extra provisioner toe die het Ansible playbook zal uitvoeren.
Dit ziet er als volgt uit:
resource “opennebula_image” “clone_image” {
count = 2
resource “opennebula_virtual_machine” “create_servers” { count = 2
context = {
NETWORK = “YES”
}
graphics {
type = “VNC”
}
os {
arch = “x86_64”
}
disk {
image_id = opennebula_image.clone_image[count.index].id
}
nic {
model = “virtio”
}
provisioner “remote-exec” {
inline = [“sudo apt update”, “sudo apt upgrade -y”, “sudo apt install python3 -y”]
connection {
host = “${self.ip}”
}
}
provisioner “local-exec” {
command = “ansible-playbook -u root -i ‘${self.ip}’, ansible/webserver.yaml”
}
|
Wanneer we nu een Terraform apply
uitvoeren, zullen de nieuwe servers worden aangemaakt en zal ook het Ansible playbook worden uitgevoerd. Na een paar minuten zijn deze servers dan klaar voor gebruik!
$ terraform apply
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create
opennebula_virtual_machine.create_servers[1] (local-exec): PLAY RECAP ********************************************************************* opennebula_virtual_machine.create_servers[1]: Creation complete after 6m1s [id=343] opennebula_virtual_machine.create_servers[0] (local-exec): PLAY RECAP ********************************************************************* opennebula_virtual_machine.create_servers[0]: Creation complete after 6m4s [id=342] Apply complete! Resources: 4 added, 0 changed, 0 destroyed. |
Dit bericht verscheen eerder op BIT