Este tutorial fornece as etapas para criar uma infraestrutura de laboratório em KVM usando Terraform e preparar as VMs para serem gerenciadas via Ansible. As máquinas virtuais terão diferentes sistemas operacionais, incluindo distribuições Debian/Ubuntu e RHEL, e serão configuradas automaticamente usando Cloud-init.
Este arquivo contém a configuração principal para criar a infraestrutura KVM, definindo a rede, volumes e as VMs.
terraform {
required_providers {
libvirt = {
source = "dmacvicar/libvirt"
}
}
}
provider "libvirt" {
uri = "qemu:///system"
}
variable "vms" {
type = list(map(any))
}
resource "libvirt_network" "ansible" {
name = "ansible"
mode = "nat"
addresses = ["10.3.4.0/24"]
autostart = true
dhcp {
enabled = false
}
dns {
enabled = true
}
}
resource "libvirt_volume" "os_image" {
for_each = { for vm in var.vms : vm.name => vm }
name = each.value.os_image_name
pool = each.value.storage_pool
source = each.value.os_image_url
format = "qcow2"
}
resource "libvirt_volume" "os_datas" {
for_each = { for vm in var.vms : vm.name => vm }
name = each.value.os_datas_name
base_volume_id = libvirt_volume.os_image[each.key].id
pool = each.value.storage_pool
size = each.value.disksize * 1024 * 1024 * 1024 // GB para bytes
}
data "template_file" "user_data_deb" {
for_each = { for vm in var.vms : vm.name => vm if lookup(vm, "user_data_deb", null) != null }
template = file("${path.module}/${each.value.user_data_deb}")
vars = {
hostname = each.value.hostname
}
}
data "template_file" "user_data_rhel" {
for_each = { for vm in var.vms : vm.name => vm if lookup(vm, "user_data_rhel", null) != null }
template = file("${path.module}/${each.value.user_data_rhel}")
vars = {
hostname = each.value.hostname
}
}
data "template_file" "network_config_deb" {
for_each = { for vm in var.vms : vm.name => vm if lookup(vm, "network_config_deb", null) != null }
template = file("${path.module}/${each.value.network_config_deb}")
vars = {
network_ip = each.value.network_ip
}
}
data "template_file" "network_config_rhel" {
for_each = { for vm in var.vms : vm.name => vm if lookup(vm, "network_config_rhel", null) != null }
template = file("${path.module}/${each.value.network_config_rhel}")
vars = {
network_ip = each.value.network_ip
}
}
resource "libvirt_cloudinit_disk" "cloudinit_deb" {
for_each = { for vm in var.vms : vm.name => vm if lookup(vm, "user_data_deb", null) != null }
name = "${each.key}_cloudinit.iso"
user_data = data.template_file.user_data_deb[each.key].rendered
network_config = data.template_file.network_config_deb[each.key].rendered
pool = each.value.storage_pool
}
resource "libvirt_cloudinit_disk" "cloudinit_rhel" {
for_each = { for vm in var.vms : vm.name => vm if lookup(vm, "user_data_rhel", null) != null }
name = "${each.key}_cloudinit.iso"
user_data = data.template_file.user_data_rhel[each.key].rendered
network_config = data.template_file.network_config_rhel[each.key].rendered
pool = each.value.storage_pool
}
locals {
cloudinit_disks = {
for vm in var.vms : vm.name => (
lookup(vm, "user_data_deb", null) != null ?
libvirt_cloudinit_disk.cloudinit_deb[vm.name].id :
libvirt_cloudinit_disk.cloudinit_rhel[vm.name].id
)
}
}
resource "libvirt_domain" "domain" {
for_each = { for vm in var.vms : vm.name => vm }
name = each.value.name
memory = each.value.memory
vcpu = each.value.cpu
cpu {
mode = "host-passthrough"
}
cloudinit = local.cloudinit_disks[each.key]
network_interface {
network_name = each.value.network_name
}
disk {
volume_id = libvirt_volume.os_datas[each.key].id
}
console {
type = "pty"
target_type = "virtio"
target_port = "1"
}
graphics {
type = "spice"
listen_type = "address"
autoport = true
}
}
Configura as variáveis para definir as VMs no ambiente.
vms = [
{
name = "ansible"
cpu = 2
memory = 4096
disksize = 32
storage_pool = "default"
hostname = "ansible"
os_image_name = "ansible_image.qcow2"
os_datas_name = "ansible_datas.qcow2"
network_name = "ansible"
user_data_deb = "cloud-init-deb.yml"
network_config_deb = "network-config-deb.yml"
network_ip = "10.3.4.10"
os_image_url = "/home/gean/kvm/templates/ubuntu-22.04-server-cloudimg-amd64.img"
},
{
name = "balancer"
cpu = 2
memory = 2048
disksize = 64
storage_pool = "default"
hostname = "balancer"
os_image_name = "balancer_image.qcow2"
os_datas_name = "balancer_datas.qcow2"
network_name = "ansible"
user_data_rhel = "cloud-init-rhel.yml"
network_config_rhel = "network-config-rhel.yml"
network_ip = "10.3.4.11"
os_image_url = "/home/gean/kvm/templates/OL9U3_x86_64-kvm-b220.qcow2"
},
{
name = "webserver1"
cpu = 2
memory = 2048
disksize = 32
storage_pool = "default"
hostname = "webserver1"
os_image_name = "webserver1_image.qcow2"
os_datas_name = "webserver1_datas.qcow2"
network_name = "ansible"
user_data_deb = "cloud-init-deb.yml"
network_config_deb = "network-config-deb.yml"
network_ip = "10.3.4.12"
os_image_url = "/home/gean/kvm/templates/ubuntu-22.04-server-cloudimg-amd64.img"
},
{
name = "webserver2"
cpu = 2
memory = 2048
disksize = 64
storage_pool = "default"
hostname = "webserver2"
os_image_name = "webserver2_image.qcow2"
os_datas_name = "webserver2_datas.qcow2"
network_name = "ansible"
user_data_rhel = "cloud-init-rhel.yml"
network_config_rhel = "network-config-rhel.yml"
network_ip = "10.3.4.13"
os_image_url = "/home/gean/kvm/templates/OL9U3_x86_64-kvm-b220.qcow2"
},
{
name = "dbserver"
cpu = 2
memory = 2048
disksize = 32
storage_pool = "default"
hostname = "dbserver"
os_image_name = "dbserver_image.qcow2"
os_datas_name = "dbserver_datas.qcow2"
network_name = "ansible"
user_data_deb = "cloud-init-deb.yml"
network_config_deb = "network-config-deb.yml"
network_ip = "10.3.4.14"
os_image_url = "/home/gean/kvm/templates/debian-12-generic-amd64.qcow2"
}
]
Configuração de inicialização para as VMs baseadas em Debian/Ubuntu.
#cloud-config hostname: ${hostname} ssh_pwauth: yes users: - name: gean sudo: ALL=(ALL) NOPASSWD:ALL groups: users, sudo shell: /bin/bash lock_passwd: false passwd: $6$uGQol.HnKU0nvpEy$YJl94Y7/p1cWZVlu0gsZIeebssh4oHCIQ9VNX721T1/Lx0UbQVbjfbzS2.9.2EGz4Hdxi0ICNKAua8lo/AsuT1 chpasswd: list: | root:root expire: False packages: - qemu-guest-agent - bash-completion package_update: true package_upgrade: true
Configuração de inicialização para as VMs baseadas em RHEL.
#cloud-config ssh_pwauth: yes users: - name: gean sudo: ALL=(ALL) NOPASSWD:ALL groups: users, whell shell: /bin/bash lock_passwd: false passwd: $6$uGQol.HnKU0nvpEy$YJl94Y7/p1cWZVlu0gsZIeebssh4oHCIQ9VNX721T1/Lx0UbQVbjfbzS2.9.2EGz4Hdxi0ICNKAua8lo/AsuT1 chpasswd: list: | root:root expire: False packages: - qemu-guest-agent - bash-completion package_update: true package_upgrade: true runcmd: - systemctl enable qemu-guest-agent - systemctl start qemu-guest-agent - hostnamectl set-hostname ${hostname}
Configuração de rede para VMs baseadas em Debian/Ubuntu.
#cloud-config network: version: 2 ethernets: ens3: addresses: - ${network_ip}/24 nameservers: addresses: - 10.3.4.1 routes: - to: default via: 10.3.4.1
Configuração de rede para VMs baseadas em RHEL.
#cloud-config network: version: 1 config: - type: physical name: eth0 subnets: - type: static address: ${network_ip}/24 gateway: 10.3.4.1
terraform init
terraform fmt
terraform validate
terraform plan
terraform apply
4. O Terraform criará as VMs com base na configuração e aplicará as configurações de rede e de sistema.