Package Layering & Image Customization
TunaOS is an immutable operating system managed by bootc. TunaOS mounts /usr read-only at runtime. That keeps your system stable, predictable, and safe to roll back.
This guide explains how to install software and customize your TunaOS installation:
- When to use Flatpak, Homebrew, or container environments.
- How to use
bootc usr-overlayfor transient debugging. - How to build a derived bootc image, then switch to it.
- How to manage kernel arguments and boot configurations.
Choosing the Right Customization Methodβ
Before you change the base image, choose the lightest method that fits your use case:
| Use Case | Recommended Method | Example |
|---|---|---|
| Desktop applications | Flatpak | flatpak install flathub org.mozilla.firefox |
| Command-line tools & utilities | Homebrew | brew install ripgrep neovim starship |
| Development libraries & compilers | Toolbox / Distrobox | toolbox create && toolbox enter |
| Temporary debugging / troubleshooting | bootc usr-overlay | sudo bootc usr-overlay && sudo dnf install strace |
| Permanent system daemons, kernel modules, base packages | Derived bootc image | FROM ghcr.io/tuna-os/albacore:latest Containerfile |
Transient Customization: bootc usr-overlayβ
When you need temporary access to tools like strace, gdb, or tcpdump on the host, use bootc usr-overlay.
bootc usr-overlay sets up a writable overlayfs on /usr for the current boot session:
# Enable writable overlay on /usr
sudo bootc usr-overlay
# Install debugging packages using the native package manager
sudo dnf install -y strace tcpdump
All modifications made to /usr through bootc usr-overlay disappear when you reboot the system.
However, /etc and /var are persistent writable directories on TunaOS. Configuration files and application data under /etc or /var stay in place after a reboot.
Persistent Customization: Building a Derived Imageβ
bootc has no in-place bootc layer add command. To make a change persistent on bootc, you build a derived container image.
A derived image gives you three things:
- Full reproducibility: Your entire OS definition lives in a Git repository and
Containerfile. - Atomic updates and rollbacks: If an update or a package breaks the system,
sudo bootc rollbackputs the last good state back. - Supply-chain control: You can build, test, and scan the image in CI before it reaches hardware.
Step 1: Create a Containerfileβ
Create a Containerfile that starts FROM an official TunaOS base:
FROM ghcr.io/tuna-os/albacore:latest
# Install additional packages into the image
RUN dnf install -y \
zsh \
tmux \
wireguard-tools \
&& dnf clean all
# Copy custom systemd service files or scripts
COPY my-custom-daemon.service /etc/systemd/system/
RUN systemctl enable my-custom-daemon.service
Step 2: Build and Push the Container Imageβ
Build the container image using Podman and push it to a container registry (such as GitHub Packages, Quay.io, or Docker Hub):
# Build the image
podman build -t quay.io/myusername/my-tunaos:latest .
# Push to your registry
podman push quay.io/myusername/my-tunaos:latest
Step 3: Switch Your System to the Derived Imageβ
Use bootc switch to rebase your operating system to your new image:
# Switch to the custom image
sudo bootc switch quay.io/myusername/my-tunaos:latest
# Reboot into the custom deployment
sudo systemctl reboot
To pull and stage a later build of your image:
sudo bootc upgrade
sudo systemctl reboot
Kernel Arguments (kargs.d)β
On bootc you do not edit the GRUB configuration to change a kernel argument. The arguments live in the image, in TOML files under /usr/lib/bootc/kargs.d/. bootc reads them when it stages a deployment, so a rollback takes the old arguments back with it.
Kernel Arguments in an Imageβ
A build script, an overlay, or a package drops a TOML file into /usr/lib/bootc/kargs.d/.
The TunaOS NVIDIA overlay is a live example. It writes /usr/lib/bootc/kargs.d/00-nvidia.toml:
kargs = ["rd.driver.blacklist=nouveau", "modprobe.blacklist=nouveau", "nvidia-drm.modeset=1"]
To add your own argument, write the same kind of file in your Containerfile:
RUN mkdir -p /usr/lib/bootc/kargs.d && \
printf 'kargs = ["intel_iommu=on"]\n' > /usr/lib/bootc/kargs.d/10-custom.toml
Build the image, bootc switch to it, then reboot. The new argument is on the next boot.
Inspect the Boot Entriesβ
To see the deployments bootc knows about, and the boot loader state behind them:
# Deployments: booted, staged, and rollback
bootc status
# UEFI and systemd-boot state
bootctl status
# The kernel command line of the running system
cat /proc/cmdline
Rollback & Status Inspectionβ
You can view all staged, active, and rollback deployments with bootc status:
bootc status
If an updated image fails or causes issues, roll back to the previous deployment at any time:
# Roll back to the previous deployment
sudo bootc rollback
# Reboot into the previous image
sudo systemctl reboot