Terceiro tutorial da série de templates: Ubuntu Server 24.04 (Noble) com HashiCorp Packer. O padrão é o mesmo dos templates Debian e Oracle Linux, mas o instalador automatizado é o autoinstall do Subiquity — que, curiosamente, é ele próprio um documento cloud-init. E há uma pegadinha específica do Ubuntu que este tutorial documenta (seção 4).
Código completo: pasta
ubuntu/do repositório no GitLab — user-data do autoinstall e variações, os.pkr.hcl, o script de customização e os arquivos de demo.
packer build
│
├─ HTTP server local servindo http/ (user-data + meta-data do autoinstall)
├─ VM QEMU (UEFI, qcow2, ISO Ubuntu Server)
│ └─ boot_command: autoinstall ds=nocloud-net;s=http://<ip-packer>/
├─ Subiquity lê o user-data (#cloud-config + bloco autoinstall:)
├─ SSH up → provisioners (scripts/customizing-image.sh)
└─ shutdown → build/ubuntu-noble-server.qcow2-<data>/...
Diferença conceitual: preseed e kickstart são formatos próprios dos instaladores; o autoinstall é um #cloud-config com a chave autoinstall: — quem já conhece cloud-init se sente em casa (mesma sintaxe de user-data.yaml que usamos nas VMs).
ubuntu/
├── http/
│ ├── meta-data # vazio (exigido pelo nocloud-net)
│ ├── user-data # autoinstall padrão (sem LVM)
│ ├── template-receita-auto-lvm-data # layout automático com LVM
│ ├── template-receita-lvm-data # LVM explícito
│ ├── template-receita-direct-auto-data # layout "direct" (sem LVM)
│ └── template-receita-direct-data # sem LVM explícito
├── scripts/customizing-image.sh
├── demo/
├── packer.pkr.hcl
├── ubuntu-template.pkr.hcl
├── ubuntu-variables.pkr.hcl
├── global-variables.pkr.hcl
├── locals.pkr.hcl
├── provisioners.pkr.hcl
└── secrets.pkrvars.hcl.template
Correção em relação às anotações originais: o passo de criação do diretório trazia
mkdir -p packer/qemu/debian— o correto épacker/qemu/ubuntu(copia do tutorial anterior).
Sintoma: o build morre no meio do autoinstall, sem erro claro. Causa: o Subiquity sobe o SSH cedo demais — o Packer conecta, acha que a instalação terminou e dispara o shutdown_command. A correção é segurar o SSH até o fim da instalação, com early-commands no próprio user-data:
#cloud-config
autoinstall:
version: 1
early-commands:
- systemctl stop ssh.socket ssh.service
apt:
# ...
Este ajuste pode depender da versão do Packer/plugin — em algumas combinações o build funciona sem ele. Registre a versão (
packer --version) ao lado da template: se um build futuro falhar nesse ponto, você saberá o que mudou. (Nas nossas notas, funcionava antes sem o ajuste e passou a exigir — sem a versão anterior registrada, ficou impossível comparar.)
boot_command: carrega o kernel com autoinstall ds=nocloud-net;s=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ — o Subiquity baixa user-data e meta-data do HTTP do Packer;storage: layout — direct (sem LVM), lvm ou um bloco storage: customizado. As variações em http/ cobrem os três cenários, escolhidos pela variável que aponta o user-data;| Receita | Layout | Crescimento pelo cloud-init |
|---|---|---|
user-data / template-receita-direct* |
direct (sem LVM) |
Sim (growpart) |
template-receita-auto-lvm / template-receita-lvm-data |
lvm |
Não — expansão manual de PV/LV |
scripts/customizing-image.sh replica a otimização dos outros projetos (pacotes, logs, machine-id, cloud-init + qemu-guest-agent).cp secrets.pkrvars.hcl.template secrets.pkrvars.hcl # usuário/senha temporários do build
packer init .
packer validate -var-file=secrets.pkrvars.hcl .
PACKER_LOG=1 packer build -var-file=secrets.pkrvars.hcl .
sudo mv build/ubuntu-noble-server.qcow2-*/ubuntu-noble-server.qcow2 /datastore/templates/ubuntu-noble-server-base.qcow2
sudo virsh pool-refresh templates
cd demo
genisoimage -output cidata.iso -volid cidata -joliet -rock user-data meta-data network-config
sudo cp /datastore/templates/ubuntu-noble-server-base.qcow2 /datastore/images/demo.qcow2
./virt-install.sh # --os-variant: osinfo-query os | grep -i ubuntu (ex.: ubuntu24.04)
virsh domifaddr ubuntu
ssh -i ~/.ssh/kvm gean@<ip>
# Limpeza
virsh undefine --domain ubuntu --nvram
sudo rm /datastore/images/demo.qcow2
storage: layoutds=nocloud-net usado no boot