Terraform module for KVM/Libvirt Virtual Machine. This module will create a KVM Virtual Machine(s), configure it using Cloud Init and test the ssh connection. This module is using dmacvicar/libvirt Terraform provider.
- creates one or more VMs
- one NIC per domain, connected to the network using the bridge interface
- setup network interface using DHCP or static configuration
- cloud_init VM(s) configuration (Ubuntu+Netplan complient)
- optionally add multiple extra disks
- test the ssh connection
- Ubuntu 20.04 TLS Cloud Image
- Ubuntu 22.04 TLS Cloud Image
Name | Version |
---|---|
terraform | >= 1.0 |
libvirt | >= 0.7.0 |
No modules.
Name | Type |
---|---|
libvirt_cloudinit_disk.commoninit | resource |
libvirt_domain.virt-machine | resource |
libvirt_volume.base-volume-qcow2 | resource |
libvirt_volume.volume-qcow2 | resource |
Name | Description | Type | Default | Required |
---|---|---|---|---|
additional_disk_ids | List of volume ids | list(string) |
[] |
no |
autostart | Autostart the domain | bool |
true |
no |
base_pool_name | Name of base OS image | string |
null |
no |
base_volume_name | Name of base OS image | string |
null |
no |
bridge | Bridge interface | string |
"virbr0" |
no |
cpu_mode | CPU mode | string |
"host-passthrough" |
no |
dhcp | Use DHCP or Static IP settings | bool |
false |
no |
graphics | Graphics type (can be 'spice ' or 'vnc ') |
string |
spice |
no |
index_start | From where the indexig start | number |
1 |
no |
ip_address | List of IP addresses | list(string) |
[ |
no |
ip_gateway | IP addresses of a gateway | string |
"192.168.123.1" |
no |
ip_nameserver | IP addresses of a nameserver | string |
"192.168.123.1" |
no |
local_admin | Admin user without ssh access | string |
"" |
no |
local_admin_passwd | Local admin user password | string |
"password_example" |
no |
memory | RAM in MB | string |
"1024" |
no |
os_img_url | URL to the OS image | string |
"https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img" |
no |
pool | Storage pool name | string |
"default" |
no |
runcmd | Extra commands to be run with cloud init | list(string) |
[ |
no |
share_filesystem | n/a | object({ |
{ |
no |
ssh_admin | Admin user with ssh access | string |
"ssh-admin" |
no |
ssh_keys | List of public ssh keys | list(string) |
[] |
no |
ssh_private_key | Private key for SSH connection test (either path to file or key content) | string |
null |
no |
system_volume | System Volume size (GB) | number |
10 |
no |
time_zone | Time Zone | string |
"UTC" |
no |
vcpu | Number of vCPUs | number |
1 |
no |
vm_count | Number of VMs | number |
1 |
no |
vm_hostname_prefix | VM hostname prefix | string |
"vm" |
no |
xml_override | With these variables you can: Enable hugepages; Set USB controllers; Attach USB devices | object({ |
{ |
no |
bastion_host | ssh bastion host | string |
null |
no |
bastion_user | ssh user on bastion host | string |
null |
no |
bastion_ssh_private_key | ssh private key for bastion host (either path to file or key content) | string |
null |
no |
Name | Description |
---|---|
ip_address | n/a |
name | n/a |
Example with enable HugePages, Attached USB device, changed USB controller model... :
terraform {
required_version = ">= 0.13"
required_providers {
libvirt = {
source = "dmacvicar/libvirt"
}
}
}
resource "tls_private_key" "ecdsa-p384-bastion" {
algorithm = "ECDSA"
ecdsa_curve = "P384"
}
provider "libvirt" {
uri = "qemu+ssh://hero@192.168.165.100/system"
}
module "vm" {
source = "MonolithProjects/vm/libvirt"
version = "1.8.0"
vm_hostname_prefix = "server"
vm_count = 3
memory = "2048"
vcpu = 1
pool = "terra_pool"
system_volume = 20
dhcp = true
local_admin = "local-admin"
ssh_admin = "ci-user"
ssh_private_key = "~/.ssh/id_ed25519"
local_admin_passwd = "$6$rounds=4096$xxxxxxxxHASHEDxxxPASSWORD"
ssh_keys = [
"ssh-ed25519 AAAAxxxxxxxxxxxxSSHxxxKEY example",
]
bastion_host = "10.0.0.1"
bastion_user = "admin"
bastion_ssh_private_key = tls_private_key.ecdsa-p384-bastion.private_key_pem
time_zone = "CET"
os_img_url = "file:///home/myuser/ubuntu-20.04-server-cloudimg-amd64.img"
xml_override = {
hugepages = true,
usb_controllers = [
{
model = "qemu-xhci"
}
],
usb_devices = [
{
vendor = "0x0bc2",
product = "0xab28"
}
]
pci_devices_passthrough = [
{
src_domain = "0x0000",
src_bus = "0xc1",
src_slot = "0x00",
src_func = "0x0",
dst_domain = "0x0000",
dst_bus = "0x00",
dst_slot = "0x08"
dst_func = "0x0"
},
{
src_domain = "0x0000",
src_bus = "0xc1",
src_slot = "0x00",
src_func = "0x1",
dst_domain = "0x0000",
dst_bus = "0x00",
dst_slot = "0x09"
dst_func = "0x0"
}
]
}
}
output "ip_addresses" {
value = module.nodes
}
Static IP settings... :
terraform {
required_version = ">= 0.13"
required_providers {
libvirt = {
source = "dmacvicar/libvirt"
version = "0.6.3"
}
}
}
provider "libvirt" {
uri = "qemu+ssh://hero@192.168.165.100/system"
}
module "vm" {
source = "MonolithProjects/vm/libvirt"
version = "1.8.0"
vm_hostname_prefix = "server"
vm_count = 3
memory = "2048"
vcpu = 1
pool = "terra_pool"
system_volume = 20
share_filesystem = {
source = "/tmp"
target = "tmp"
readonly = false
}
dhcp = false
ip_address = [
"192.168.165.151",
"192.168.165.152",
"192.168.165.153"
]
ip_gateway = "192.168.165.254"
ip_nameserver = "192.168.165.104"
local_admin = "local-admin"
ssh_admin = "ci-user"
ssh_private_key = "~/.ssh/id_ed25519"
local_admin_passwd = "$6$rounds=4096$xxxxxxxxHASHEDxxxPASSWORD"
ssh_keys = [
"ssh-ed25519 AAAAxxxxxxxxxxxxSSHxxxKEY example",
]
time_zone = "CET"
os_img_url = "file:///home/myuser/ubuntu-20.04-server-cloudimg-amd64.img"
}
output "outputs" {
value = module.nodes
}
The shared directory from the example can be mounted inside the VM with command
sudo mount -t 9p -o trans=virtio,version=9p2000.L,rw tmp /host/tmp
Create a VM with an extra disk
# Creates a 50GB extra-data-disk within vms pool
resource "libvirt_volume" "data_volume" {
pool = "vms"
name = "extra-data-disk.qcow2"
format = "qcow2"
size = 1024*1024*1024*50
}
module "vm" {
source = "MonolithProjects/vm/libvirt"
version = "1.8.0"
vm_hostname_prefix = "data-server"
base_volume_name = "debian-11-base.qcow2"
base_pool_name = "linked-images"
vm_count = 1
bridge = "bridge-dmz"
memory = "4096"
vcpu = 4
pool = "vms"
system_volume = 25
additional_disk_ids = [ libvirt_volume.data_volume.id ]
dhcp = true
ssh_admin = "admin"
ssh_keys = [
chomp(file("~/.ssh/id_rsa.pub"))
]
time_zone = "America/Argentina/Buenos_Aires"
}
output "ip_addresses" {
value = module.vm
}
output_data = {
"ip_address" = [
"192.168.165.151",
"192.168.165.152",
"192.168.165.153",
]
"name" = [
"server01",
"server02",
"server03",
]
}
MIT
Created in 2020 by Michal Muransky