Fundamentos do Packer e QEMU/KVM: Criando Imagens Automatizadas
Nota: Este tutorial é o primeiro de uma série de 6 tutoriais sobre criação de imagens QEMU/KVM com Packer. A série completa abordará desde os fundamentos até técnicas avançadas de personalização e integração com pipelines CI/CD, cobrindo Oracle Linux, Debian e Ubuntu.
Introdução
A criação manual de imagens de máquinas virtuais é um processo demorado, propenso a erros e difícil de reproduzir consistentemente. Imagine ter que instalar manualmente um sistema operacional, configurar pacotes, aplicar atualizações e otimizar configurações toda vez que precisar de uma nova imagem. Agora multiplique isso por dezenas ou centenas de máquinas em um ambiente corporativo.
É aqui que o Packer entra como uma ferramenta revolucionária para DevOps e administradores de sistemas. Desenvolvido pela HashiCorp, o Packer permite automatizar todo o processo de criação de imagens de máquinas virtuais para múltiplas plataformas a partir de uma única configuração.
Neste primeiro tutorial da nossa série, vamos explorar os fundamentos do Packer em conjunto com QEMU/KVM, preparar nosso ambiente de desenvolvimento e criar nosso primeiro arquivo de configuração básico.
O que é Virtualização com QEMU/KVM?
Antes de mergulharmos no Packer, vamos entender brevemente o que é QEMU/KVM:
QEMU (Quick Emulator) é um emulador e virtualizador de código aberto que pode executar sistemas operacionais e programas feitos para uma máquina em uma arquitetura diferente. Quando combinado com o KVM (Kernel-based Virtual Machine), um módulo de virtualização no kernel Linux, o QEMU pode alcançar desempenho próximo ao nativo.
Principais características do QEMU/KVM:
- Código aberto: Totalmente gratuito e de código aberto
- Desempenho: Com KVM, oferece virtualização com desempenho próximo ao nativo
- Flexibilidade: Suporta diversos sistemas operacionais convidados
- Formatos de disco: Trabalha com vários formatos de disco virtual (raw, qcow2, vmdk, etc.)
- Integração: Base para muitas soluções de virtualização como libvirt, OpenStack e Proxmox
O que é o Packer?
Packer é uma ferramenta de código aberto para criar imagens de máquinas idênticas para múltiplas plataformas a partir de uma única configuração. Desenvolvido pela HashiCorp (mesma empresa por trás do Terraform, Vault e Consul), o Packer automatiza o processo de criação de imagens para:
- Máquinas virtuais (QEMU/KVM, VMware, VirtualBox)
- Contêineres (Docker)
- Nuvem pública (AWS AMI, Azure VHD, Google Compute Image)
- E muitas outras plataformas
Por que usar o Packer?
- Automação: Elimina processos manuais e repetitivos
- Consistência: Garante que todas as imagens sejam criadas da mesma forma
- Versionamento: Permite versionar suas configurações de imagem como código
- Multi-plataforma: Cria imagens para múltiplas plataformas simultaneamente
- Integração com IaC: Complementa ferramentas como Terraform e Ansible
- Imutabilidade: Facilita a adoção de infraestrutura imutável
Preparando o Ambiente de Desenvolvimento
Vamos configurar nosso ambiente para trabalhar com Packer e QEMU/KVM. Siga os passos abaixo para instalar as ferramentas necessárias:
Pré-requisitos
- Sistema operacional Linux (usaremos Ubuntu/Debian neste exemplo)
- Acesso de administrador (sudo)
- Processador com suporte a virtualização (Intel VT-x ou AMD-V)
- Pelo menos 4GB de RAM e 20GB de espaço em disco
Instalando o QEMU/KVM
1
2
3
4
5
6
7
8
# Atualizar repositórios
sudo apt update
# Instalar QEMU e ferramentas relacionadas
sudo apt install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virtinst
# Verificar se o KVM está disponível
kvm-ok
Se o comando kvm-ok retornar “KVM acceleration can be used”, seu sistema está pronto para usar KVM.
Instalando o Packer
O Packer está disponível em repositórios oficiais, mas para garantir que temos a versão mais recente, vamos usar o repositório da HashiCorp:
1
2
3
4
5
6
7
8
9
10
11
# Adicionar a chave GPG do HashiCorp
curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
# Adicionar o repositório do HashiCorp
sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
# Atualizar e instalar o Packer
sudo apt update && sudo apt install -y packer
# Verificar a instalação
packer version
Certifique-se de que a versão do Packer seja 1.10.0 ou superior, conforme recomendado em nosso projeto.
Estrutura de Diretórios
Para manter nosso projeto organizado, vamos criar uma estrutura de diretórios recomendada:
1
2
3
4
5
6
# Criar diretório do projeto
mkdir -p ~/packer-kvm-tutorial/tutorial1
cd ~/packer-kvm-tutorial/tutorial1
# Criar subdiretórios
mkdir -p http scripts
Esta estrutura básica nos servirá bem para este primeiro tutorial:
- http/: Armazenará arquivos que serão servidos via HTTP durante a instalação
- scripts/: Conterá scripts de provisionamento
Entendendo a Estrutura do Arquivo Packer (HCL)
O Packer usa o formato HCL (HashiCorp Configuration Language) para seus arquivos de configuração. Vamos entender as principais seções de um arquivo Packer:
1. Bloco packer
Define a versão mínima do Packer necessária e os plugins requeridos:
1
2
3
4
5
6
7
8
9
packer {
  required_version = ">= 1.10.0"
  required_plugins {
    qemu = {
      version = "= 1.1.0"
      source  = "github.com/hashicorp/qemu"
    }
  }
}
2. Bloco variable
Define variáveis que podem ser reutilizadas em todo o arquivo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
variable "vm_name" {
  default = "ubuntu-kvm-template.raw"
}
variable "disk_size" {
  default = "16384"
}
variable "iso_url" {
  default = "https://releases.ubuntu.com/22.04/ubuntu-22.04.3-live-server-amd64.iso"
}
variable "iso_checksum" {
  default = "a4acfda10b18da50e2ec50ccaf860d7f20823f8f3100053d30f137dc7cc46e9f"
}
3. Bloco source
Define a configuração da máquina virtual e do provedor (QEMU neste caso):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
source "qemu" "iso" {
  vm_name          = var.vm_name
  iso_url          = var.iso_url
  iso_checksum     = var.iso_checksum
  disk_size        = var.disk_size
  memory           = 2048
  disk_image       = false
  output_directory = "build/os-base"
  accelerator      = "kvm"
  disk_interface   = "virtio"
  format           = "raw"
  net_device       = "virtio-net"
  boot_wait        = "3s"
  http_directory   = "http"
  cpu_model        = "host"
  ssh_username     = "packer"
  ssh_password     = "packer"
  ssh_timeout      = "60m"
}
4. Bloco build
Define como a imagem será construída, incluindo provisionadores:
1
2
3
4
5
6
7
8
9
10
build {
  sources = ["source.qemu.iso"]
  # Exemplo de provisionador para executar um script
  provisioner "shell" {
    inline = [
      "echo 'Instalação concluída com sucesso!'"
    ]
  }
}
Criando Nosso Primeiro Arquivo Packer
Vamos criar um arquivo Packer básico para entender como funciona. Este exemplo não criará uma imagem completa ainda, mas nos ajudará a entender a estrutura e validar nossa configuração.
Crie um arquivo chamado basic.pkr.hcl no diretório do projeto:
1
nano ~/packer-kvm-tutorial/tutorial1/basic.pkr.hcl
Adicione o seguinte conteúdo:
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
packer {
  required_version = ">= 1.10.0"
  required_plugins {
    qemu = {
      version = "= 1.1.0"
      source  = "github.com/hashicorp/qemu"
    }
  }
}
variable "vm_name" {
  default = "basic-vm-template.raw"
}
variable "disk_size" {
  default = "8192"
}
variable "iso_url" {
  default = "https://releases.ubuntu.com/22.04/ubuntu-22.04.3-live-server-amd64.iso"
}
variable "iso_checksum" {
  default = "a4acfda10b18da50e2ec50ccaf860d7f20823f8f3100053d30f137dc7cc46e9f"
}
source "qemu" "iso" {
  vm_name          = var.vm_name
  iso_url          = var.iso_url
  iso_checksum     = var.iso_checksum
  disk_size        = var.disk_size
  memory           = 2048
  disk_image       = false
  output_directory = "build/basic"
  accelerator      = "kvm"
  disk_interface   = "virtio"
  format           = "raw"
  net_device       = "virtio-net"
  boot_wait        = "3s"
  http_directory   = "http"
  cpu_model        = "host"
  ssh_username     = "packer"
  ssh_password     = "packer"
  ssh_timeout      = "60m"
  
  # Este comando não funcionará sem um arquivo de automação adequado
  # Está aqui apenas para ilustrar a estrutura
  boot_command = [
    "<esc><wait>",
    "install <wait>",
    "preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/preseed.cfg <wait>",
    "<enter><wait>"
  ]
}
build {
  sources = ["source.qemu.iso"]
  # Exemplo simples de provisionador
  provisioner "shell" {
    inline = [
      "echo 'Este é um exemplo básico de provisionamento.'"
    ]
  }
}
Validando o Arquivo Packer
Antes de tentar construir uma imagem, é uma boa prática validar seu arquivo Packer para garantir que não há erros de sintaxe:
1
2
3
cd ~/packer-kvm-tutorial/tutorial1
packer init .
packer validate basic.pkr.hcl
Se tudo estiver correto, você verá a mensagem “The configuration is valid.”
Nota: Este arquivo básico não construirá uma imagem funcional ainda, pois não temos os arquivos de automação necessários (como o preseed.cfg mencionado no boot_command). Nos próximos tutoriais, abordaremos a criação desses arquivos para diferentes distribuições Linux.
Entendendo os Componentes Principais
Vamos revisar os componentes principais que vimos no nosso arquivo básico:
1. Variáveis
As variáveis permitem parametrizar sua configuração, facilitando a reutilização e personalização:
1
2
3
variable "vm_name" {
  default = "basic-vm-template.raw"
}
Você pode substituir o valor padrão ao executar o Packer:
1
packer build -var "vm_name=custom-template.raw" basic.pkr.hcl
2. Provedor QEMU
O provedor QEMU configura como a máquina virtual será criada:
- vm_name: Nome do arquivo de imagem resultante
- iso_urle- iso_checksum: Localização e verificação da ISO
- disk_size: Tamanho do disco em MB
- memory: Quantidade de RAM em MB
- accelerator: Usa KVM para melhor desempenho
- format: Formato do disco (raw, qcow2, etc.)
- boot_command: Comandos enviados durante o boot para automatizar a instalação
3. Provisionadores
Os provisionadores permitem configurar a máquina após a instalação do sistema operacional:
- shell: Executa comandos shell na máquina
- file: Copia arquivos para a máquina
- ansible: Executa playbooks Ansible
- E muitos outros…
Próximos Passos
Neste tutorial, aprendemos os fundamentos do Packer e QEMU/KVM, preparamos nosso ambiente de desenvolvimento e criamos um arquivo Packer básico. No próximo tutorial, vamos criar nossa primeira imagem completa para Oracle Linux usando Kickstart para automatizar a instalação.
Você já deve estar se perguntando:
- Como automatizar completamente a instalação sem interação manual?
- Como personalizar a imagem com pacotes e configurações específicas?
- Como otimizar a imagem final para uso em produção?
Todas essas perguntas serão respondidas nos próximos tutoriais da série!
Exercícios Práticos
Para fixar o conhecimento adquirido neste tutorial, tente os seguintes exercícios:
- Modifique o arquivo basic.pkr.hclpara usar uma ISO diferente (como Debian ou CentOS)
- Altere os valores padrão das variáveis (tamanho do disco, memória, etc.)
- Adicione comentários explicativos ao arquivo para documentar cada seção
- Experimente adicionar mais variáveis para outros parâmetros (como cpu_modelounet_device)
Conclusão
Neste primeiro tutorial, estabelecemos as bases para nossa jornada de criação automatizada de imagens com Packer e QEMU/KVM. Aprendemos sobre os conceitos fundamentais, preparamos nosso ambiente de desenvolvimento e criamos nosso primeiro arquivo de configuração Packer.
Nos próximos tutoriais, vamos mergulhar mais fundo na automação completa da criação de imagens para diferentes distribuições Linux, começando com Oracle Linux e o método Kickstart.
Até lá, experimente com o arquivo básico que criamos e familiarize-se com a sintaxe HCL e os conceitos do Packer!