Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Containerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ FROM ghcr.io/ublue-os/bazzite:stable

## Other possible base images include:
# FROM ghcr.io/ublue-os/bazzite:latest
# FROM ghcr.io/ublue-os/bluefin-nvidia:stable
# FROM ghcr.io/ublue-os/bluefin:stable
# FROM ghcr.io/ublue-os/aurora:stable
#
# ... and so on, here are more base images
# Universal Blue Images: https://github.com/orgs/ublue-os/packages
# Fedora base image: quay.io/fedora/fedora-bootc:41
# CentOS base images: quay.io/centos-bootc/centos-bootc:stream10
#
# NOTE: For Nvidia support, see Containerfile.nvidia and README.md

### MODIFICATIONS
## make modifications desired in your image and install packages by modifying the build.sh script
Expand Down
70 changes: 70 additions & 0 deletions Containerfile.nvidia
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Example Containerfile with Nvidia support
# This shows how to add Nvidia drivers to any base image

# Allow build scripts to be referenced without being copied into the final image
FROM scratch AS ctx
COPY build_files /

# Your base image - can be any Universal Blue or Fedora image
ARG BASE_IMAGE="${BASE_IMAGE:-ghcr.io/ublue-os/bazzite:stable}"
ARG KERNEL_FLAVOR="${KERNEL_FLAVOR:-fsync}"
ARG FEDORA_VERSION="${FEDORA_VERSION:-42}"
# IMPORTANT: The kernel version must match your base image's kernel
# Check available versions at: https://github.com/orgs/ublue-os/packages/container/package/akmods-nvidia
ARG KERNEL_VERSION="${KERNEL_VERSION:-6.16.4-102.fsync.fc42.x86_64}"

# Import nvidia akmods - this provides the compiled Nvidia kernel modules
FROM ghcr.io/ublue-os/akmods-nvidia:${KERNEL_FLAVOR}-${FEDORA_VERSION}-${KERNEL_VERSION} AS nvidia-akmods

# Base stage - your customizations
FROM ${BASE_IMAGE} AS base

ARG IMAGE_NAME="${IMAGE_NAME:-base}"
ARG FEDORA_VERSION="${FEDORA_VERSION:-42}"

### MODIFICATIONS
## make modifications desired in your image and install packages by modifying the build.sh script
## the following RUN directive does all the things required to run "build.sh" as recommended.

RUN --mount=type=bind,from=ctx,source=/,target=/ctx \
--mount=type=cache,dst=/var/cache \
--mount=type=cache,dst=/var/log \
--mount=type=tmpfs,dst=/tmp \
/ctx/build.sh

# Nvidia stage - add nvidia drivers
FROM base AS nvidia

ARG IMAGE_NAME="${IMAGE_NAME:-base}"
ARG KERNEL_VERSION="${KERNEL_VERSION:-6.16.4-102.fsync.fc42.x86_64}"

# Remove packages that conflict with Nvidia
# These are typically AMD GPU firmware and drivers
RUN --mount=type=cache,dst=/var/cache \
--mount=type=cache,dst=/var/log \
--mount=type=bind,from=ctx,source=/,target=/ctx \
--mount=type=tmpfs,dst=/tmp \
dnf5 config-manager unsetopt skip_if_unavailable && \
dnf5 -y remove \
nvidia-gpu-firmware \
rocm-hip \
rocm-opencl \
rocm-clinfo \
rocm-smi || true

# Install Nvidia drivers
RUN --mount=type=cache,dst=/var/cache \
--mount=type=cache,dst=/var/log \
--mount=type=bind,from=ctx,source=/,target=/ctx \
--mount=type=bind,from=nvidia-akmods,src=/rpms,dst=/tmp/akmods-rpms \
--mount=type=tmpfs,dst=/tmp \
--mount=type=secret,id=GITHUB_TOKEN \
/ctx/ghcurl "https://raw.githubusercontent.com/ublue-os/main/refs/heads/main/build_files/nvidia-install.sh" --retry 3 -Lo /tmp/nvidia-install.sh && \
chmod +x /tmp/nvidia-install.sh && \
IMAGE_NAME="${IMAGE_NAME}" /tmp/nvidia-install.sh && \
rm -f /usr/share/vulkan/icd.d/nouveau_icd.*.json && \
ln -s libnvidia-ml.so.1 /usr/lib64/libnvidia-ml.so

### LINTING
## Verify final image and contents are correct.
RUN bootc container lint
118 changes: 118 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,124 @@ The [build.sh](./build_files/build.sh) file is called from your Containerfile. I

The [build.yml](./.github/workflows/build.yml) Github Actions workflow creates your custom OCI image and publishes it to the Github Container Registry (GHCR). By default, the image name will match the Github repository name. There are several environment variables at the start of the workflow which may be of interest to change.

# Adding Nvidia Driver Support

Universal Blue's dedicated Nvidia images (`ublue-os/*-nvidia`) have been deprecated following [community vote](https://github.com/ublue-os/main/issues/927). Users can now add Nvidia support to any base image using the method below.

## How to Add Nvidia Drivers

This template includes the necessary scripts to add Nvidia driver support to your custom image. The implementation follows the same approach used by Bazzite and other Universal Blue projects.

### Option 1: Use the Example Containerfile

The easiest way to add Nvidia support is to use the example [Containerfile.nvidia](./Containerfile.nvidia) as a reference. This file demonstrates the complete setup needed to add Nvidia drivers.

Key components:
1. Import the nvidia akmods for your kernel
2. Remove conflicting packages (nvidia-gpu-firmware, rocm packages)
3. Run the nvidia-install.sh script to install drivers

### Option 2: Modify Your Existing Containerfile

To add Nvidia support to your existing Containerfile, you need to:

1. **Add build arguments** at the top of your Containerfile:
```dockerfile
ARG KERNEL_FLAVOR="${KERNEL_FLAVOR:-fsync}"
ARG FEDORA_VERSION="${FEDORA_VERSION:-42}"
ARG KERNEL_VERSION="${KERNEL_VERSION:-6.16.4-102.fsync.fc42.x86_64}"
```

2. **Import nvidia akmods** before your base image:
```dockerfile
FROM ghcr.io/ublue-os/akmods-nvidia:${KERNEL_FLAVOR}-${FEDORA_VERSION}-${KERNEL_VERSION} AS nvidia-akmods
```

3. **Add a nvidia stage** after your main customizations:
```dockerfile
FROM base AS nvidia

# Remove conflicting packages
RUN --mount=type=cache,dst=/var/cache \
--mount=type=cache,dst=/var/log \
--mount=type=bind,from=ctx,source=/,target=/ctx \
--mount=type=tmpfs,dst=/tmp \
dnf5 -y remove \
nvidia-gpu-firmware \
rocm-hip \
rocm-opencl \
rocm-clinfo \
rocm-smi || true

# Install Nvidia drivers
RUN --mount=type=cache,dst=/var/cache \
--mount=type=cache,dst=/var/log \
--mount=type=bind,from=ctx,source=/,target=/ctx \
--mount=type=bind,from=nvidia-akmods,src=/rpms,dst=/tmp/akmods-rpms \
--mount=type=tmpfs,dst=/tmp \
--mount=type=secret,id=GITHUB_TOKEN \
/ctx/ghcurl "https://raw.githubusercontent.com/ublue-os/main/refs/heads/main/build_files/nvidia-install.sh" --retry 3 -Lo /tmp/nvidia-install.sh && \
chmod +x /tmp/nvidia-install.sh && \
IMAGE_NAME="${IMAGE_NAME}" /tmp/nvidia-install.sh && \
rm -f /usr/share/vulkan/icd.d/nouveau_icd.*.json && \
ln -s libnvidia-ml.so.1 /usr/lib64/libnvidia-ml.so
```

### Important Notes

- **Kernel Version**: The `KERNEL_VERSION` must match the kernel in your base image. You can find available versions at the [akmods-nvidia packages page](https://github.com/orgs/ublue-os/packages/container/package/akmods-nvidia).

To find the kernel version in your base image, you can inspect it:
```bash
podman run --rm <your-base-image:tag> rpm -q kernel
# Example: podman run --rm ghcr.io/ublue-os/bazzite:stable rpm -q kernel
```

- **Kernel Flavor**: Common kernel flavors include:
- `fsync` - Standard Universal Blue kernel with fsync patches
- `bazzite` - Bazzite's gaming-optimized kernel
- `main` - Standard Fedora kernel

- **IMAGE_NAME**: Set this to match your base image type (e.g., `kinoite`, `silverblue`) to get the appropriate GPU management tools (supergfxctl).

- **Build Arguments**: You can override these values during build:
```bash
podman build --build-arg KERNEL_VERSION=6.16.4-102.fsync.fc42.x86_64 .
```

### Available Scripts

This template includes helper scripts in the `build_files` directory:

- **nvidia-install.sh**: Main script that installs Nvidia drivers and configures the system
- **ghcurl**: Helper script for authenticated GitHub API requests (handles rate limiting)

These scripts are maintained to match the implementation used by Universal Blue's main projects.

### Verifying Your Setup

After building your image with Nvidia support:

1. Switch to your image: `sudo bootc switch ghcr.io/<username>/<image_name>`
2. Reboot your system
3. Verify the drivers are loaded: `nvidia-smi`
4. Check kernel modules: `lsmod | grep nvidia`

### Troubleshooting

**Build fails with "kmod-nvidia version does not match nvidia-driver version"**
- This means the kernel version in your base image doesn't match the akmods version you're using
- Solution: Check the kernel version in your base image and update the `KERNEL_VERSION` build argument

**Image builds but nvidia-smi shows "No devices found"**
- Verify your system has an Nvidia GPU installed
- Check if the nouveau driver is loaded instead: `lsmod | grep nouveau`
- If nouveau is loaded, you may need to add `modprobe.blacklist=nouveau` to your kernel parameters

**Missing supergfxctl tools**
- Make sure you set `IMAGE_NAME` to match your desktop environment (`kinoite` or `silverblue`)
- For other desktops, these tools are optional and may not be available

# Building Disk Images

This template provides an out of the box workflow for creating disk images (ISO, qcow, raw) for your custom OCI image which can be used to directly install onto your machines.
Expand Down
32 changes: 32 additions & 0 deletions build_files/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Build Files

This directory contains helper scripts used during the container image build process.

## Scripts

### build.sh
Main build script that runs during the container build. Add your customizations here:
- Install packages with `dnf5 install`
- Enable system services with `systemctl enable`
- Copy configuration files
- Run other setup commands

### nvidia-install.sh
Installs Nvidia drivers into the image. This script:
- Removes conflicting packages (nvidia-gpu-firmware, rocm packages)
- Installs Nvidia driver packages from the akmods repository
- Configures the system for Nvidia GPU support
- Sets up proper kernel module loading

**Note**: This script is automatically downloaded from ublue-os/main during the build process to ensure you always get the latest version. The version in this repository is provided as a reference.

### ghcurl
Helper script for making authenticated requests to GitHub API. This helps avoid rate limiting when downloading files from GitHub during the build process.

## Nvidia Support

To add Nvidia support to your image, see:
- [Containerfile.nvidia](../Containerfile.nvidia) - Example Containerfile with Nvidia drivers
- [README.md](../README.md#adding-nvidia-driver-support) - Full documentation on adding Nvidia support

The Nvidia implementation in this template matches the approach used by [ublue-os/bazzite](https://github.com/ublue-os/bazzite) and other Universal Blue projects.
22 changes: 22 additions & 0 deletions build_files/ghcurl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -euo pipefail

# Check for GITHUB_TOKEN in /run/secrets/GITHUB_TOKEN (Podman secret mount)
if [[ -f /run/secrets/GITHUB_TOKEN ]]; then
GITHUB_TOKEN=$(< /run/secrets/GITHUB_TOKEN)
echo "Using GITHUB_TOKEN from /run/secrets/GITHUB_TOKEN for authentication." >&2
AUTH_HEADER="Authorization: Bearer $GITHUB_TOKEN"
else
echo "GITHUB_TOKEN secret not found. Using unauthenticated requests." >&2
AUTH_HEADER=""
fi

URL="$1"
shift
OPTIONS=("$@")

if [[ -n "$AUTH_HEADER" ]]; then
curl -sSL -H "$AUTH_HEADER" "${OPTIONS[@]}" "$URL"
else
curl -sSL "${OPTIONS[@]}" "$URL"
fi
121 changes: 121 additions & 0 deletions build_files/nvidia-install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#!/bin/bash

set -ouex pipefail

RELEASE="$(rpm -E %fedora)"
: "${AKMODNV_PATH:=/tmp/akmods-rpms}"

# this is only to aid in human understanding of any issues in CI
find "${AKMODNV_PATH}"/

if ! command -v dnf5 >/dev/null; then
echo "Requires dnf5... Exiting"
exit 1
fi

# Check if any rpmfusion repos exist before trying to disable them
if dnf5 repolist --all | grep -q rpmfusion; then
dnf5 config-manager setopt "rpmfusion*".enabled=0
fi

# Always try to disable cisco repo (or add similar check)
dnf5 config-manager setopt fedora-cisco-openh264.enabled=0

## nvidia install steps
dnf5 install -y "${AKMODNV_PATH}"/ublue-os/ublue-os-nvidia-addons-*.rpm

# Install MULTILIB packages from negativo17-multimedia prior to disabling repo

MULTILIB=(
mesa-dri-drivers.i686
mesa-filesystem.i686
mesa-libEGL.i686
mesa-libGL.i686
mesa-libgbm.i686
mesa-va-drivers.i686
mesa-vulkan-drivers.i686
)

if [[ "$(rpm -E %fedora)" -lt 41 ]]; then
MULTILIB+=(
mesa-libglapi.i686
libvdpau.i686
)
fi

dnf5 install -y "${MULTILIB[@]}"

# enable repos provided by ublue-os-nvidia-addons
dnf5 config-manager setopt fedora-nvidia.enabled=1 nvidia-container-toolkit.enabled=1

# Disable Multimedia
NEGATIVO17_MULT_PREV_ENABLED=N
if dnf5 repolist --enabled | grep -q "fedora-multimedia"; then
NEGATIVO17_MULT_PREV_ENABLED=Y
echo "disabling negativo17-fedora-multimedia to ensure negativo17-fedora-nvidia is used"
dnf5 config-manager setopt fedora-multimedia.enabled=0
fi

# Enable staging for supergfxctl if repo file exists
if [[ -f /etc/yum.repos.d/_copr_ublue-os-staging.repo ]]; then
sed -i 's@enabled=0@enabled=1@g' /etc/yum.repos.d/_copr_ublue-os-staging.repo
else
# Otherwise, retrieve the repo file for staging
curl -Lo /etc/yum.repos.d/_copr_ublue-os-staging.repo https://copr.fedorainfracloud.org/coprs/ublue-os/staging/repo/fedora-"${RELEASE}"/ublue-os-staging-fedora-"${RELEASE}".repo
fi

source "${AKMODNV_PATH}"/kmods/nvidia-vars

if [[ "${IMAGE_NAME}" == "kinoite" ]]; then
VARIANT_PKGS="supergfxctl-plasmoid supergfxctl"
elif [[ "${IMAGE_NAME}" == "silverblue" ]]; then
VARIANT_PKGS="gnome-shell-extension-supergfxctl-gex supergfxctl"
else
VARIANT_PKGS=""
fi

dnf5 install -y \
libnvidia-fbc \
libnvidia-ml.i686 \
libva-nvidia-driver \
nvidia-driver \
nvidia-driver-cuda \
nvidia-driver-cuda-libs.i686 \
nvidia-driver-libs.i686 \
nvidia-settings \
nvidia-container-toolkit ${VARIANT_PKGS:-} \
"${AKMODNV_PATH}"/kmods/kmod-nvidia-"${KERNEL_VERSION}"-"${NVIDIA_AKMOD_VERSION}"."${DIST_ARCH}".rpm

# Ensure the version of the Nvidia module matches the driver
KMOD_VERSION="$(rpm -q --queryformat '%{VERSION}' kmod-nvidia)"
DRIVER_VERSION="$(rpm -q --queryformat '%{VERSION}' nvidia-driver)"
if [ "$KMOD_VERSION" != "$DRIVER_VERSION" ]; then
echo "Error: kmod-nvidia version ($KMOD_VERSION) does not match nvidia-driver version ($DRIVER_VERSION)"
exit 1
fi

## nvidia post-install steps
# disable repos provided by ublue-os-nvidia-addons
dnf5 config-manager setopt fedora-nvidia.enabled=0 nvidia-container-toolkit.enabled=0

# Disable staging
sed -i 's@enabled=1@enabled=0@g' /etc/yum.repos.d/_copr_ublue-os-staging.repo

# ensure kernel.conf matches NVIDIA_FLAVOR (which must be nvidia or nvidia-open)
# kmod-nvidia-common defaults to 'nvidia-open' but this will match our akmod image
sed -i "s/^MODULE_VARIANT=.*/MODULE_VARIANT=$KERNEL_MODULE_TYPE/" /etc/nvidia/kernel.conf

systemctl enable ublue-nvctk-cdi.service
semodule --verbose --install /usr/share/selinux/packages/nvidia-container.pp

# Universal Blue specific Initramfs fixes
cp /etc/modprobe.d/nvidia-modeset.conf /usr/lib/modprobe.d/nvidia-modeset.conf
# we must force driver load to fix black screen on boot for nvidia desktops
sed -i 's@omit_drivers@force_drivers@g' /usr/lib/dracut/dracut.conf.d/99-nvidia.conf
# as we need forced load, also mustpre-load intel/amd iGPU else chromium web browsers fail to use hardware acceleration
sed -i 's@ nvidia @ i915 amdgpu nvidia @g' /usr/lib/dracut/dracut.conf.d/99-nvidia.conf

# re-enable negativo17-mutlimedia since we disabled it
if [[ "${NEGATIVO17_MULT_PREV_ENABLED}" = "Y" ]]; then
dnf5 config-manager setopt fedora-multimedia.enabled=1
fi