A Go-based image builder that wraps buildah to create layered OS images with support for multiple package managers. It is the next-generation replacement for the Python-based image-builder tool used by OpenCHAMI.
- Multiple package managers — DNF, Zypper, APT (parent builds only), mmdebstrap (scratch builds only)
- Scratch & parent builds — build from
scratchor layer on top of an existing image - Multi-arch manifests — one template, one manifest, per-arch expansion with automatic tag pinning
- Declarative YAML config with a
validatesubcommand - Multiple publishers — local container storage, SquashFS, container registry, S3
- OpenSCAP scanning — XCCDF benchmarks + OVAL vulnerability evaluation
- Structured logging — JSON or text, configurable levels
The pre-built unified image includes every supported package manager.
podman pull ghcr.io/openchami/image-thrillhouse:latestSee docs/container-usage.md for the full podman run invocation and flag explanations.
Grab the .rpm for your architecture from the latest release and install it:
sudo dnf install ./image-thrillhouse-<version>.<arch>.rpmbuildah is a hard dependency; squashfs-tools and podman are recommended/suggested.
Grab the .deb for your architecture from the latest release and install it:
sudo apt install ./image-thrillhouse_<version>_<arch>.debbuildah is a hard dependency; squashfs-tools is recommended and podman is suggested.
For development or unsupported platforms, see docs/development.md.
Save the following as rocky-base.yaml:
meta:
name: rocky-base
tags:
- "9.5"
from: scratch
layer:
manager:
name: dnf
options:
releasever: "9" # required for DNF scratch builds
config: |
[main]
gpgcheck=1
reposdir=/etc/image-thrillhouse/yum.repos.d
repos:
- path: /etc/image-thrillhouse/yum.repos.d/rocky-baseos.repo
content: |
[rocky-baseos]
name=rocky-baseos
baseurl=https://dl.rockylinux.org/pub/rocky/9/BaseOS/x86_64/os
enabled=1
gpgcheck=1
gpgkey=https://dl.rockylinux.org/pub/rocky/RPM-GPG-KEY-Rocky-9
actions:
install:
packages:
- kernel
- systemd
publish:
- type: localValidate, then build:
image-thrillhouse validate --config rocky-base.yaml
image-thrillhouse build --config rocky-base.yaml --log-level infovalidate checks YAML syntax, required fields, backend option names/values, and publisher config — useful in CI before a full build.
The publish section is a list, so you can fan out to multiple targets in one build. To produce a bootable SquashFS file alongside the local image:
publish:
- type: local
- type: squashfs
path: /output/images # writes <meta.name>-<meta.tags[0]>.squashfsFor registry and S3 targets, see docs/configuration.md#publish.
image-thrillhouse build --config <path> # build a single image
image-thrillhouse build --manifest <path> --layer <name> # build one layer from a manifest
image-thrillhouse validate --config <path> # validate config without building
image-thrillhouse version # print version infoFor multi-arch manifests, pass --arch <x86_64|aarch64|…>; it defaults to the host arch. See Manifests for the full manifest schema.
Global flags:
--log-level—debug|info|warn|error(defaultinfo).debugadds build detail (created containers, written files, full package lists) without container-runtime internals.--log-format—json|text|textblock(defaulttextblock)--container-debug— also emit debug output from the container runtime libraries (buildah, containers/storage). Very verbose; mainly useful for diagnosing storage, mount, or isolation problems.
- Start with
validate. Runimage-thrillhouse validatein CI before any build — it catches typos in backend options and missing required fields before you pay for a long package download. - Use the unified container. It already has DNF, Zypper, APT, and mmdebstrap. Switching distros is a config change, not an image change. See docs/container-usage.md.
- Always set
releaseverfor DNF scratch builds. This is the most common scratch-build failure mode. See docs/configuration.md. - Use
remove_packagesto slim images. Drop debug packages, docs, and unused firmware in the same step that installs the base — see docs/configuration.md#package-removal. - Pin image tags in production. Use
ghcr.io/openchami/image-thrillhouse:v0.1.0rather than:latestfor reproducible builds.
- Configuration reference — every field in the YAML, with examples
- Container usage — running the pre-built image, flag explanations, multi-version DNF
- Package manager support — backend feature matrix
- Example configs — annotated index of
tests/configs - Development — building, testing, architecture, adding backends/publishers
- Troubleshooting — common errors
- Migration from the Python image-builder
- Unit testing guide
- Buildah — container building tool
- Podman — container runtime
- OpenCHAMI — HPC cluster management (original use case)
Issues and PRs are welcome. Areas of interest include additional package managers (pacman, apk, …), additional publishers (Azure, GCP, …), broader test coverage, and build-time optimization.
This project is licensed under the MIT License.
It is REUSE compliant: every file carries an SPDX
license header (or is covered by REUSE.toml), and compliance is
checked in CI via the REUSE Compliance Check
workflow. To check locally, install the reuse
tool and run reuse lint.
The majority of the documentation and some of the code was written by Claude Sonnet 4.5 (training cutoff September 29, 2025). All generated content has been verified and tested.