Terraform is a great tool to build infrastructures. You will see many tutorials on how to use it with AWS, Azure or GCP. But you can do more.
I use it to quickly create KVM virtual machines for ansible roles testing, and fun ! Thanks to the Terraform libvirt provider
I will explain here how to create a sandbox of three machines. I used it to develop my etcd ansible role.
Setup
Terraform installation
As a Debian user, I installed terraform with apt: https://www.terraform.io/docs/cli/install/apt.html
genisoimage
The libvirt provider needs mkisofs, you will find it in the genisoimage
package.
sudo apt install genisoimage
KVM installation
The easy way is to install virt-manager
:
sudo apt install virt-manager
Add yourself in the libvirt group:
sudo adduser your-user libvirt
Then log-out / log-in to this take effect, or reboot your PC.
Enable KSM (optional)
According to Wikipedia:
In computing, kernel same-page merging (KSM), also known as kernel shared memory, memory merging, memory deduplication, and page deduplication is a kernel feature that makes it possible for a hypervisor system to share memory pages that have identical contents between multiple processes and/or virtualized guests. While not directly linked, Kernel-based Virtual Machine (KVM) can use KSM to merge memory pages occupied by virtual machines.
In short, you will save RAM. And with only 8GB on my Laptop PC, saving RAM is appreciated.
To setup KSM on Debian systems:
sudo apt install ksmtuned
To check if KSM is efficient:
watch "grep -H '' /sys/kernel/mm/ksm/pages_*"
With no virtual machines, all values are set to zero:
/sys/kernel/mm/ksm/pages_shared:0
/sys/kernel/mm/ksm/pages_sharing:0
/sys/kernel/mm/ksm/pages_to_scan:300
/sys/kernel/mm/ksm/pages_unshared:0
/sys/kernel/mm/ksm/pages_volatile:0
Once your 3 virtual machines will be up and running, you will see something like this with non-zero values:
/sys/kernel/mm/ksm/pages_shared:12093
/sys/kernel/mm/ksm/pages_sharing:65774
/sys/kernel/mm/ksm/pages_to_scan:300
/sys/kernel/mm/ksm/pages_unshared:101163
/sys/kernel/mm/ksm/pages_volatile:379066
It means KSM RAM deduplication is active \0/
Using Terraform to create/destroy your KVM machines
I put needed files in this git repository: https://gitlab.com/AnatomicJC/terraform-libvirt
Terraform configuration files
Terraform uses tf files to describe your infrastructure. Each file with the tf extension are read and applied.
In my git repository, there is 3 tf files:
provider.tf
This file contains the terraform-libvirt-provider configuration.
cloud_init.tf
According to this Terraform page:
When you create a generic compute resource in Terraform, your virtual machine (VM) may not have much capability because it is a “fresh” install and needs to be provisioned with the software you want to use. Manually installing the necessary software and its respective dependencies on each VM is time consuming and difficult to maintain at scale.
cloud-init is a standard configuration support tool available on most Linux distributions and all major cloud providers. cloud-init allows you to pass a shell script to your instance that installs or configures the machine to your specifications.
cloud_init.tf is the Terraform configuration file, and cloud_init.cfg the Cloud-init configuration file. In this file, I setup a jc user with its ssh key, and install some package.
Thanks to cloud-init, my 3 VM will have the same setup, and I will be able to connect to them.
If you want to dig into cloud-init configuration file, have a look here: https://cloudinit.readthedocs.io/en/latest/topics/examples.html
libvirt.tf
This file contains your VM specification: CPU, RAM, etc.
As I want to create the 3 same virtual machines, there is a count = "3"
who will be used as for the machine name:
name = "test-vm-ubuntu-${count.index + 1}"
Or to set the machine IP address:
addresses = ["172.16.0.${count.index + 11}" ]
Another important configuration is the source image in the libvirt_volume resource.
You can set an online image who will be downloaded each time you will setup your virtual machine (it can be a bit long).
But if, like me, you are using terraform to often create/destroy machines, you can download the img file on a download
folder and set it as source:
resource "libvirt_volume" "image-qcow2" {
name = "ubuntu-amd64-${count.index + 1}.qcow2"
count = "3"
pool = libvirt_pool.ubuntu.name
source ="${path.module}/downloads/bionic-server-cloudimg-amd64.img"
#source = "https://cloud-images.ubuntu.com/releases/focal/release/ubuntu-20.04-server-cloudimg-amd64-disk-kvm.img"
format = "qcow2"
}
You can find Ubuntu cloud images here and Debian cloud images here. For others distros, Google and your brain are yours friends.
Let’s create your VMs
Initialize your terraform project by downloading the libvirt provider and dependencies:
terraform init
You can know create your 3 virtual machines:
terraform apply -auto-approve
Or destroy them:
terraform destroy -auto-approve
The cloud image is first loaded, then the cloud-init script will install packages and create your user with its ssh key. Once it is done, you can connect to your VM with ssh [email protected]
If you got appArmor errors, you must set
security_driver = "none"
in/etc/libvirt/qemu.conf
and restart the libvirt daemon.
Please enjoy !
Resources: