Robert Szczepanowski
Robert Szczepanowski
Senior Software Engineer

Missing files in your Packer built image? You might be skipping graceful shutdowns.

May 28, 20252 min read

Are your files and folders missing after you run the newly created image? This is a common issue when building images with Packer. It is a widely used tool for creating machine images in a repeatable and automated way. When using the QEMU builder to generate local or CI-friendly images, it's common to upload files with the file provisioner and configure systems using shell provisioner. One often overlooked but critical part of this workflow is how the virtual machine shuts down after provisioning. Without a proper shutdown, the resulting image can be unstable, incomplete, or even unbootable.

Let’s see why graceful shutdowns matter.

After provisioning completes, Packer snapshots the virtual disk to produce the final image. If the guest operating system is not properly shut down before this snapshot, you risk file system corruption, lost configuration changes, services failing to start, or persistent files missing entirely - especially those written during the final steps of provisioning. These issues often go unnoticed until the image is deployed in staging or production environments, where the consequences are far more disruptive.

By default, the shutdown_command is set to an empty string (""). This means Packer does not attempt a clean shutdown unless you explicitly configure one. Instead, the virtual machine is forcefully terminated, which is equivalent to abruptly cutting power on a physical machine - a common cause of data loss and image inconsistency.

To prevent this, you must define a shutdown_command that instructs the OS to shut down safely after provisioning. This ensures that services have time to stop, file operations complete, and the system reaches a stable state before the image is captured.

Correct usage of shutdown_command

A clean shutdown requires a properly formed command with the necessary privileges, and the exact command you use depends on the operating system inside the virtual machine. Most Linux distributions support the shutdown command, but the syntax, required privileges, and available tools can vary slightly.

Here’s a reliable example in HCL2 for a Debian/Ubuntu based image:

... shutdown_command = "echo 'packer' | sudo --stdin shutdown --poweroff now" ...

This command assumes the use of a user with password-based sudo access. It triggers a privileged system shutdown, allowing services to stop cleanly and file buffers to flush before power-off. The --poweroff flag ensures the machine actually powers off, which is essential for clean termination when using virtual hardware emulation. Adjust the password to match your base image setup.

If you're using a different base image - such as CentOS, RHEL, or Alpine - the shutdown binary might be located elsewhere, require different flags, or use an alternative like poweroff or halt. You may also need to configure sudoers to avoid prompts or password issues during provisioning.

Always test the shutdown command interactively inside a VM before inserting it into your template. It should work silently and reliably in the automated provisioning context.

Conclusion

To sum up, graceful shutdowns are a necessary safeguard when building machine images with the QEMU builder in Packer. Skipping this step or relying on Packer’s default behavior (which can forcibly terminate the VM) introduces the risk of unstable and corrupted images. By using a proper shutdown_command, you ensure the system shuts down in a controlled way, preserving the integrity of the file system and producing a clean, bootable image.

This practice is simple to implement and greatly improves reliability in both development and production environments. If you're managing CI pipelines or building images for downstream automation, it's a foundational step that prevents subtle and costly failures later in the lifecycle.

RELATED POSTS
Maciej Łopalewski
Maciej Łopalewski
Senior Software Engineer

Boost Your Medusa E-Commerce Development: Streamlined Local Setup Guide

May 22, 20253 min read
Article image
Daniel Kraszewski
Daniel Kraszewski
Head of Engineering

Exposing Private Load Balancers with CloudFront VPC Origins

Apr 30, 20254 min read
Article image
Michał Miler
Michał Miler
Senior Software Engineer

Passing Dynamic Environment Variables Between GitLab CI Matrix Jobs: AWS OIDC Example

Apr 09, 20254 min read
Article image