Este tutorial demonstra como criar uma máquina virtual (VM) utilizando KVM e Terraform, assumindo que o Terraform, KVM e o provider libvirt já estão instalados.
Antes de começar, certifique-se de que:
Crie um arquivo main.tf com o seguinte conteúdo:
# Definindo variáveis para configuração da VM
variable "vm_template" {
type = map(any)
}
# # Define os provedores necessários para o Terraform.
terraform {
required_providers {
libvirt = {
source = "dmacvicar/libvirt"
}
}
}
# Configura o provedor libvirt com a URI do sistema QEMU.
provider "libvirt" {
uri = "qemu:///system"
}
Aqui, o provider libvirt será usado para gerenciar a VM via KVM.
# Volume de imagem do sistema operacional
resource "libvirt_volume" "os_image" {
name = var.vm_template["os_image_name"]
pool = var.vm_template["storage_pool"]
source = var.vm_template["os_image_url"]
format = "qcow2"
}
# Volume de dados da VM
resource "libvirt_volume" "os_datas" {
name = var.vm_template["os_volume_name"]
base_volume_id = libvirt_volume.os_image.id
pool = var.vm_template["storage_pool"]
size = var.vm_template["disksize"] * 1024 * 1024 * 1024 # Converte para bytes
}
Esse trecho define os volumes usados pela VM, especificando a imagem do SO e o volume de dados.
# Definir o arquivo cloud-init para automação
data "template_file" "user_data" {
template = file("${path.module}/${var.vm_template["cloud_init_file"]}")
}
resource "libvirt_cloudinit_disk" "cloudinit" {
name = "cloudinit.iso"
user_data = data.template_file.user_data.rendered
pool = var.vm_template["storage_pool"]
}
O cloud-init permite automatizar a configuração inicial da VM, como a criação de usuários e a instalação de pacotes.
resource "libvirt_domain" "domain" {
name = var.vm_template["name"]
memory = var.vm_template["memory"]
vcpu = var.vm_template["cpu"]
cpu {
mode = "host-passthrough"
}
cloudinit = libvirt_cloudinit_disk.cloudinit.id
network_interface {
network_name = var.vm_template["network_name"]
wait_for_lease = true
}
console {
type = "pty"
target_type = "virtio"
target_port = "1"
}
disk {
volume_id = libvirt_volume.os_datas.id
}
graphics {
type = "spice"
listen_type = "address"
autoport = true
}
}
output "ip" {
value = libvirt_domain.domain.network_interface[0].addresses[0]
}
Este trecho define a configuração principal da VM, incluindo CPU, memória, rede e interface gráfica.
Crie um arquivo `variables.tf` ou defina diretamente no `main.tf`:
vm_template = {
name = "tf-vm-01"
cpu = 2
memory = 2048
disksize = 32
storage_pool = "default"
os_image_name = "tf_vm_01_image.qcow2"
os_volume_name = "tf_vm_01_volume.qcow2"
network_name = "default"
cloud_init_file = "cloud-init.yml"
os_image_url = "/home/user/kvm/templates/debian-12-generic-amd64.qcow2"
}
Altere os valores conforme necessário para a sua infraestrutura.
Crie um arquivo cloud-init.yml para automatizar a configuração da VM:
Definição para acesso ssh por senha
#cloud-config hostname: vm-tf ssh_pwauth: yes # Habilita login por senha para usuários users: - name: gean sudo: ALL=(ALL) NOPASSWD:ALL # Permite 'gean' usar sudo sem senha groups: users, sudo shell: /bin/bash lock_passwd: false # Desbloqueia o usuário 'gean' para usar senhas passwd: $6$uGQol.HnKU0nvpEy$YJl94Y7/p1cWZVlu0gsZIeebssh4oHCIQ9VNX721T1/Lx0UbQVbjfbzS2.9.2EGz4Hdxi0ICNKAua8lo/AsuT1 # Senha criptografada de 'gean' chpasswd: list: | root:$6$uGQol.HnKU0nvpEy$YJl94Y7/p1cWZVlu0gsZIeebssh4oHCIQ9VNX721T1/Lx0UbQVbjfbzS2.9.2EGz4Hdxi0ICNKAua8lo/AsuT1 # Senha criptografada de root expire: False # Define que as senhas não expiram packages: - qemu-guest-agent # Instala o agente QEMU para máquinas virtuais - bash-completion # Completa comandos no Bash package_update: true # Atualiza lista de pacotes package_upgrade: true # Atualiza os pacotes instalados # Definir a localidade e fuso horário (opcional) locale: pt_BR.UTF-8 timezone: America/Sao_Paulo
Esse arquivo define o hostname, usuários, senha root, e instala pacotes.
# vim main.tf
# Definindo variáveis para configuração da VM
variable "vm_template" {
type = map(any)
}
terraform {
required_providers {
libvirt = {
source = "dmacvicar/libvirt"
}
}
}
provider "libvirt" {
uri = "qemu:///system"
}
# Volume de imagem do sistema operacional
resource "libvirt_volume" "os_image" {
name = var.vm_template["os_image_name"]
pool = var.vm_template["storage_pool"]
source = var.vm_template["os_image_url"]
format = "qcow2"
}
# Volume de dados da VM
resource "libvirt_volume" "os_datas" {
name = var.vm_template["os_volume_name"]
base_volume_id = libvirt_volume.os_image.id
pool = var.vm_template["storage_pool"]
size = var.vm_template["disksize"] * 1024 * 1024 * 1024 # Converte para bytes
}
# Definir o arquivo cloud-init para automação
data "template_file" "user_data" {
template = file("${path.module}/${var.vm_template["cloud_init_file"]}")
vars = {
hostname = var.vm_template["hostname"]
ssh_key = var.vm_template["ssh_key"]
}
}
# Criando disco Cloud-Init
resource "libvirt_cloudinit_disk" "cloudinit" {
name = "cloudinit.iso"
user_data = data.template_file.user_data.rendered
pool = var.vm_template["storage_pool"]
}
# Criando a VM com libvirt
resource "libvirt_domain" "domain" {
name = var.vm_template["name"]
memory = var.vm_template["memory"]
vcpu = var.vm_template["cpu"]
cpu {
mode = "host-passthrough"
}
cloudinit = libvirt_cloudinit_disk.cloudinit.id
network_interface {
network_name = var.vm_template["network_name"]
wait_for_lease = true
}
console {
type = "pty"
target_type = "virtio"
target_port = "1"
}
disk {
volume_id = libvirt_volume.os_datas.id
}
graphics {
type = "spice"
listen_type = "address"
autoport = true
}
}
output "ip" {
value = libvirt_domain.domain.network_interface[0].addresses[0]
}
# vim cloud-init.yml #cloud-config # Configuração do Hostname hostname: ${hostname} # Criação de usuário users: - name: gean sudo: ALL=(ALL) NOPASSWD:ALL groups: users, sudo shell: /bin/bash ssh-authorized-keys: - ${ssh_key} # Definir senha root chpasswd: list: | root:$6$R4tXC5apTx$f4WVAylB/SZ/0ppE7Zp4lurvzAhcm.BaU3xJKaoESu7cv13sR7RYVkjVQwxtvA9/vUggWu/a9N0L9EP1lg/Ez1 expire: False # Pacotes a serem instalados packages: - qemu-guest-agent - bash-completion # Atualização do sistema package_update: true package_upgrade: true # Localidade e fuso horário locale: pt_BR.UTF-8 timezone: America/Sao_Paulo # Logs de inicialização para depuração final_message: "A VM foi provisionada corretamente!"
$ cat terraform.tfvars
vm_template = {
name = "tf-vm-01"
cpu = 2
memory = 2048
disksize = 32
storage_pool = "default"
hostname = "tf-vm-01"
os_image_name = "tf_vm_01_image.qcow2"
os_volume_name = "tf_vm_01_volume.qcow2"
network_name = "default"
cloud_init_file = "cloud-init.yml"
os_image_url = "/home/gean/kvm/templates/ubuntu-22.04-server-cloudimg-amd64.img"
ssh_key = "ssh-ed25519 AAAA..."
}
mkpasswd --method=SHA-512
ssh-keygen -t ed25519 -C "your_email@example.com" -f ~/.ssh/tfvms
Execute os comandos Terraform:
terraform init # Inicializar o Terraform terraform fmt # Formatar arquivos terraform validate # Validar a configuração terraform plan # Planejar a infraestrutura terraform apply # Aplicar a infraestrutura
terraform apply -var="vm_name=custom_name" -var="vm_memory=4096"
terraform apply -var-file="custom_variables.tfvars"
Este tutorial fornece um processo completo para criar uma VM no KVM usando Terraform, com foco em automação e personalização.