mirror of
https://github.com/mostlygeek/llama-swap.git
synced 2026-09-07 16:37:22 +02:00
Key changes: - add cuda13 container for Ampere to Blackwell GPUs - support DGX Spark (GB10) with arm64 cuda 13 manifests - enable ik_llama on vulkan container - map `LLAMA_SWAP_*` env vars to llama-server CLI flags with backwards support - refactor GHA/docker build to accept variants closes: #905, #1066 supercedes: PR #841, PR #1084
276 lines
11 KiB
YAML
276 lines
11 KiB
YAML
name: Build Unified Docker Image
|
|
|
|
on:
|
|
schedule:
|
|
- cron: "37 5 * * *"
|
|
|
|
workflow_dispatch:
|
|
inputs:
|
|
llama_cpp_ref:
|
|
description: "llama.cpp commit hash, tag, or branch"
|
|
required: false
|
|
default: "master"
|
|
whisper_ref:
|
|
description: "whisper.cpp commit hash, tag, or branch"
|
|
required: false
|
|
default: "master"
|
|
sd_ref:
|
|
description: "stable-diffusion.cpp commit hash, tag, or branch"
|
|
required: false
|
|
default: "master"
|
|
audio_ref:
|
|
description: "audio.cpp commit hash, tag, or branch"
|
|
required: false
|
|
default: "main"
|
|
ik_llama_ref:
|
|
description: "ik_llama.cpp commit hash, tag, or branch"
|
|
required: false
|
|
default: "main"
|
|
llama_swap_version:
|
|
description: "llama-swap version (e.g. v198, latest, main)"
|
|
required: false
|
|
default: "main"
|
|
build_cuda:
|
|
description: "Build CUDA 12 image (Pascal through Ada)"
|
|
type: boolean
|
|
required: false
|
|
default: true
|
|
build_cuda13:
|
|
description: "Build CUDA 13 image (Ampere through Blackwell)"
|
|
type: boolean
|
|
required: false
|
|
default: true
|
|
build_arm64:
|
|
description: "Include linux/arm64 in the CUDA 13 image (NVIDIA GB10 / DGX Spark)"
|
|
type: boolean
|
|
required: false
|
|
default: true
|
|
build_vulkan:
|
|
description: "Build Vulkan image"
|
|
type: boolean
|
|
required: false
|
|
default: true
|
|
push_to_ghcr:
|
|
description: "Push the unified images to ghcr.io (per-project artifacts images are always pushed; they are how the build stages reach the assemble job)"
|
|
type: boolean
|
|
required: false
|
|
default: true
|
|
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
|
|
# The build is one Dockerfile per piece: a builder base per backend, one per
|
|
# upstream project, and the runtime. Each compiles in its own job and publishes
|
|
# an image; a final job copies the /install trees into the unified image.
|
|
#
|
|
# Building everything in one job put five concurrent CUDA compiles on a
|
|
# four-core runner, which stopped fitting in the 6h job limit; a cancelled job
|
|
# also never reached --cache-to, so nothing was cached and every later run
|
|
# rebuilt from scratch. Images are addressed by content -- the base by its
|
|
# Dockerfile, a project by its upstream commit plus its own two files and the
|
|
# base tag -- so anything unchanged is skipped, and one project overrunning no
|
|
# longer discards the others.
|
|
#
|
|
# Each variant runs as its own call to unified-docker-backend.yml, so Vulkan
|
|
# publishes as soon as its own projects finish rather than waiting on the
|
|
# multi-hour CUDA compiles.
|
|
#
|
|
# There are two CUDA variants. cuda is CUDA 12 compiled for Pascal through Ada;
|
|
# cuda13 is CUDA 13 compiled for Ampere through Blackwell. CUDA 13 removed
|
|
# Maxwell, Pascal and Volta from nvcc, so the older cards need an image of their
|
|
# own. They share every Dockerfile and install script -- only CUDA_VERSION and
|
|
# CMAKE_CUDA_ARCHITECTURES differ, and the builder base tag is keyed on both, so
|
|
# each variant gets its own base and artifacts images and neither invalidates
|
|
# the other.
|
|
#
|
|
# cuda13 is also the only variant built for linux/arm64. NVIDIA's GB10 -- the
|
|
# Blackwell GPU in DGX Spark -- sits next to a Grace CPU, so aarch64 is the only
|
|
# way to reach it, and its sm_121 needs a CUDA 13 nvcc. Every other NVIDIA arm64
|
|
# part is a Grace pairing too, so there is nothing for an arm64 CUDA 12 image to
|
|
# run on, and no arm64 GPU that the Vulkan image would serve. Each platform is a
|
|
# separate matrix cell over the backend workflow, compiled natively on a runner
|
|
# of that architecture; a manifest job then joins them into the tag users pull.
|
|
jobs:
|
|
setup:
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
build_cuda: ${{ steps.plan.outputs.build_cuda }}
|
|
build_cuda13: ${{ steps.plan.outputs.build_cuda13 }}
|
|
build_vulkan: ${{ steps.plan.outputs.build_vulkan }}
|
|
cuda_projects: ${{ steps.plan.outputs.cuda_projects }}
|
|
vulkan_projects: ${{ steps.plan.outputs.vulkan_projects }}
|
|
amd64_only: ${{ steps.plan.outputs.amd64_only }}
|
|
cuda13_platforms: ${{ steps.plan.outputs.cuda13_platforms }}
|
|
date_tag: ${{ steps.plan.outputs.date_tag }}
|
|
push_to_ghcr: ${{ steps.plan.outputs.push_to_ghcr }}
|
|
llama_hash: ${{ steps.refs.outputs.llama_hash }}
|
|
whisper_hash: ${{ steps.refs.outputs.whisper_hash }}
|
|
sd_hash: ${{ steps.refs.outputs.sd_hash }}
|
|
audio_hash: ${{ steps.refs.outputs.audio_hash }}
|
|
ik_llama_hash: ${{ steps.refs.outputs.ik_llama_hash }}
|
|
ls_hash: ${{ steps.refs.outputs.ls_hash }}
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
|
|
|
|
# Resolve every ref once, here. The build and assemble jobs are handed
|
|
# full commit hashes, so a branch that moves mid-run cannot leave two
|
|
# jobs building different revisions of the same project.
|
|
- name: Resolve upstream commits
|
|
id: refs
|
|
env:
|
|
LLAMA_REF: ${{ inputs.llama_cpp_ref || 'master' }}
|
|
WHISPER_REF: ${{ inputs.whisper_ref || 'master' }}
|
|
SD_REF: ${{ inputs.sd_ref || 'master' }}
|
|
AUDIO_REF: ${{ inputs.audio_ref || 'main' }}
|
|
IK_LLAMA_REF: ${{ inputs.ik_llama_ref || 'main' }}
|
|
LS_VERSION: ${{ inputs.llama_swap_version || 'main' }}
|
|
run: |
|
|
chmod +x docker/unified/build-image.sh
|
|
docker/unified/build-image.sh --cuda --resolve | tee -a "$GITHUB_OUTPUT"
|
|
|
|
- name: Plan variants
|
|
id: plan
|
|
run: |
|
|
# schedule uses defaults (build all, push); workflow_dispatch respects inputs
|
|
if [[ "${{ github.event_name }}" == "schedule" ]]; then
|
|
build_cuda=true; build_cuda13=true; build_vulkan=true
|
|
build_arm64=true; push=true
|
|
else
|
|
build_cuda="${{ inputs.build_cuda }}"
|
|
build_cuda13="${{ inputs.build_cuda13 }}"
|
|
build_vulkan="${{ inputs.build_vulkan }}"
|
|
build_arm64="${{ inputs.build_arm64 }}"
|
|
push="${{ inputs.push_to_ghcr }}"
|
|
fi
|
|
|
|
# cuda and vulkan are amd64 only; cuda13 adds arm64 for GB10.
|
|
if [[ "${build_arm64}" == "true" ]]; then
|
|
cuda13_platforms='["linux/amd64","linux/arm64"]'
|
|
else
|
|
cuda13_platforms='["linux/amd64"]'
|
|
fi
|
|
|
|
{
|
|
echo "build_cuda=${build_cuda}"
|
|
echo "build_cuda13=${build_cuda13}"
|
|
echo "build_vulkan=${build_vulkan}"
|
|
echo "push_to_ghcr=${push}"
|
|
echo 'cuda_projects=["whisper","sd","audio","llama","ik-llama"]'
|
|
echo 'vulkan_projects=["whisper","sd","audio","llama","ik-llama"]'
|
|
echo 'amd64_only=["linux/amd64"]'
|
|
echo "cuda13_platforms=${cuda13_platforms}"
|
|
# Resolved once so every platform's image and the manifest that
|
|
# joins them carry the same date, even across UTC midnight.
|
|
echo "date_tag=$(date -u +%Y-%m-%d)"
|
|
} >> "$GITHUB_OUTPUT"
|
|
|
|
cuda:
|
|
needs: setup
|
|
if: ${{ needs.setup.outputs.build_cuda == 'true' }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
platform: ${{ fromJSON(needs.setup.outputs.amd64_only) }}
|
|
uses: ./.github/workflows/unified-docker-backend.yml
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
with:
|
|
variant: cuda
|
|
platform: ${{ matrix.platform }}
|
|
projects: ${{ needs.setup.outputs.cuda_projects }}
|
|
push_to_ghcr: ${{ needs.setup.outputs.push_to_ghcr == 'true' }}
|
|
date_tag: ${{ needs.setup.outputs.date_tag }}
|
|
llama_hash: ${{ needs.setup.outputs.llama_hash }}
|
|
whisper_hash: ${{ needs.setup.outputs.whisper_hash }}
|
|
sd_hash: ${{ needs.setup.outputs.sd_hash }}
|
|
audio_hash: ${{ needs.setup.outputs.audio_hash }}
|
|
ik_llama_hash: ${{ needs.setup.outputs.ik_llama_hash }}
|
|
ls_hash: ${{ needs.setup.outputs.ls_hash }}
|
|
|
|
cuda-manifest:
|
|
needs: [setup, cuda]
|
|
if: ${{ needs.setup.outputs.build_cuda == 'true' && needs.setup.outputs.push_to_ghcr == 'true' }}
|
|
uses: ./.github/workflows/unified-docker-manifest.yml
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
with:
|
|
variant: cuda
|
|
platforms: ${{ needs.setup.outputs.amd64_only }}
|
|
date_tag: ${{ needs.setup.outputs.date_tag }}
|
|
|
|
cuda13:
|
|
needs: setup
|
|
if: ${{ needs.setup.outputs.build_cuda13 == 'true' }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
platform: ${{ fromJSON(needs.setup.outputs.cuda13_platforms) }}
|
|
uses: ./.github/workflows/unified-docker-backend.yml
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
with:
|
|
variant: cuda13
|
|
platform: ${{ matrix.platform }}
|
|
projects: ${{ needs.setup.outputs.cuda_projects }}
|
|
push_to_ghcr: ${{ needs.setup.outputs.push_to_ghcr == 'true' }}
|
|
date_tag: ${{ needs.setup.outputs.date_tag }}
|
|
llama_hash: ${{ needs.setup.outputs.llama_hash }}
|
|
whisper_hash: ${{ needs.setup.outputs.whisper_hash }}
|
|
sd_hash: ${{ needs.setup.outputs.sd_hash }}
|
|
audio_hash: ${{ needs.setup.outputs.audio_hash }}
|
|
ik_llama_hash: ${{ needs.setup.outputs.ik_llama_hash }}
|
|
ls_hash: ${{ needs.setup.outputs.ls_hash }}
|
|
|
|
cuda13-manifest:
|
|
needs: [setup, cuda13]
|
|
if: ${{ needs.setup.outputs.build_cuda13 == 'true' && needs.setup.outputs.push_to_ghcr == 'true' }}
|
|
uses: ./.github/workflows/unified-docker-manifest.yml
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
with:
|
|
variant: cuda13
|
|
platforms: ${{ needs.setup.outputs.cuda13_platforms }}
|
|
date_tag: ${{ needs.setup.outputs.date_tag }}
|
|
|
|
vulkan:
|
|
needs: setup
|
|
if: ${{ needs.setup.outputs.build_vulkan == 'true' }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
platform: ${{ fromJSON(needs.setup.outputs.amd64_only) }}
|
|
uses: ./.github/workflows/unified-docker-backend.yml
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
with:
|
|
variant: vulkan
|
|
platform: ${{ matrix.platform }}
|
|
projects: ${{ needs.setup.outputs.vulkan_projects }}
|
|
push_to_ghcr: ${{ needs.setup.outputs.push_to_ghcr == 'true' }}
|
|
date_tag: ${{ needs.setup.outputs.date_tag }}
|
|
llama_hash: ${{ needs.setup.outputs.llama_hash }}
|
|
whisper_hash: ${{ needs.setup.outputs.whisper_hash }}
|
|
sd_hash: ${{ needs.setup.outputs.sd_hash }}
|
|
audio_hash: ${{ needs.setup.outputs.audio_hash }}
|
|
ik_llama_hash: ${{ needs.setup.outputs.ik_llama_hash }}
|
|
ls_hash: ${{ needs.setup.outputs.ls_hash }}
|
|
|
|
vulkan-manifest:
|
|
needs: [setup, vulkan]
|
|
if: ${{ needs.setup.outputs.build_vulkan == 'true' && needs.setup.outputs.push_to_ghcr == 'true' }}
|
|
uses: ./.github/workflows/unified-docker-manifest.yml
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
with:
|
|
variant: vulkan
|
|
platforms: ${{ needs.setup.outputs.amd64_only }}
|
|
date_tag: ${{ needs.setup.outputs.date_tag }}
|