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 Brasilkeyboard-configuration/xkb-keymap select br
: Define o layout de teclado como brasileirotime/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 redenetcfg/get_hostname string packer
: Define o hostname como “packer”
Configuração de Espelho (Mirror)
mirror/country string BR
: Seleciona espelhos do Brasilmirror/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 rootpasswd/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 particionamentopartman-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 SSHpkgsel/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 resultantedisk_size
: Tamanho do disco em MB (16GB neste caso)iso_url
: URL da ISO do Debian 12iso_checksum
: Checksum da ISO para verificação
Configuração QEMU
memory
: 2GB de RAM para a VMaccelerator
: Usa KVM para melhor desempenhodisk_interface
enet_device
: Usa dispositivos virtio para melhor desempenhoformat
: 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 Preseeddebian-installer=pt_BR.UTF-8
: Define o idioma do instaladorauto
: 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
,/home
e 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.