Terraform is a well-known open-source infrastructure as code (IaC) tool developed by HashiCorp. It allows users to define and provision infrastructure using a declarative configuration language. In homelab environment, it can also interacts with Linux libvirt
hypervisor with the help of a third-party provider. This greatly simplifies the homelab VM management with a unified IaC language that can also be used to provision resources on public cloud like AWS, Azure and GCP. In this post, I will briefly introduce how to install libvirt
on major Linux distros, and how to use terraform to interact with libvirt
to create/provision VMs.
Install libvirt
For Ubuntu,
sudo apt install qemu-kvm libvirt-daemon-system genisoimage
sudo apt install virt-manager
For CentOS like,
sudo yum module install virt
sudo yum install virt-install virt-viewer
sudo systemctl start libvirtd
After installation, virt-host-validate
helps to verify the system is prepared to be a virtualization host.
To manage virtual machines without sudo
, make sure the user is added to the group libvirt
.
sudo adduser $USER libvirt
virsh
is the command line utility to manage VMs. Common use cases include:
- List running VMs:
virsh list
- Start, shutdown, reboot VMs
- Delete VM:
virsh undefine <VM name>
In my use cases, virsh
is used mainly to monitor the VMs. In most situations I prefer to provision VMs with Terraform.
Terraform
To install terraform, simply download the binary (https://developer.hashicorp.com/terraform/install) and place the executable at a location available on your $PATH
. The official website also have a list of tutorials to cover the basics of terraform.
For libvirt
provider, a template configuration file I used to create VMs is shown below.
terraform {
required_providers {
libvirt = {
source = "dmacvicar/libvirt"
}
}
}
provider "libvirt" {
uri = "qemu:///system"
}
locals {
vm_name = "dev1"
ip_addr = "192.168.122.71"
}
resource "libvirt_pool" "server_pool" {
name = "pool-${local.vm_name}"
type = "dir"
path = "/home/yeguang/libvirt_pool/pool-${local.vm_name}"
}
resource "libvirt_volume" "ubuntu_base" {
name = "ubuntu.qcow2"
pool = libvirt_pool.server_pool.name
source = "${path.module}/jammy-server-cloudimg-amd64.img"
format = "qcow2"
}
resource "libvirt_volume" "server_disk" {
name = "disk.qcow2"
size = 10740000000
pool = libvirt_pool.server_pool.name
base_volume_id = libvirt_volume.ubuntu_base.id
}
resource "libvirt_cloudinit_disk" "commoninit" {
name = "commoninit.iso"
user_data = templatefile("${path.module}/config/cloud_init.cfg", { hostname = local.vm_name })
network_config = templatefile("${path.module}/config/network_config.cfg", { ip_addr = local.ip_addr })
pool = libvirt_pool.server_pool.name
}
resource "libvirt_domain" "vm" {
name = local.vm_name
memory = "8192"
vcpu = 4
cloudinit = libvirt_cloudinit_disk.commoninit.id
cpu {
mode = "host-passthrough"
}
disk {
volume_id = libvirt_volume.server_disk.id
scsi = "true"
}
network_interface {
bridge = "virbr0"
}
console {
type = "pty"
target_type = "serial"
target_port = "0"
}
}
cloud_init.cfg
is used to initialize users, groups, and ssh_authorized_keys. Some examples can be found here: https://cloudinit.readthedocs.io/en/latest/reference/examples.html
network_config.cfg
is used to initialize network interfaces. The template I use is the following:
version: 2
ethernets:
eth:
match:
name: en*
dhcp4: no
optional: true
addresses: [${ip_addr}/24]
gateway4: 192.168.122.1
nameservers:
addresses: [192.168.122.1]
Note in terraform I used templatefile
function to reuse the same network_config.cfg
when provisioning multiple VMs.
After cd
into the folder, terraform init
will install the required provider plugin dmacvicar/libvirt
. To apply the config and create VM, first preview the changes with terraform plan
. Once OK with the changes, simply apply the config:
terraform apply
To destroy all the resources, just use terraform destroy
.
References
- https://ubuntu.com/server/docs/virtualization-libvirt
- https://developer.hashicorp.com/terraform/tutorials
- https://registry.terraform.io/providers/dmacvicar/libvirt/latest/docs
- https://github.com/dmacvicar/terraform-provider-libvirt/issues/546
License
