Table of Contents
Criação de uma Máquina Virtual em Ambiente de Virtualização KVM com Terraform
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.
Pré-requisitos
Antes de começar, certifique-se de que:
- KVM está instalado e configurado no seu sistema.
- Terraform está instalado na máquina.
- O provider libvirt do Terraform está disponível.
1. Definir Variáveis e Configuração do Terraform
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.
2. Criar os Volumes da VM
# 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.
3. Definir o Disco cloud-init
# 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.
4. Configurar o Domínio (VM)
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.
5. Variáveis de Configuração
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.
6. Arquivo cloud-init
Crie um arquivo cloud-init.yml para automatizar a configuração da VM:
Definição para acesso ssh por senha
- cloud-init.yml
#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.
Configuração para acesso por ssh senha senha
- main.tf
# 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] }
- cloud-init.yml
# 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!"
- terraform.tfvars
$ 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..." }
7. Gerar Senha e Chave SSH
- Para gerar a senha root:
mkpasswd --method=SHA-512
- Para gerar a chave SSH:
ssh-keygen -t ed25519 -C "your_email@example.com" -f ~/.ssh/tfvms
8. Construção da Infraestrutura
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
9. Outras Opções
- Aplicar com parâmetros personalizados:
terraform apply -var="vm_name=custom_name" -var="vm_memory=4096"
- Aplicar com um arquivo de variáveis:
terraform apply -var-file="custom_variables.tfvars"
Conclusão
Este tutorial fornece um processo completo para criar uma VM no KVM usando Terraform, com foco em automação e personalização.
