328 lines
8.0 KiB
Markdown
328 lines
8.0 KiB
Markdown
# Modern libvirt-driven Terraform examples
|
|
|
|
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) |