diff --git a/README.md b/README.md index 3eba63c..bc829b3 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,328 @@ -# advanced-libvirt-terraform-examples +# Modern libvirt-driven Terraform examples -This repository contains terraform examples to deploy various modern virtual machines using QEMU and libvirt \ No newline at end of file +This repository contains Terraform recipes to deploy various modern virtual machines using QEMU and libvirt. + +By modern, it is meant virtual machines that leverage the use of modern desktop-oriented technologies, like UEFI firmware and recent virtual motherboard chipset (i.e. Phyllome OS itself), by staying as close as possible as domain definitions maintained [here](https://git.phyllo.me/roots/xml-definition-for-domains). + +## Requirements + +- [QEMU](https://www.qemu.org/) +- [libvirt](https://libvirt.org/) +- [Terraform provider for Libvirt](https://github.com/dmacvicar/terraform-provider-libvirt) + +## Assumptions + +Your Linux x86_64-based machine has at least 4 GB of available memory and 2 CPUs. + +## How to use it + +- Clone this repository +- Go to folder *ubuntu-cloud-server-2404-bios* +- Execute the following commands, which will download and install the required Terraform provider if not already present + +``` +$ terraform init + +Initializing the backend... +Initializing provider plugins... +- Reusing previous version of dmacvicar/libvirt from the dependency lock file +- Using previously-installed dmacvicar/libvirt v0.8.3 + +Terraform has been successfully initialized! + +[...] +``` + +- The following command will plan the deployment, describing actions that will be taken when applied + +``` +$ terraform plan + +[...] + +Terraform will perform the following actions + +# A cloud-init ISO disk is created, which provides pre-configured settings and scripts that are applied to a cloud-native disk image during its initial boot. Without it, no user would be created and it would not be possible to log into the virtual machine + + + resource "libvirt_cloudinit_disk" "commoninit" { + + name = "commoninit.iso" + + pool = "ubuntu-bios" + +[...] + + } + +# The libvirt domain or virtual machine will be created + + + resource "libvirt_domain" "domain" { + + cloudinit = (known after apply) + +[...] + + } + +# Here, a libvirt pool to store the virtual machine disk image will be created. It should be possible to use the default one + + + resource "libvirt_pool" "ubuntu-bios" { + +[...] + + + name = "ubuntu-bios" + + type = "dir" + + + target { + + path = "/tmp/ubuntu-bios" + } + } + +# A qcow2 disk volume will be created and stored in the previously created pool, based on a Ubuntu noble (24.04) hosted cloud image + + + resource "libvirt_volume" "ubuntu-qcow2" { + + format = "qcow2" + +[...] + +# The plan summaries the action to be taken, which in this case is about creating resources + +Plan: 4 to add, 0 to change, 0 to destroy. +``` + +- The last command will carry out the plan + +``` +$ terraform apply + +[...] + +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 + +# The actions are carried out +libvirt_pool.ubuntu-bios: Creating... +libvirt_pool.ubuntu-bios: Creation complete after 0s + +[...] + +Apply complete! Resources: 4 added, 0 changed, 0 destroyed. +``` + +- Identify the created machine + +``` +$ sudo virsh list --all + + Id Name State +--------------------------------------------- + 10 ubuntu-cloud-server-2404-0 running +``` + +- Determine its IP address + +``` +$ sudo virsh domifaddr ubuntu-cloud-server-2404-0 +``` + +``` + Name MAC address Protocol Address +---------------------------------------------------------------- + vnet3 52:54:00:e2:51:c0 ipv4 192.168.122.24/24 +``` + +- Connect to the machine + +``` +$ ssh root@192.168.122.24 + +[...] + +# Use the password defined in the cloud-init.cfg file + +root@192.168.122.24's password: + +Welcome to Ubuntu 24.04.3 LTS (GNU/Linux 6.8.0-71-generic x86_64) +[...] + System information as of Tue Aug 26 10:40:49 UTC 2025 + + System load: 0.0 Processes: 113 + Usage of /: 67.4% of 2.35GB Users logged in: 0 + Memory usage: 5% IPv4 address for ens3: 192.168.122.24 + Swap usage: 0% +``` + +- Exit the virtual machine + +``` +root@ubuntu$ exit +``` + +- To destroy the virtual machine, execute the following command + +``` +$ terraform destroy + +[...] + +Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + - destroy + +Terraform will perform the following actions: + + # libvirt_cloudinit_disk.commoninit will be destroyed + - resource "libvirt_cloudinit_disk" "commoninit" { + +[...] + + # libvirt_domain.domain[0] will be destroyed + - resource "libvirt_domain" "domain" { + - arch = "x86_64" -> null + +[...] + + } + } + + # libvirt_pool.ubuntu2 will be destroyed + - resource "libvirt_pool" "ubuntu2" { + - allocation = 798310400 -> null + - available = 16019255296 -> null + +[...] + + } + } + + # libvirt_volume.ubuntu-qcow2 will be destroyed + - resource "libvirt_volume" "ubuntu-qcow2" { + +[...] + + } + +Plan: 0 to add, 0 to change, 4 to destroy. + +Do you really want to destroy all resources? + Terraform will destroy all your managed infrastructure, as shown above. + There is no undo. Only 'yes' will be accepted to confirm. + + Enter a value: yes + +libvirt_domain.domain[0]: Destroying... [id=611d5ede-e4b4-4ca5-ad83-83030942a6b5] +libvirt_domain.domain[0]: Destruction complete after 0s +libvirt_cloudinit_disk.commoninit: Destroying... [id=/tmp/cluster_storage2/commoninit.iso;5f4e08ef-ad51-484f-a9f2-c926f582974a] +libvirt_volume.ubuntu-qcow2: Destroying... [id=/tmp/cluster_storage2/ubuntu-qcow2] +libvirt_cloudinit_disk.commoninit: Destruction complete after 0s +libvirt_volume.ubuntu-qcow2: Destruction complete after 0s +libvirt_pool.ubuntu2: Destroying... [id=dbd62f8b-5d09-4e96-87e2-88e95c582896] +libvirt_pool.ubuntu2: Destruction complete after 0s + +Destroy complete! Resources: 4 destroyed. +``` + +## Explanations + +Let's take a look inside the *ubuntu-cloud-server-2404-bios* folder, which contains two files, *ubuntu-cloud-server-2404-bios.tf* and *cloud_init.cfg* + +The first file *ubuntu-cloud-server-2404-bios.tf* contains the main configuration for the Terraform deployment. + +- It starts by defining the required Terraform version and provider + +``` +terraform { + required_version = ">= 0.13" + required_providers { + libvirt = { + source = "dmacvicar/libvirt" + version = "0.8.3" + } + } +} +``` + +- The specific provider is defined here + +``` +provider "libvirt" { + uri = "qemu:///system" +} +``` + +> The [connection URI](https://libvirt.org/uri.html#qemu-qemu-and-kvm-uris) of the libvirt instance can be defined. One could for instance specific a libvirt instance that is hosted remotely + +- A libvirt pool, to store the virtual machine image, is created: + +``` +resource "libvirt_pool" "ubuntu-bios" { + name = "ubuntu-bios" + type = "dir" + target { + path = "/tmp/ubuntu-bios" + } +} +``` + +- The cloud-init user data will be fetched from a specific file whose path has to be declared: + +``` +data "template_file" "user_data" { + template = file("${path.module}/cloud_init.cfg") +} +``` + +- The ISO cloud-init disk will be created: + +``` +resource "libvirt_cloudinit_disk" "commoninit" { + name = "commoninit.iso" + user_data = data.template_file.user_data.rendered + pool = libvirt_pool.ubuntu-bios.name +} +``` + +- Perhaps the most important, the domain will be created: + +> Values can be adjusted, such as memory or vCPU counts. In the examples, multiple virtio-based device hardware are created, such as a virtio-gpu. + +``` +resource "libvirt_domain" "domain" { + count = 1 + name = "ubuntu-cloud-server-2404-${count.index}" + memory = "4092" + vcpu = 2 + cloudinit = libvirt_cloudinit_disk.commoninit.id + + cpu { + mode = "host-model" + } + + disk { + volume_id = libvirt_volume.ubuntu-qcow2.id + } + + console { + type = "pty" + target_port = "0" + target_type = "virtio" + } + + video { + type = "virtio" + } + + tpm { + backend_type = "emulator" + backend_version = "2.0" + } + + network_interface { + network_name = "default" + } + +} +``` + +## Resources + +- [Terraform provider domain documentation](https://github.com/dmacvicar/terraform-provider-libvirt/blob/master/website/docs/r/domain.html.markdown) \ No newline at end of file