Provisionamento de uma Máquina Virtual (VM) no KVM utilizando Terraform
Introdução: Automatizando a Infraestrutura com KVM e Terraform
No cenário tecnológico atual, a automação de infraestrutura tornou-se um pilar fundamental para a eficiência, escalabilidade e reprodutibilidade. Ferramentas como o Terraform, da HashiCorp, revolucionaram a forma como gerenciamos recursos de infraestrutura, permitindo a definição, provisionamento e gerenciamento de infraestrutura como código (IaC). Quando combinado com tecnologias de virtualização robustas como o KVM (Kernel-based Virtual Machine), o Terraform oferece uma solução poderosa e flexível para automatizar a criação e configuração de máquinas virtuais em ambientes Linux.
A combinação KVM e Terraform destaca-se pela leveza do KVM em comparação com outras soluções de virtualização, o que resulta em melhor desempenho e menor sobrecarga de recursos. Além disso, a flexibilidade do Terraform permite gerenciar não apenas o KVM, mas também diversos outros provedores de infraestrutura, tornando-o uma ferramenta versátil para qualquer ambiente. Este tutorial detalhado tem como objetivo guiar você através do processo de provisionamento de uma Máquina Virtual (VM) no ambiente KVM utilizando o Terraform. Abordaremos desde a configuração dos pré-requisitos até a implantação e acesso à VM, fornecendo um guia prático e abrangente para quem busca otimizar seus fluxos de trabalho de virtualização. Ao final deste guia, você terá uma compreensão clara de como alavancar o poder do Terraform para gerenciar suas VMs KVM de forma eficiente e repetível, transformando o gerenciamento de infraestrutura em um processo automatizado e rastreável.
Pré-requisitos
Para seguir este tutorial e provisionar suas VMs com sucesso, certifique-se de que os seguintes pré-requisitos estejam instalados e configurados em seu ambiente:
- KVM (Kernel-based Virtual Machine): O KVM é a tecnologia de virtualização de código aberto que utilizaremos. Para garantir que seu ambiente KVM esteja pronto e funcionando corretamente, consulte nosso guia detalhado sobre Configurando o KVM no Ubuntu para obter instruções passo a passo.
- Terraform: O Terraform será a ferramenta principal para a automação da sua infraestrutura. Se você ainda não o tem instalado, siga as instruções em Instalando e Configurando o Terraform para configurar o ambiente necessário.
Estrutura do Projeto
Para manter seu projeto organizado e facilitar a gestão dos recursos de infraestrutura como código, recomendamos a seguinte estrutura de diretórios e arquivos. Esta organização padronizada melhora a legibilidade, a manutenção e a colaboração em projetos Terraform:
1
2
3
4
5
6
7
8
9
10
11
12
13
.
├── .gitignore # Regras para ignorar arquivos sensíveis e temporários, garantindo que credenciais e estados do Terraform não sejam versionados.
├── cloudinit.tf # Configuração do Cloud-Init para personalização da VM, incluindo a criação de usuários, instalação de pacotes e execução de scripts de inicialização na primeira inicialização da máquina.
├── domain.tf # Definição principal da máquina virtual KVM, onde são especificados recursos como CPU, memória, rede e o disco de boot, detalhando as características da VM.
├── output.tf # Define quais informações importantes (como o endereço IP da VM) serão exibidas após a aplicação do Terraform, facilitando o acesso e a integração com outros sistemas ou scripts.
├── provider.tf # Configuração do provedor Libvirt para Terraform, estabelecendo a conexão com o hypervisor KVM e permitindo que o Terraform interaja com a API do Libvirt.
├── README.md # Descrição do projeto para versionamento, contendo informações essenciais sobre o propósito do projeto, como configurá-lo e utilizá-lo.
├── terraform.tfvars # Arquivo real de variáveis sensíveis (NÃO versionado), contendo valores específicos para as variáveis definidas em `variables.tf` que não devem ser expostos publicamente.
├── terraform.tfvars.example # Modelo de variáveis sensíveis (exemplo), fornecendo um template para o `terraform.tfvars` sem expor dados reais.
├── user_data.yml # Template do Cloud-Init para configuração inicial da VM, escrito em sintaxe YAML e contendo as instruções para personalização da VM.
├── variables.tf # Definição das variáveis de entrada do projeto, permitindo a reutilização do código Terraform com diferentes valores para cada VM ou ambiente.
├── versions.tf # Define as versões usadas no projeto, garantindo a compatibilidade entre o Terraform Core e os provedores utilizados, o que é crucial para a reprodutibilidade.
└── volumes.tf # Definição dos volumes de disco da VM, incluindo a imagem base do sistema operacional que será utilizada para criar o disco da nova VM.
1. Configuração dos Arquivos Terraform
Nesta seção, detalharemos a configuração de cada arquivo Terraform, explicando seu propósito e a lógica por trás de cada bloco de código. Compreender a função de cada um é fundamental para gerenciar sua infraestrutura de forma eficaz.
1.1. cloudinit.tf
O Cloud-Init é uma ferramenta padrão da indústria para personalização de VMs na primeira inicialização, permitindo a injeção de configurações como usuários, chaves SSH e scripts. Este recurso Terraform cria um disco de Cloud-Init que será anexado à sua VM, fornecendo as instruções de configuração inicial.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
resource "libvirt_cloudinit_disk" "cloudinit" {
name = "cloudinit-${var.vm_name}.iso"
pool = "default"
user_data = templatefile(var.user_data, {
hostname = var.vm_name
user_name = var.user_name
gecos = var.gecos
groups = var.groups
ssh_key = var.ssh_public_key
})
lifecycle {
precondition {
condition = fileexists(var.user_data)
error_message = "Arquivo user_data \'${var.user_data}\' não encontrado"
}
}
}
1.2. domain.tf
Este arquivo define a máquina virtual KVM em si, especificando seus recursos e como ela se integra com outros componentes. O bloco cpu { mode = "host-passthrough" }
é importante para o desempenho e compatibilidade, pois permite que a VM utilize as mesmas características de CPU do host físico, otimizando a performance.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
resource "libvirt_domain" "domain" {
name = var.vm_name
memory = var.memory_mb
vcpu = var.vcpu_count
cpu {
mode = "host-passthrough"
}
cloudinit = libvirt_cloudinit_disk.cloudinit.id
network_interface {
network_name = var.network_name
wait_for_lease = true
}
disk {
volume_id = libvirt_volume.os_image.id
}
console {
type = "pty"
target_port = "0"
target_type = "virtio"
}
}
1.3. output.tf
O arquivo output.tf
é utilizado para expor informações importantes sobre a infraestrutura provisionada. O uso da função try
neste contexto é particularmente útil para lidar com casos onde o IP da VM ainda não foi alocado, tornando o output mais robusto e evitando erros.
1
2
3
4
5
6
output "vm_ip" {
value = try(
libvirt_domain.domain.network_interface[0].addresses[0],
"Nenhum IP alocado"
)
}
1.4. provider.tf
O provedor Libvirt atua como uma interface entre o Terraform e o KVM, permitindo que o Terraform interaja com a API do Libvirt para gerenciar os recursos de virtualização. Este arquivo configura a conexão com o hypervisor KVM.
1
2
3
provider "libvirt" {
uri = var.libvirt_uri
}
1.5. variables.tf
Este arquivo define as variáveis de entrada do projeto, permitindo a reutilização do código Terraform com diferentes valores para cada VM ou ambiente. Isso torna o código mais flexível e parametrizável.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
variable "libvirt_uri" {
description = "URI de conexão libvirt (ex: qemu:///system, qemu+ssh://user@host/system)"
type = string
default = "qemu:///system"
}
variable "vm_name" {
description = "Nome da máquina virtual. Exemplo: 'vm-producao-01'"
type = string
default = "vm-tf-01"
}
variable "user_name" {
description = "Nome do usuário a ser criado na VM. Este usuário será usado para acesso SSH."
type = string
default = "suporte"
}
variable "gecos" {
description = "Nome Completo do usuário (campo GECOS). Exemplo: 'Usuário de Suporte'"
type = string
default = "Suporte User"
}
variable "groups" {
description = "Nome do grupo ao qual o usuário fará parte (Debian: sudo; RHEL: wheel). Exemplo: ['users', 'sudo']"
type = list(string)
default = ["users", "sudo"]
}
variable "ssh_public_key" {
description = "Conteúdo da chave SSH pública a ser injetada na VM para acesso seguro. Exemplo: 'ssh-rsa AAAAB3Nz...'"
type = string
sensitive = true
}
variable "user_data" {
description = "Caminho para o template do cloud-init (user_data.yml)."
type = string
default = "user_data.yml"
}
variable "base_image_path" {
description = "Caminho da imagem base (.qcow2) do sistema operacional a ser utilizada para a VM. Exemplo: '~/kvm/templates/debian-12-amd64.qcow2'"
type = string
default = "~/kvm/templates/debian-12-amd64.qcow2"
}
variable "memory_mb" {
description = "Memória em MB a ser alocada para a VM. Exemplo: 4096 (para 4GB)"
type = number
default = 2048
}
variable "vcpu_count" {
description = "Número de vCPUs a serem alocadas para a VM. Exemplo: 4"
type = number
default = 2
}
variable "network_name" {
description = "Nome da rede Libvirt à qual a VM será conectada. Exemplo: 'default' ou 'minha_rede_isolada'"
type = string
default = "default"
}
1.6. versions.tf
Este arquivo define as versões mínimas necessárias do Terraform Core e dos provedores utilizados no projeto. Fixar as versões é uma boa prática para garantir a reprodutibilidade do ambiente, evitando problemas de compatibilidade que podem surgir com atualizações futuras dos provedores ou do Terraform.
1
2
3
4
5
6
7
8
9
10
terraform {
required_version = ">= 1.11.0"
required_providers {
libvirt = {
source = "dmacvicar/libvirt"
version = "0.8.3"
}
}
}
1.7. volumes.tf
Este recurso Terraform é responsável por criar o disco virtual para a VM. O atributo source
aponta para a imagem base do sistema operacional que será clonada ou utilizada para criar o disco da nova VM, garantindo que a VM inicie com um sistema operacional pré-configurado.
1
2
3
4
5
6
resource "libvirt_volume" "os_image" {
name = "base-${var.vm_name}.qcow2"
pool = "default"
source = var.base_image_path
format = "qcow2"
}
2. Configuração do Cloud-Init
O Cloud-Init é uma ferramenta de inicialização de máquinas virtuais que permite a personalização automática de VMs na primeira inicialização. Ele lê configurações fornecidas em formatos como YAML (no caso do user_data.yml
) e executa ações como criação de usuários, instalação de pacotes, configuração de rede e execução de scripts. Isso é fundamental para a automação, pois garante que cada VM provisionada já venha com as configurações básicas necessárias.
2.1 Configuração do Cloud-Init (user_data.yml
)
O arquivo user_data.yml
contém as instruções de configuração que o Cloud-Init aplicará à sua VM. A sintaxe YAML é utilizada para definir essas configurações de forma estruturada. É importante notar que disable_root: true
e ssh_pwauth: false
são configurações de segurança recomendadas, desabilitando o login direto como root e a autenticação por senha via SSH, respectivamente, forçando o uso de chaves SSH para acesso seguro.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#cloud-config
users:
- name: ${user_name}
gecos: ${gecos}
sudo: ALL=(ALL) NOPASSWD:ALL
groups: ${jsonencode(groups)}
shell: /bin/bash
lock_passwd: true
ssh_authorized_keys:
- "${ssh_key}"
disable_root: true
ssh_pwauth: false
# Hostname da VM
runcmd:
- hostnamectl set-hostname ${hostname}
Para garantir que seu arquivo user_data.yml
esteja sintaticamente correto e siga o schema do Cloud-Init, é altamente recomendável validá-lo. Isso evita erros de configuração na VM durante a inicialização. Você pode fazer isso com o seguinte comando:
1
cloud-init schema --config-file user_data.yml
3. Configurações Sensíveis (terraform.tfvars
)
O arquivo terraform.tfvars
é onde você define os valores reais para as variáveis do seu projeto Terraform. É crucial entender que este arquivo NUNCA deve ser versionado em sistemas de controle de versão como o Git. Isso ocorre porque ele geralmente contém informações sensíveis, como chaves SSH, senhas ou outros dados confidenciais que não devem ser expostos publicamente. O terraform.tfvars.example
serve como um modelo seguro para que outros colaboradores saibam quais variáveis precisam ser definidas, sem expor os valores reais.
3.1. Crie terraform.tfvars
a partir do Exemplo
1
2
3
4
5
6
7
8
9
10
vm_name = "vm-tf-01"
user_name = "suporte"
gecos = "Suporte User"
groups = ["users", "sudo"]
ssh_public_key = "ssh-ed25519 AAAAC... user@host"
user_data = "user_data.yml"
memory_mb = 4096
vcpu_count = 4
network_name = "default"
base_image_path = "/home/gean/kvm/templates/debian-12-amd64.qcow2"
4. Versionamento com .gitignore
No contexto de Infraestrutura como Código (IaC), o versionamento é fundamental para rastrear mudanças, colaborar em projetos e garantir a reprodutibilidade. O arquivo .gitignore
desempenha um papel crucial nesse processo, pois ele especifica quais arquivos e diretórios o Git deve ignorar, evitando que dados sensíveis, arquivos temporários ou gerados automaticamente sejam acidentalmente commitados ao repositório. Isso é vital para a segurança e para manter o histórico do Git limpo e relevante.
# Terraform
.terraform/
*.tfstate
*.tfstate.*
*.tfplan
*.tfout
# Arquivos sensíveis
terraform.tfvars
*.tfvars.json
# Arquivos temporários
*~
.swp
.swo
.swn
# Logs e saídas
logs/
output/
Passos para Aplicar o .gitignore
:
- Crie o arquivo: Se ainda não existir, crie o arquivo
.gitignore
na raiz do seu projeto:1
touch .gitignore
- Cole as regras: Adicione o conteúdo acima ao arquivo
.gitignore
. - Adicione ao repositório: Adicione e commite o
.gitignore
ao seu repositório Git:1 2
git add .gitignore git commit -m "Adiciona .gitignore para ignorar arquivos sensíveis e temporários"
- Remova arquivos sensíveis já versionados (se necessário): Se você acidentalmente já versionou arquivos que deveriam ser ignorados (como
terraform.tfvars
ou.tfstate
), você precisará removê-los do histórico do Git. Cuidado ao executar estes comandos, pois eles reescrevem o histórico e podem causar perda de dados se não forem usados corretamente.1 2 3
git rm -r --cached .terraform git rm -r --cached terraform.tfstate git commit -m "Remove arquivos sensíveis do histórico do Git"
Recomendações Extras para Segurança e Versionamento:
- Não ignore o
.terraform.lock.hcl
: Este arquivo deve ser commitado para garantir consistência nas versões dos provedores entre diferentes ambientes e colaboradores. Ele garante que todos os membros da equipe usem as mesmas versões exatas dos provedores Terraform. - Proteja segredos: Para ambientes de produção, considere usar ferramentas mais robustas para gerenciamento de segredos, como HashiCorp Vault ou variáveis de ambiente seguras em pipelines de CI/CD, em vez de
terraform.tfvars
. Essas soluções oferecem maior segurança e controle de acesso. - Documentação: Mantenha um
README.md
atualizado explicando a estrutura do projeto, como usá-lo e quaisquer considerações de segurança. Uma boa documentação é essencial para a colaboração e a manutenção a longo prazo.
5. Implantação da VM
Após configurar todos os arquivos Terraform e o Cloud-Init, o próximo passo é implantar a máquina virtual. Este processo envolve três comandos principais do Terraform, cada um com uma função específica no ciclo de vida da infraestrutura como código.
5.1. Inicialize o Terraform
O comando terraform init
inicializa o diretório de trabalho do Terraform. Ele baixa os provedores necessários (neste caso, o provedor libvirt
) e configura o backend, preparando o ambiente para que o Terraform possa interagir com sua infraestrutura.
1
terraform init
5.2. Planeje a Infraestrutura
O comando terraform plan
gera um plano de execução que mostra as ações que o Terraform realizará para atingir o estado desejado da infraestrutura. Ele compara o estado atual da sua infraestrutura com a configuração definida nos seus arquivos .tf
e exibe um resumo das mudanças (criações, modificações, exclusões) que serão aplicadas, sem realmente executar essas mudanças. Isso é crucial para revisar e validar as operações antes de aplicá-las.
1
terraform plan
5.3. Aplique as Mudanças
O comando terraform apply
aplica as mudanças definidas no plano de execução, provisionando ou modificando a infraestrutura real de acordo com a sua configuração. Após a execução, o Terraform exibirá um resumo das operações realizadas e, se tudo ocorrer bem, sua VM será provisionada no KVM.
1
terraform apply
6. Acessando a VM
Após o provisionamento bem-sucedido da sua Máquina Virtual, o próximo passo é acessá-la. A forma mais comum e segura de acesso a VMs Linux é via SSH (Secure Shell).
6.1. Acesso via SSH
Para acessar sua VM via SSH, você precisará do nome de usuário configurado no Cloud-Init e do endereço IP da VM, que pode ser obtido através do terraform output vm_ip
. O comando ssh
é utilizado da seguinte forma:
1
2
3
ssh -i ~/.ssh/tfvms <user_name>@<vm_ip>
# Exemplo:
ssh -i ~/.ssh/tfvms suporte@10.64.0.10
O parâmetro -i
é utilizado para especificar o caminho para o arquivo da sua chave SSH privada. Certifique-se de que a chave privada correspondente à chave pública que você injetou na VM via Cloud-Init esteja localizada no caminho especificado e que suas permissões estejam corretamente configuradas (geralmente chmod 400 ~/.ssh/tfvms
).
7. Testando Variáveis com terraform console
O terraform console
é uma ferramenta interativa poderosa que permite testar expressões e variáveis do Terraform em tempo real. Isso é extremamente útil para depurar configurações, entender o comportamento de funções e validar valores de variáveis antes de aplicá-los à sua infraestrutura. Além disso, o terraform console
é uma excelente ferramenta para depurar módulos complexos ou validar a lógica condicional em seus arquivos Terraform.
Para iniciar o console, navegue até o diretório raiz do seu projeto Terraform e execute:
1
terraform console
Uma vez no console, você pode testar suas variáveis. Por exemplo, para verificar o valor da variável groups
que definimos como ["users", "sudo"]
:
1
2
> var.groups
[ "users", "sudo" ]
Você também pode testar expressões mais complexas ou funções do Terraform. Por exemplo, para verificar se um determinado grupo está presente na lista:
1
2
3
4
> contains(var.groups, "sudo")
true
> contains(var.groups, "admin")
false
Para sair do console, digite exit
ou pressione Ctrl+D
.
Informações Adicionais: Boas Práticas e Considerações Avançadas
Para otimizar ainda mais o uso do Terraform com KVM e garantir um ambiente robusto, seguro e escalável, considere as seguintes boas práticas e informações adicionais. A adoção dessas práticas eleva a qualidade da sua infraestrutura como código e melhora a eficiência operacional.
Gerenciamento de Imagens Base
É crucial ter um processo bem definido para o gerenciamento de suas imagens base (.qcow2
). Mantenha suas imagens atualizadas com as últimas correções de segurança e pacotes. Você pode automatizar a criação dessas imagens usando ferramentas como o Packer, que permite criar imagens customizadas e pré-configuradas para diferentes sistemas operacionais. Os benefícios do Packer incluem a automatização do processo de criação de imagens, a garantia de consistência entre as imagens e a redução de erros manuais. Isso garante que todas as VMs provisionadas a partir dessas imagens já venham com as configurações básicas e dependências necessárias, reduzindo o tempo de provisionamento e a chance de erros.
Redes e Segurança
Ao configurar redes para suas VMs KVM, planeje cuidadosamente a topologia de rede. O Libvirt oferece diversas opções de rede, como redes em bridge (para comunicação direta com a rede física), redes NAT (para VMs com acesso à internet, mas isoladas da rede física) e redes isoladas (para comunicação apenas entre VMs dentro da mesma rede virtual). Utilize redes isoladas para diferentes ambientes (desenvolvimento, teste, produção) e implemente regras de firewall robustas para controlar o tráfego de entrada e saída. Considere também a implementação de grupos de segurança ou listas de controle de acesso (ACLs) para granularidade no controle de acesso entre VMs, aumentando a segurança da sua infraestrutura.
Monitoramento e Logging
Após o provisionamento das VMs, é fundamental implementar soluções de monitoramento e logging. Ferramentas como Prometheus e Grafana podem ser utilizadas para coletar métricas de desempenho das VMs e do host KVM (CPU, memória, disco, rede), enquanto soluções de logging centralizado como ELK Stack (Elasticsearch, Logstash, Kibana) ou Loki podem agregar logs de todas as suas VMs (logs de sistema, logs de aplicação). Isso permite identificar proativamente problemas de desempenho, segurança e disponibilidade, garantindo a estabilidade da sua infraestrutura e facilitando a depuração.
CI/CD para Infraestrutura
Integrar seu código Terraform em um pipeline de CI/CD (Integração Contínua/Entrega Contínua) é uma prática recomendada para garantir a consistência e a automação de suas implantações. Ferramentas como GitLab CI/CD, Jenkins ou GitHub Actions podem ser configuradas para executar terraform plan
em cada pull request e terraform apply
após a aprovação e merge do código. Isso não só automatiza o processo de implantação, mas também garante que todas as mudanças na infraestrutura passem por um processo de revisão e validação, minimizando riscos e garantindo a imutabilidade da infraestrutura e a rastreabilidade das mudanças.
Manutenção e Atualizações
Periodicamente, revise e atualize suas configurações Terraform e as versões dos provedores. O ecossistema Terraform está em constante evolução, e novas versões trazem melhorias de desempenho, segurança e novas funcionalidades. Mantenha-se atualizado com as últimas versões do Terraform e do provedor libvirt
para aproveitar ao máximo os recursos disponíveis e garantir a compatibilidade com as versões mais recentes do KVM. É altamente recomendável testar todas as atualizações em ambientes de não-produção antes de aplicá-las em produção para evitar interrupções inesperadas.
Conclusão
Este tutorial demonstrou como o Terraform pode ser uma ferramenta incrivelmente poderosa para automatizar o provisionamento e gerenciamento de máquinas virtuais no KVM. Ao adotar a abordagem de Infraestrutura como Código (IaC), você ganha não apenas em velocidade e eficiência, mas também em consistência, reprodutibilidade e rastreabilidade de suas infraestruturas. A capacidade de definir sua infraestrutura em arquivos de código permite que você versionize, revise e colabore em suas configurações, transformando o gerenciamento de VMs em um processo mais robusto e menos propenso a erros manuais.
Ao seguir as etapas e considerar as boas práticas e informações adicionais apresentadas, você estará bem equipado para construir e manter ambientes virtuais complexos com facilidade. A combinação de KVM e Terraform abre um leque de possibilidades para desenvolvedores, engenheiros de DevOps e administradores de sistemas que buscam otimizar suas operações e focar em inovação, em vez de tarefas repetitivas de configuração manual. A capacidade de recriar ambientes rapidamente para testes, recuperação de desastres ou escalabilidade é um valor de longo prazo inestimável que a IaC proporciona. Continue explorando as capacidades dessas ferramentas e adapte-as às suas necessidades específicas para maximizar o potencial da sua infraestrutura automatizada.