Criação de Imagem Debian com Packer e Preseed
Nota: Este tutorial é o terceiro de uma série de 6 tutoriais sobre criação de imagens QEMU/KVM com Packer. Se você ainda não leu os tutoriais anteriores sobre os fundamentos do Packer e a criação de imagens Oracle Linux, recomendamos que o faça antes de prosseguir. Criação de Imagem Oracle Linux com Packer e Kickstart.
Introdução
Nos tutoriais anteriores, exploramos os fundamentos do Packer e QEMU/KVM e aprendemos a criar uma imagem automatizada do Oracle Linux usando Kickstart. Agora, vamos avançar para a criação de uma imagem do Debian 12 (Bookworm) utilizando o método Preseed para automação da instalação.
O Debian é uma das distribuições Linux mais estáveis e amplamente utilizadas, servindo como base para muitas outras distribuições, incluindo o Ubuntu. Sua filosofia de software livre e estabilidade o torna uma excelente escolha para servidores e ambientes de produção.
Neste tutorial, vamos:
- Entender o que é o Preseed e como ele funciona
- Criar um arquivo Preseed personalizado para Debian 12
- Configurar o Packer para utilizar o Preseed
- Adicionar scripts de provisionamento para personalização
- Construir e validar a imagem final
O que é Preseed?
Preseed é o sistema de automação de instalação do Debian, similar ao Kickstart usado no Red Hat/Oracle Linux. Ele permite automatizar completamente o processo de instalação, fornecendo respostas pré-definidas para todas as perguntas que normalmente seriam feitas durante uma instalação manual.
Um arquivo Preseed contém configurações para:
- Localização e idioma
- Configuração de rede
- Configuração de usuários e senhas
- Particionamento de disco
- Seleção de pacotes
- Configurações de boot
- Scripts de pós-instalação
Vantagens do Preseed
- Automação completa: Elimina a necessidade de intervenção manual
- Flexibilidade: Permite personalização detalhada da instalação
- Reprodutibilidade: Garante instalações idênticas a cada vez
- Integração: Funciona perfeitamente com ferramentas como o Packer
- Documentação extensa: Bem documentado na wiki do Debian
Preparando o Ambiente
Vamos preparar nosso ambiente de trabalho para este tutorial:
1
2
3
4
5
6
# Criar diretório para o terceiro tutorial
mkdir -p ~/packer-kvm-tutorial/tutorial3
cd ~/packer-kvm-tutorial/tutorial3
# Criar subdiretórios necessários
mkdir -p http scripts build/os-base
Criando o Arquivo Preseed
O arquivo Preseed é o coração da nossa automação. Vamos criar um arquivo preseed.cfg no diretório http que será servido via HTTP durante a instalação:
1
nano http/preseed.cfg
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
66
# Definindo o idioma como português do Brasil
d-i debian-installer/locale string pt_BR.UTF-8
# Teclado para layout brasileiro
d-i keyboard-configuration/xkb-keymap select br
# Locales adicionais
d-i localechooser/supported-locales multiselect pt_BR.UTF-8, en_US.UTF-8
### Network configuration
d-i netcfg/choose_interface select auto
d-i netcfg/get_hostname string packer
d-i netcfg/get_domain string local
### Mirror settings
d-i mirror/country string BR
d-i mirror/http/hostname string deb.debian.org
d-i mirror/http/directory string /debian
d-i mirror/http/proxy string
### Account setup
# Senha root e usuário padrão
d-i passwd/root-password password packer
d-i passwd/root-password-again password packer
d-i passwd/user-fullname string Packer
d-i passwd/username string packer
d-i passwd/user-password password packer
d-i passwd/user-password-again password packer
# Fuso horário do Brasil
d-i time/zone string America/Sao_Paulo
d-i clock-setup/utc boolean true
# Particionamento Automático - LVM
d-i partman-auto/disk string /dev/vda
d-i partman-auto/method string lvm
d-i partman-lvm/device_remove_lvm boolean true
d-i partman-md/device_remove_md boolean true
d-i partman-lvm/confirm boolean true
d-i partman-lvm/confirm_nooverwrite boolean true
# Forçar o particionamento e gravação no disco sem confirmação
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
d-i partman/confirm_nooverwrite boolean true
### Base system installation
d-i base-installer/install-recommends boolean false
# Definindo para usar atualização completa após a instalação
d-i pkgsel/upgrade select full-upgrade
# Escolha de pacotes
tasksel tasksel/first multiselect SSH server
d-i pkgsel/include string openssh-server sudo
### Boot loader installation
d-i grub-installer/only_debian boolean true
d-i grub-installer/with_other_os boolean true
d-i grub-installer/bootdev string default
### Finishing up the installation
d-i finish-install/reboot_in_progress note
# Comando de finalização
d-i preseed/late_command string echo 'packer ALL = (root) NOPASSWD: ALL' > /target/etc/sudoers.d/packer; chmod 440 /target/etc/sudoers.d/packer
Vamos analisar as principais seções deste arquivo Preseed:
Configurações Básicas
- debian-installer/locale string pt_BR.UTF-8: Define o idioma como português do Brasil
- keyboard-configuration/xkb-keymap select br: Define o layout de teclado como brasileiro
- time/zone string America/Sao_Paulo: Define o fuso horário para São Paulo
Configuração de Rede
- netcfg/choose_interface select auto: Seleciona automaticamente a interface de rede
- netcfg/get_hostname string packer: Define o hostname como “packer”
Configuração de Espelho (Mirror)
- mirror/country string BR: Seleciona espelhos do Brasil
- mirror/http/hostname string deb.debian.org: Define o servidor espelho principal
Configuração de Usuários
- passwd/root-password password packer: Define a senha do root
- passwd/username string packer: Cria um usuário chamado “packer”
- passwd/user-password password packer: Define a senha do usuário
Particionamento
- partman-auto/method string lvm: Usa LVM para particionamento
- partman-auto/disk string /dev/vda: Usa o disco vda (padrão para QEMU/KVM)
Seleção de Pacotes
- tasksel/first multiselect SSH server: Instala o servidor SSH
- pkgsel/include string openssh-server sudo: Instala pacotes adicionais
Comando de Finalização
- preseed/late_command: Executa comandos após a instalação, neste caso configurando o sudo para o usuário packer
Criando o Script de Limpeza
Agora, vamos criar um script de limpeza que será executado após a instalação para otimizar a imagem:
1
nano scripts/cleanup.sh
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
#!/bin/bash -eux
# Atualizar o sistema
apt-get update
apt-get -y upgrade
# Instalar pacotes essenciais
apt-get -y install cloud-init qemu-guest-agent
# Configurar cloud-init para NoCloud
cat > /etc/cloud/cloud.cfg.d/99-nocloud.cfg << EOF
datasource_list: [ NoCloud, None ]
EOF
# Limpar pacotes não necessários
apt-get -y autoremove
apt-get -y clean
# Limpar logs e arquivos temporários
find /var/log -type f -exec truncate --size=0 {} \;
rm -rf /tmp/*
rm -rf /var/tmp/*
# Remover informações específicas da máquina
truncate -s 0 /etc/machine-id
rm -f /etc/ssh/*key*
rm -f ~/.bash_history
# Limpar histórico de apt
rm -f /var/lib/apt/lists/*
# Zerar espaço livre
fstrim -av
Este script realiza várias tarefas importantes:
- Atualiza o sistema e instala pacotes essenciais (cloud-init, qemu-guest-agent)
- Configura o cloud-init para usar o datasource NoCloud
- Remove pacotes desnecessários e limpa caches
- Remove logs e arquivos temporários
- Remove identificadores únicos da máquina (machine-id, chaves SSH)
- Executa fstrim para otimizar o espaço em disco
Torne o script executável:
1
chmod +x scripts/cleanup.sh
Criando o Arquivo Packer
Agora, vamos criar o arquivo Packer que utilizará o Preseed e o script de limpeza:
1
nano debian12-kvm.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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
packer {
  required_version = ">= 1.10.0" 
  required_plugins {
    qemu = {
      version = "= 1.1.0"
      source  = "github.com/hashicorp/qemu"
    }
  }
}
variable "vm_name" {
  default = "debian-12-amd64.raw"
}
variable "disk_size" {
  default = "16384"
}
variable "iso_url" {
  default = "https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-12.5.0-amd64-netinst.iso"
}
variable "iso_checksum" {
  default = "013f5b44670d81280b5b1bc02455842b247951bf8ba45f6.."
}
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        = "5s"
  boot_command = [
    "<esc><wait>",
    "install <wait>",
    "preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/preseed.cfg <wait>",
    "debian-installer=pt_BR.UTF-8 <wait>",
    "auto <wait>",
    "locale=pt_BR.UTF-8 <wait>",
    "kbd-chooser/method=br <wait>",
    "keyboard-configuration/xkb-keymap=br <wait>",
    "netcfg/get_hostname=packer <wait>",
    "netcfg/get_domain=local <wait>",
    "fb=false <wait>",
    "debconf/frontend=noninteractive <wait>",
    "console-setup/ask_detect=false <wait>",
    "console-keymaps-at/keymap=br <wait>",
    "<enter><wait>"
  ]
  http_directory   = "http"
  cpu_model        = "host"
  shutdown_command = "echo 'packer' | sudo -S shutdown -P now"
  ssh_username     = "packer"
  ssh_password     = "packer"
  ssh_timeout      = "60m"
}
build {
  sources = ["source.qemu.iso"]
  # Envia o script de limpeza para a VM
  provisioner "file" {
    source      = "scripts/cleanup.sh"          
    destination = "/tmp/cleanup.sh"      
  }
  # Executa o script de limpeza na VM
  provisioner "shell" {
    inline = [
      "chmod +x /tmp/cleanup.sh",
      "echo 'packer' | sudo -S /tmp/cleanup.sh" 
    ]
  }
}
Vamos analisar as partes importantes deste arquivo:
Variáveis
- vm_name: Nome do arquivo de imagem resultante
- disk_size: Tamanho do disco em MB (16GB neste caso)
- iso_url: URL da ISO do Debian 12
- iso_checksum: Checksum da ISO para verificação
Configuração QEMU
- memory: 2GB de RAM para a VM
- accelerator: Usa KVM para melhor desempenho
- disk_interfacee- net_device: Usa dispositivos virtio para melhor desempenho
- format: Formato raw para a imagem resultante
Boot Command
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
boot_command = [
  "<esc><wait>",
  "install <wait>",
  "preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/preseed.cfg <wait>",
  "debian-installer=pt_BR.UTF-8 <wait>",
  "auto <wait>",
  "locale=pt_BR.UTF-8 <wait>",
  "kbd-chooser/method=br <wait>",
  "keyboard-configuration/xkb-keymap=br <wait>",
  "netcfg/get_hostname=packer <wait>",
  "netcfg/get_domain=local <wait>",
  "fb=false <wait>",
  "debconf/frontend=noninteractive <wait>",
  "console-setup/ask_detect=false <wait>",
  "console-keymaps-at/keymap=br <wait>",
  "<enter><wait>"
]
Esta sequência de comandos:
- Pressiona ESC para acessar o menu de boot
- Inicia a instalação com vários parâmetros:- preseed/url: Aponta para nosso arquivo Preseed
- debian-installer=pt_BR.UTF-8: Define o idioma do instalador
- auto: Ativa o modo automático
- Várias outras configurações de localização e teclado
 
- Pressiona Enter para iniciar a instalação
Provisionadores
1
2
3
4
5
6
7
8
9
10
11
12
13
# Envia o script de limpeza para a VM
provisioner "file" {
  source      = "scripts/cleanup.sh"          
  destination = "/tmp/cleanup.sh"      
}
# Executa o script de limpeza na VM
provisioner "shell" {
  inline = [
    "chmod +x /tmp/cleanup.sh",
    "echo 'packer' | sudo -S /tmp/cleanup.sh" 
  ]
}
Estes provisionadores:
- Copiam o script de limpeza para a VM
- Tornam o script executável
- Executam o script com privilégios sudo
Construindo a Imagem
Agora que temos todos os arquivos necessários, vamos construir nossa imagem:
1
2
3
4
5
6
7
8
# Inicializar o Packer (baixa os plugins necessários)
packer init .
# Validar a configuração
packer validate debian12-kvm.pkr.hcl
# Construir a imagem (com logs detalhados)
PACKER_LOG=1 packer build debian12-kvm.pkr.hcl
Este processo pode levar algum tempo, pois o Packer irá:
- Baixar a ISO do Debian (se ainda não estiver em cache)
- Iniciar uma VM QEMU/KVM
- Inicializar a instalação com o Preseed
- Aguardar a conclusão da instalação
- Conectar-se via SSH
- Executar os provisionadores
- Desligar a VM
- Empacotar a imagem resultante
Verificando a Imagem Gerada
Após a conclusão do build, você terá uma imagem raw no diretório build/os-base:
1
ls -lh build/os-base/
Você deve ver um arquivo como debian-12-amd64.raw.
Convertendo para QCOW2 (Opcional)
O formato raw é ótimo para desempenho, mas o formato QCOW2 oferece recursos adicionais como compressão e snapshots. Para converter a imagem:
1
qemu-img convert -O qcow2 -c build/os-base/debian-12-amd64.raw debian-12-amd64.qcow2
Testando a Imagem
Para testar a imagem, você pode iniciar uma VM usando o QEMU diretamente:
1
2
3
4
5
6
7
8
9
10
qemu-system-x86_64 \
  -name "Test-Debian12" \
  -machine type=q35,accel=kvm \
  -cpu host \
  -m 2048 \
  -drive file=build/os-base/debian-12-amd64.raw,format=raw,if=virtio \
  -net nic,model=virtio \
  -net user,hostfwd=tcp::2222-:22 \
  -display none \
  -daemonize
Conecte-se à VM via SSH:
1
ssh -p 2222 packer@localhost
Diferenças entre Preseed e Kickstart
Agora que já trabalhamos com Kickstart (Oracle Linux) e Preseed (Debian), vamos destacar algumas diferenças importantes:
Sintaxe
- Kickstart: Usa uma sintaxe baseada em comandos com seções específicas (como %packages,%post)
- Preseed: Usa uma sintaxe de pares chave-valor com prefixos de domínio (como d-i,tasksel)
Flexibilidade
- Kickstart: Oferece scripts pré e pós-instalação mais flexíveis
- Preseed: Mais detalhado nas opções de configuração do instalador
Integração
- Kickstart: Integrado diretamente ao instalador Anaconda
- Preseed: Integrado ao debian-installer
Complexidade
- Kickstart: Geralmente mais simples e direto
- Preseed: Pode ser mais complexo devido ao grande número de opções disponíveis
Personalizações Adicionais
Vamos explorar algumas personalizações adicionais que você pode fazer no arquivo Preseed:
Particionamento Avançado
Para um particionamento mais detalhado com LVM:
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
# Particionamento avançado com LVM
d-i partman-auto/expert_recipe string                         \
      boot-root ::                                            \
              500 10000 1000 ext4                             \
                      $primary{ } $bootable{ }                \
                      method{ format } format{ }              \
                      use_filesystem{ } filesystem{ ext4 }    \
                      mountpoint{ /boot }                     \
              .                                               \
              6000 10000 10000 ext4                           \
                      $lvmok{ }                               \
                      method{ format } format{ }              \
                      use_filesystem{ } filesystem{ ext4 }    \
                      mountpoint{ / }                         \
              .                                               \
              2000 10000 3000 ext4                            \
                      $lvmok{ }                               \
                      method{ format } format{ }              \
                      use_filesystem{ } filesystem{ ext4 }    \
                      mountpoint{ /var }                      \
              .                                               \
              2000 10000 2000 linux-swap                      \
                      $lvmok{ }                               \
                      method{ swap } format{ }                \
              .
Configuração de Rede Avançada
Para configuração de rede estática:
1
2
3
4
5
6
7
# Configuração de rede estática
d-i netcfg/disable_autoconfig boolean true
d-i netcfg/get_ipaddress string 192.168.1.42
d-i netcfg/get_netmask string 255.255.255.0
d-i netcfg/get_gateway string 192.168.1.1
d-i netcfg/get_nameservers string 8.8.8.8
d-i netcfg/confirm_static boolean true
Instalação de Pacotes Adicionais
Para instalar mais pacotes:
1
2
# Pacotes adicionais
d-i pkgsel/include string openssh-server sudo vim git curl wget htop net-tools
Configurações Avançadas de APT
Para configurar repositórios adicionais:
1
2
3
# Configurar repositórios adicionais
d-i apt-setup/local0/repository string http://deb.debian.org/debian bookworm-backports main
d-i apt-setup/local0/comment string Debian Backports
Comandos de Finalização Avançados
Para executar comandos mais complexos após a instalação:
1
2
3
4
5
6
7
8
# Comandos de finalização avançados
d-i preseed/late_command string \
    in-target apt-get update; \
    in-target apt-get -y install cloud-init; \
    echo 'packer ALL = (root) NOPASSWD: ALL' > /target/etc/sudoers.d/packer; \
    chmod 440 /target/etc/sudoers.d/packer; \
    in-target systemctl enable qemu-guest-agent; \
    in-target sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin no/' /etc/ssh/sshd_config;
Exercícios Práticos
Para fixar o conhecimento adquirido neste tutorial, tente os seguintes exercícios:
- Modifique o arquivo Preseed para instalar um ambiente de desktop mínimo (como XFCE)
- Altere o particionamento para criar partições separadas para /,/var,/homee swap
- Adicione configurações para instalar e configurar o firewall (ufw)
- Crie uma variável adicional no arquivo Packer para permitir a escolha entre Debian 11 e 12
Solução de Problemas Comuns
A instalação não inicia com o Preseed
Verifique:
- Se o boot_command está correto e completo
- Se o arquivo Preseed está no diretório http
- Se há erros de sintaxe no arquivo Preseed
Timeout de SSH
Se o Packer não conseguir se conectar via SSH:
- Aumente o valor de ssh_timeout
- Verifique se o usuário e senha no Preseed correspondem aos definidos no Packer
- Verifique se o SSH está instalado e habilitado no Preseed
Erros no script de limpeza
Se o script de limpeza falhar:
- Verifique permissões do script
- Verifique se todos os comandos são compatíveis com Debian 12
- Tente executar os comandos manualmente para identificar o problema
Conclusão
Neste tutorial, aprendemos a criar uma imagem automatizada do Debian 12 usando Packer e Preseed. Exploramos:
- Como criar um arquivo Preseed para automação da instalação
- Como configurar o Packer para usar o Preseed
- Como adicionar scripts de provisionamento para personalização
- Como construir e validar a imagem final
- As diferenças entre Preseed e Kickstart
Esta abordagem permite criar imagens padronizadas e reproduzíveis do Debian, ideais para ambientes de produção, desenvolvimento ou testes.
No próximo tutorial, vamos explorar a criação de imagens para Ubuntu usando o método Cloud-init, que oferece uma abordagem mais moderna para automação de instalações.