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
21 changes: 15 additions & 6 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,18 @@ concurrency:

jobs:
build_push:
name: Build and push image
name: Build and push image (${{ matrix.flavor.name || 'base' }})
runs-on: ubuntu-24.04

strategy:
fail-fast: false
matrix:
flavor:
- name: ""
suffix: ""
- name: "nvidia"
suffix: "-nvidia"

permissions:
contents: read
packages: write
Expand Down Expand Up @@ -110,9 +119,9 @@ jobs:
with:
containerfiles: |
./Containerfile
# Postfix image name with -custom to make it a little more descriptive
# Syntax: https://docs.github.com/en/actions/learn-github-actions/expressions#format
image: ${{ env.IMAGE_NAME }}
build-args: |
BUILD_FLAVOR=${{ matrix.flavor.name }}
image: ${{ env.IMAGE_NAME }}${{ matrix.flavor.suffix }}
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
oci: false
Expand Down Expand Up @@ -160,7 +169,7 @@ jobs:
REGISTRY_PASSWORD: ${{ github.token }}
with:
registry: ${{ env.IMAGE_REGISTRY }}
image: ${{ env.IMAGE_NAME }}
image: ${{ env.IMAGE_NAME }}${{ matrix.flavor.suffix }}
tags: ${{ steps.metadata.outputs.tags }}
username: ${{ env.REGISTRY_USER }}
password: ${{ env.REGISTRY_PASSWORD }}
Expand All @@ -178,7 +187,7 @@ jobs:
- name: Sign container image
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
run: |
IMAGE_FULL="${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}"
IMAGE_FULL="${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.flavor.suffix }}"
for tag in ${{ steps.metadata.outputs.tags }}; do
cosign sign -y --key env://COSIGN_PRIVATE_KEY $IMAGE_FULL:$tag
done
Expand Down
14 changes: 13 additions & 1 deletion Containerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,16 @@
FROM scratch AS ctx
COPY build_files /

# NVIDIA drivers from ublue-os akmods
FROM ghcr.io/ublue-os/akmods-nvidia-open:main-43 AS akmods-nvidia

ARG BUILD_FLAVOR="${BUILD_FLAVOR:-}"

# Base Image
FROM ghcr.io/ublue-os/bazzite:stable

ARG BUILD_FLAVOR

## Other possible base images include:
# FROM ghcr.io/ublue-os/bazzite:latest
# FROM ghcr.io/ublue-os/bluefin-nvidia:stable
Expand All @@ -25,6 +32,10 @@ FROM ghcr.io/ublue-os/bazzite:stable

# RUN rm /opt && mkdir /opt

### NVIDIA DRIVERS
## Copy pre-built NVIDIA drivers from akmods layer (only used when BUILD_FLAVOR=nvidia)
COPY --from=akmods-nvidia / /usr/share/akmods

### 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.
Expand All @@ -33,7 +44,8 @@ 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
/ctx/build.sh && \
BUILD_FLAVOR="${BUILD_FLAVOR}" /ctx/nvidia.sh

### LINTING
## Verify final image and contents are correct.
Expand Down
31 changes: 31 additions & 0 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,29 @@ build-raw $target_image=("localhost/" + image_name) $tag=default_tag: && (_build
[group('Build Virtal Machine Image')]
build-iso $target_image=("localhost/" + image_name) $tag=default_tag: && (_build-bib target_image tag "iso" "disk_config/iso.toml")

# Build NVIDIA variant
[group('Build NVIDIA Variant')]
build-nvidia $target_image=("localhost/" + image_name + "-nvidia") $tag=default_tag:
#!/usr/bin/env bash
BUILD_ARGS=()
BUILD_ARGS+=("--build-arg" "BUILD_FLAVOR=nvidia")
if [[ -z "$(git status -s)" ]]; then
BUILD_ARGS+=("--build-arg" "SHA_HEAD_SHORT=$(git rev-parse --short HEAD)")
fi
podman build \
"${BUILD_ARGS[@]}" \
--pull=newer \
--tag "${target_image}:${tag}" \
.

# Build a QCOW2 virtual machine image (NVIDIA variant)
[group('Build NVIDIA Variant')]
build-qcow2-nvidia $target_image=("localhost/" + image_name + "-nvidia") $tag=default_tag: build-nvidia && (_build-bib target_image tag "qcow2" "disk_config/disk.toml")

# Build an ISO virtual machine image (NVIDIA variant)
[group('Build NVIDIA Variant')]
build-iso-nvidia $target_image=("localhost/" + image_name + "-nvidia") $tag=default_tag: build-nvidia && (_build-bib target_image tag "iso" "disk_config/iso-nvidia.toml")

# Rebuild a QCOW2 virtual machine image
[group('Build Virtal Machine Image')]
rebuild-qcow2 $target_image=("localhost/" + image_name) $tag=default_tag: && (_rebuild-bib target_image tag "qcow2" "disk_config/disk.toml")
Expand Down Expand Up @@ -275,6 +298,14 @@ run-vm-raw $target_image=("localhost/" + image_name) $tag=default_tag: && (_run-
[group('Run Virtal Machine')]
run-vm-iso $target_image=("localhost/" + image_name) $tag=default_tag: && (_run-vm target_image tag "iso" "disk_config/iso.toml")

# Run a virtual machine from an NVIDIA QCOW2 image
[group('Run NVIDIA Variant')]
run-vm-qcow2-nvidia $target_image=("localhost/" + image_name + "-nvidia") $tag=default_tag: && (_run-vm target_image tag "qcow2" "disk_config/disk.toml")

# Run a virtual machine from an NVIDIA ISO
[group('Run NVIDIA Variant')]
run-vm-iso-nvidia $target_image=("localhost/" + image_name + "-nvidia") $tag=default_tag: && (_run-vm target_image tag "iso" "disk_config/iso-nvidia.toml")

# Run a virtual machine using systemd-vmspawn
[group('Run Virtal Machine')]
spawn-vm rebuild="0" type="qcow2" ram="6G":
Expand Down
66 changes: 66 additions & 0 deletions build_files/nvidia.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/env bash

if [[ ! "${BUILD_FLAVOR:-}" =~ "nvidia" ]]; then
exit 0
fi

set -xeuo pipefail

# Install pre-built nvidia-open drivers from ublue-os akmods
# These RPMs are copied from ghcr.io/ublue-os/akmods-nvidia-open in the Containerfile

dnf5 install -y /usr/share/akmods/rpms/ublue-os/ublue-os-nvidia*.rpm
dnf5 install -y /usr/share/akmods/rpms/kmods/kmod-nvidia*.rpm

dnf5 install -y \
nvidia-gpu-firmware \
libva-nvidia-driver

dnf5 install -y nvidia-container-toolkit

curl --retry 3 -L https://raw.githubusercontent.com/NVIDIA/dgx-selinux/master/bin/RHEL9/nvidia-container.pp -o nvidia-container.pp
semodule -i nvidia-container.pp
rm -f nvidia-container.pp

# Blacklist nouveau driver
tee /usr/lib/modprobe.d/00-nouveau-blacklist.conf <<'EOF'
blacklist nouveau
options nouveau modeset=0
EOF

# Configure kernel boot arguments for NVIDIA
tee /usr/lib/bootc/kargs.d/00-nvidia.toml <<'EOF'
kargs = ["rd.driver.blacklist=nouveau", "modprobe.blacklist=nouveau", "nvidia-drm.modeset=1"]
EOF

# Configure dracut for NVIDIA driver loading
# Force-load NVIDIA drivers and pre-load iGPU drivers for hardware acceleration
if [[ -f /usr/lib/dracut/dracut.conf.d/99-nvidia.conf ]]; then
sed -i 's/omit_drivers/force_drivers/g' /usr/lib/dracut/dracut.conf.d/99-nvidia.conf
sed -i 's/ nvidia / i915 amdgpu nvidia /g' /usr/lib/dracut/dracut.conf.d/99-nvidia.conf
fi

# Move modprobe config to system location if it exists
if [[ -f /etc/modprobe.d/nvidia-modeset.conf ]]; then
mv /etc/modprobe.d/nvidia-modeset.conf /usr/lib/modprobe.d/nvidia-modeset.conf
fi

# Create systemd service for NVIDIA Container Toolkit CDI generation
tee /usr/lib/systemd/system/nvctk-cdi.service <<'EOF'
[Unit]
Description=NVIDIA Container Toolkit CDI auto-generation
ConditionFileIsExecutable=/usr/bin/nvidia-ctk
After=local-fs.target

[Service]
Type=oneshot
ExecStart=/usr/bin/nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml

[Install]
WantedBy=multi-user.target
EOF

systemctl enable nvctk-cdi.service

# Clean up copied akmods RPMs
rm -rf /usr/share/akmods
20 changes: 20 additions & 0 deletions disk_config/iso-nvidia.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[customizations.installer.kickstart]
contents = """
%post
bootc switch --mutate-in-place --transport registry ghcr.io/ublue-os/image-template-nvidia:latest
%end
"""

[customizations.installer.modules]
enable = [
"org.fedoraproject.Anaconda.Modules.Storage",
"org.fedoraproject.Anaconda.Modules.Runtime"
]
disable = [
"org.fedoraproject.Anaconda.Modules.Network",
"org.fedoraproject.Anaconda.Modules.Security",
"org.fedoraproject.Anaconda.Modules.Services",
"org.fedoraproject.Anaconda.Modules.Users",
"org.fedoraproject.Anaconda.Modules.Subscription",
"org.fedoraproject.Anaconda.Modules.Timezone"
]