Skip to content

Golden Images with Packer

Packer is a powerful tool for automating the creation of machine images across multiple platforms. This blog post will help you set up Packer to build custom images for both x86 and ARM64 architectures.

Installation

Packer supports both x86 and arm64 architectures. We've provided an installation function that detects distro / cpu architecture and installs the appropriate packages.

bash
source <(curl -fsSL https://raw.githubusercontent.com/michielvha/PDS/main/bash/common/software/hashicorp.sh)
install_packer

If you are not on linux or you just prefer the official installation guide you may find it here.

Creating Images with our Packer Templates

Packer Template Structure

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

Cloud-init Configuration

The Cloud-init configuration is packed into the image as a virtual CD-ROM (ISO):y

  • The cd_files directive specifies the path to the user-data and meta-data files.
  • The cd_label is set to cidata, which Cloud-Init expects for NoCloud configuration.
  • When the VM boots, Cloud-Init reads these files to configure the instance.

Extra Provisioning Scripts

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

You can use our provided scripts or create your own.

Build Instructions

To build the image:

bash
cd build/packer/ubuntu-cloud-image/
sudo packer init
sudo packer build -var-file=variables.pkrvars.hcl .

TIP

Add the following alias to your shell config to make your life easier: 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-$distro directory.

Testing & Troubleshooting

Connect to image via VNC during build

If you're on a Linux system with graphical capabilities:

  1. Install TigerVNC Viewer:

    bash
    sudo apt-get install tigervnc-viewer   # Ubuntu/Debian
    sudo dnf install tigervnc              # Fedora
  2. Connect to the VNC server:

    bash
    vncviewer 127.0.0.1:5956

SSH Tunnel for Remote Shell Use

For headless environments, tunnel VNC through SSH:

  1. Create an SSH tunnel:

    bash
    ssh -N -L 5956:127.0.0.1:5956 remote_user@remote_host
  2. Connect via VNC locally:

    bash
    vncviewer 127.0.0.1:5956
  3. For Windows users: Use MobaXterm as VNC viewer.

Troubleshoot image after creation

Use QEMU to Boot Images

The way to boot the images varies slightly depending on the os architecture.

bash
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
bash
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=

Shell Access via chroot

To inspect the image filesystem without booting:

  1. Create a mount directory:

    bash
    sudo mkdir /mnt/image
  2. Mount the image:

    bash
    sudo mount -o loop /path/to/your/image.raw /mnt/image

    For images with multiple partitions:

    bash
    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
  3. Enter chroot environment:

    bash
    sudo chroot /mnt/image /bin/bash
  4. Exit and unmount:

    bash
    exit
    sudo umount /mnt/image

Advanced Topics

Automating Future Builds

TODO: show extended integrations here once finished

Once you have your Packer templates configured, you can automate builds through CI/CD pipelines:

  • Use GitHub Actions or Equivalent to trigger builds when configurations change
  • Schedule regular builds to incorporate security updates
  • Implement testing frameworks to validate image functionality