Terraform - Utiliser le provider libvirt
Publié le : 4 février 2021 | Mis à jour le : 22 janvier 2023Je vous propose ici de découvrir comment utiliser Terraform avec libvirt. Je vous conseille de monter ma configuration Devops 2022 qui contient tout ce qu’il faut. Ce billet fait suite à l'introduction à Terraform ou tout est expliqué sur ce produit d’Infrastructure As Code.
Installer le plugin libvirt
Si vous avez pris ma configuration deveops 2022 rien à installer, ça fonctionne
de suite. Ah si quelques outils comme mkisofs
et libguestfs-tools
car on va
utiliser cloud-init
.
sudo apt install -y libguestfs-tools genisoimage
Pour que terraform fonctionne avec ce provider il faut modifier la configuration de libvirtd :
sudo vi /etc/libvirt/qemu.conf
Modifier la ligne : #security = [...]
par security_driver = "none"
. Ne pas
oublier d’enlever le #
au début de la ligne. On redémarre libvirt pour que
cela soit pris en compte.
sudo systemctl restart libvirtd
Tout est prêt, mais avant je tiens à préciser que le provider libvirt
n’est
pas fourni par hashicorp mais par un développeur répondant au nom de Duncan
Mac-Vicar P.
Dans votre fichier main.tf
il suffit d’indiquer ce provider. Le code source
est là :
terraform {
required_providers {
libvirt = {
source = "dmacvicar/libvirt"
}
}
}
provider "libvirt" {
# Configuration options
}
On lance la commande terraform init
et normalement il va installer ce plugin.
terraform init
Initializing the backend...
Initializing provider plugins...
- Finding latest version of dmacvicar/libvirt...
- Installing dmacvicar/libvirt v0.6.11...
- Installed dmacvicar/libvirt v0.6.11 (self-signed, key ID 96B1FE1A8D4E1EAB)
Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html
Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
Création de la première machine
On va voir un exemple permettant de créer une machine ubuntu en utilisant
cloud-init
pour sa configuration.
Faites attention à ce que votre réseau kvm default existe avec le même réseau 192.168.122.1, sinon adaptez le contenu en conséquence :
mkdir test-terraform
cd test-terraform
Les fichiers de configuration
Éditer le fichier main.tf
avec ce contenu :
terraform {
required_providers {
libvirt = {
source = "dmacvicar/libvirt"
version = "0.6.14"
}
}
}
// instance the provider
provider "libvirt" {
uri = "qemu:///system"
}
// variables that can be overriden
variable "hostname" { default = "test" }
variable "domain" { default = "example.com" }
variable "ip_type" { default = "dhcp" } # dhcp is other valid type
variable "memoryMB" { default = 1024*1 }
variable "cpu" { default = 1 }
// fetch the latest ubuntu release image from their mirrors
resource "libvirt_volume" "os_image" {
name = "${var.hostname}-os_image"
pool = "default"
source = "jammy-server-cloudimg-amd64.img"
format = "qcow2"
}
// Use CloudInit ISO to add ssh-key to the instance
resource "libvirt_cloudinit_disk" "commoninit" {
name = "${var.hostname}-commoninit.iso"
pool = "default"
user_data = data.template_cloudinit_config.config.rendered
network_config = data.template_file.network_config.rendered
}
data "template_file" "user_data" {
template = file("${path.module}/cloud_init.cfg")
vars = {
hostname = var.hostname
fqdn = "${var.hostname}.${var.domain}"
public_key = file("~/.ssh/id_rsa.pub")
}
}
data "template_cloudinit_config" "config" {
gzip = false
base64_encode = false
part {
filename = "init.cfg"
content_type = "text/cloud-config"
content = "${data.template_file.user_data.rendered}"
}
}
data "template_file" "network_config" {
template = file("${path.module}/network_config_${var.ip_type}.cfg")
}
// Create the machine
resource "libvirt_domain" "domain-ubuntu" {
# domain name in libvirt, not hostname
name = "${var.hostname}"
memory = var.memoryMB
vcpu = var.cpu
disk {
volume_id = libvirt_volume.os_image.id
}
network_interface {
network_name = "default"
}
cloudinit = libvirt_cloudinit_disk.commoninit.id
# IMPORTANT
# Ubuntu can hang is a isa-serial is not present at boot time.
# If you find your CPU 100% and never is available this is why
console {
type = "pty"
target_port = "0"
target_type = "serial"
}
graphics {
type = "spice"
listen_type = "address"
autoport = "true"
}
}
terraform {
required_version = ">= 1.2.5"
}
output "ips" {
value = libvirt_domain.domain-ubuntu.*.network_interface.0.addresses
}
Créer les deux fichiers cloud_init.cfg et network_config_dhcp.cfg
hostname: ${hostname}
fqdn: ${fqdn}
manage_etc_hosts: true
users:
- name: ubuntu
sudo: ALL=(ALL) NOPASSWD:ALL
groups: users, admin
home: /home/ubuntu
shell: /bin/bash
lock_passwd: false
ssh-authorized-keys:
- ${public_key}
ssh_pwauth: true
disable_root: false
chpasswd:
list: |
ubuntu:linux
expire: False
packages:
- qemu-guest-agent
- python3
bootcmd:
- [ sh, -c, 'echo $(date) | sudo tee -a /root/bootcmd.log' ]
runcmd:
- [ sh, -c, 'echo $(date) | sudo tee -a /root/runcmd.log' ]
final_message: "The system is finall up, after $UPTIME seconds"
power_state:
delay: "+30"
mode: reboot
message: Bye Bye
timeout: 30
condition: True
le second :
version: 2
ethernets:
ens3:
dhcp4: true
Préparation de l’image
Avant de se lancer je vous propose de récupérer l’image et de changer le mot
de passe de root. Cela sera bien pratique pour debugger et surtout d’éviter
de télécharger l’image à chaque lancement de la commande terraform apply
.
wget http://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img
sudo virt-customize -a bionic-server-cloudimg-amd64.img --root-password password:stephan
[ 0.0] Examining the guest ...
[ 12.4] Setting a random seed
virt-customize: warning: random seed could not be set for this type of
guest
[ 12.4] Setting the machine ID in /etc/machine-id
[ 12.4] Setting passwords
[ 13.5] Finishing off
Provisionning
C’est bon on peut y aller, lancer les commandes suivantes :
terraform init
terraform plan
terraform apply
Répondez yes
à la commande apply.
Contrôlons si la vm a bien été provisionné :
sudo virsh list --all
Id Name State
------------------------------------------------------------
2 staticip running
Récupérons son adresse IP :
terraform refresh && terraform output ips
libvirt_cloudinit_disk.commoninit: Refreshing state... [id=/var/lib/libvirt/images/staticip-commoninit.iso;bb2ef864-37cf-444a-a8a0-efe6b036dfbb]
libvirt_volume.os_image: Refreshing state... [id=/var/lib/libvirt/images/staticip-os_image]
libvirt_domain.domain-ubuntu: Refreshing state... [id=ac83d6c0-acb0-4465-9f83-01324deae8bd]
Outputs:
ips = [
tolist([
"192.168.122.66",
]),
]
sudo virsh net-dhcp-leases default
Expiry Time MAC address Protocol IP address Hostname Client ID or DUID
------------------------------------------------------------------------------------------------------------------------------------------------
2022-08-17 12:52:41 52:54:00:e2:65:01 ipv4 192.168.122.66/24 ubuntu ff:b5:5e:67:ff:00:02:00:00:ab:11:77:6b:c8:0b:77:8a:3e:de
Oui elle bien up ! Maintenant il suffit de lancer se connecter à la vm
ssh ubuntu@192.168.122.66
Welcome to Ubuntu 22.04.1 LTS (GNU/Linux 5.15.0-46-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Wed Aug 17 12:08:03 UTC 2022
System load: 0.0 Processes: 91
Usage of /: 78.3% of 1.96GB Users logged in: 0
Memory usage: 21% IPv4 address for ens3: 192.168.122.66
Swap usage: 0%
10 updates can be applied immediately.
1 of these updates is a standard security update.
To see these additional updates run: apt list --upgradable
The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.
-bash: warning: setlocale: LC_ALL: cannot change locale (fr_FR.UTF-8)
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.
ubuntu@test:~$
On va contrôler le résultat de la commande cloud_init :
cat /var/log/cloud-init-output.log
Cloud-init v. 22.2-0ubuntu1~22.04.3 running 'init-local' at Wed, 17 Aug 2022 11:52:36 +0000. Up 7.86 seconds.
Cloud-init v. 22.2-0ubuntu1~22.04.3 running 'init' at Wed, 17 Aug 2022 11:52:40 +0000. Up 11.83 seconds.
ci-info: ++++++++++++++++++++++++++++++++++++++Net device info++++++++++++++++++++++++++++++++++++++
ci-info: +--------+------+----------------------------+---------------+--------+-------------------+
ci-info: | Device | Up | Address | Mask | Scope | Hw-Address |
ci-info: +--------+------+----------------------------+---------------+--------+-------------------+
ci-info: | ens3 | True | 192.168.122.66 | 255.255.255.0 | global | 52:54:00:e2:65:01 |
ci-info: | ens3 | True | fe80::5054:ff:fee2:6501/64 | . | link | 52:54:00:e2:65:01 |
ci-info: | lo | True | 127.0.0.1 | 255.0.0.0 | host | . |
ci-info: | lo | True | ::1/128 | . | host | . |
ci-info: +--------+------+----------------------------+---------------+--------+-------------------+
ci-info: ++++++++++++++++++++++++++++++++Route IPv4 info++++++++++++++++++++++++++++++++
ci-info: +-------+---------------+---------------+-----------------+-----------+-------+
....
Processing triggers for libc-bin (2.35-0ubuntu3.1) ...
Processing triggers for man-db (2.10.2-1) ...
NEEDRESTART-VER: 3.5
NEEDRESTART-KCUR: 5.15.0-46-generic
NEEDRESTART-KEXP: 5.15.0-46-generic
NEEDRESTART-KSTA: 1
Wed Aug 17 11:52:59 UTC 2022
The system is finall up, after 30.62 seconds
Génial !!!
Voila maintenant détruisez la :
Décomissionnement
terraform destroy -f
Debug
Attention le cloud-init ne se lance que lors du premier resfresh et donc il faudra faire un destroy puis aplly si vous devez le rejouer.
Pour debugger votre cloud-init il suffit d’activer cockpit :
sudo dnf -y install cockpit
sudo systemctl enable --now cockpit.socket
sudo firewall-cmd --add-service=cockpit --permanent
sudo firewall-cmd --reload
Ensuite, allez sur votre navigateur, pour accéder à cockpit qui sera disponible via l’url : https://(serverip or hostname):9090/
Il vous suffira ensuite de vous connecter à la machine via la console série avec
le compte root. Ensuite les logs de cloud-init se trouve dans le répertoire
/var/log
.
[Maj] La suite sur comment lancer le provisioning avec Ansible sur ce billet.
A bientôt !