This repository provides Packer templates and scripts for building linux images, specifically tailored for use with cloud-init and automation tools. The goal is to create a streamlined process for generating ready-to-use images that can be deployed in various environments. This is great for organisations that need to maintain consistent and secure base images across their infrastructure (golden image concept).
Packer can be installed on both x86 and ARM64 architectures. The recommended installation method uses Hashicorp's official package repositories with dynamic architecture detection.
# Install required packages
sudo apt install -y wget curl gnupg software-properties-common
# Add HashiCorp GPG key and repository
wget -O - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
# Install Packer and required QEMU packages
sudo apt update
sudo apt install -y packer
# Install architecture-specific dependencies
if [ "$(dpkg --print-architecture)" = "amd64" ]; then
# x86 (amd64) specific packages
sudo apt install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virtinst virt-manager genisoimage guestfs-tools
else
# ARM64 specific packages
sudo apt install -y qemu-system-arm qemu-system-aarch64 qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virtinst virt-manager genisoimage guestfs-tools
fi
# Install QEMU plugin for Packer
sudo packer plugins install github.com/hashicorp/qemu
Note
The installation scripts auto-detect your system architecture and install the appropriate packages. For non-Debian based distributions, adjust the package installation commands accordingly.
Our Packer templates define how to build custom images. Key components include:
- Source Configuration: Specifies the base image, VM settings, and QEMU parameters
- Build Configuration: Defines provisioners for customization and post-processors for output format
- Variable Definitions: Parameters that can be customized per build
The Cloud-init configuration is packed into the image as a virtual CD-ROM (ISO):y
- The
cd_files
directive specifies the path to theuser-data
andmeta-data
files. - The
cd_label
is set tocidata
, which Cloud-Init expects for NoCloud configuration. - When the VM boots, Cloud-Init reads these files to configure the instance.
In addition to Cloud-init, we use shell scripts to perform additional customization:
- Install packages
- Configure system settings
- Set up custom motd messages
- Any other specialized configuration needed
To build the image:
cd build/packer/ubuntu-cloud-image/
sudo packer init
sudo packer build -var-file=variables.pkrvars.hcl .
# Tip: Add this alias to your shell config
# alias pb='sudo packer build -var-file=variables.pkrvars.hcl .'
After running the Packer build, you'll find the final raw image in the output-ubuntu-image
directory.
If you're on a Linux system with graphical capabilities:
-
Install TigerVNC Viewer:
sudo apt-get install tigervnc-viewer # Ubuntu/Debian sudo dnf install tigervnc # Fedora
-
Connect to the VNC server:
vncviewer 127.0.0.1:5956
For headless environments, tunnel VNC through SSH:
-
Create an SSH tunnel:
ssh -N -L 5956:127.0.0.1:5956 remote_user@remote_host
-
Connect via VNC locally:
vncviewer 127.0.0.1:5956
-
For Windows users: Use MobaXterm as VNC viewer.
To boot and access the shell of an x86 image:
sudo qemu-system-x86_64 \
-drive file=/path/to/output-noble/ubuntu-noble.img,format=qcow2 \
-smp cores=4,sockets=1 \
-m 4G \
-net nic -net user,hostfwd=tcp::2222-:22 \
-nographic
To boot an ARM64 image with QEMU:
sudo qemu-system-aarch64 -m 2048 -cpu cortex-a72 \
-M virt \
-drive file=/path/to/armbian-image.img,format=raw \
-serial mon:stdio \
-netdev user,id=user.0 \
-device virtio-net,netdev=user.0,romfile=
To inspect the image filesystem without booting:
-
Create a mount directory:
sudo mkdir /mnt/image
-
Mount the image:
sudo mount -o loop /path/to/your/image.raw /mnt/image
For images with multiple partitions:
sudo fdisk -l /path/to/your/image.img # Find partition offset # Calculate offset: start_sector * 512 sudo mount -o loop,offset=<calculated_offset> /path/to/your/image.img /mnt/image
-
Enter chroot environment:
sudo chroot /mnt/image /bin/bash
-
Exit and unmount:
exit sudo umount /mnt/image