Files
llama-swap/.github/workflows/unified-docker.yml
T
Benson WongandGitHub e31a1adee4 Split Docker build into per-project stages for CI (#1071)
Big refactor to split the build stages for the unified container to be built in parallel. 

- parallel building of binaries to speed up full container build (~6+hr to 1.5hr) 
- split cuda and vulkan pipelines to be independent (vulkan is much faster)
- establish pattern for building building binaries for final image (easier to add new resources)
- use llama-swap-build for build containers to avoid untagged clean up script

Fixes: #1069
2026-08-30 11:57:20 -07:00

159 lines
6.0 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 (CUDA only)"
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 image"
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 backend 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.
jobs:
setup:
runs-on: ubuntu-latest
outputs:
build_cuda: ${{ steps.plan.outputs.build_cuda }}
build_vulkan: ${{ steps.plan.outputs.build_vulkan }}
cuda_projects: ${{ steps.plan.outputs.cuda_projects }}
vulkan_projects: ${{ steps.plan.outputs.vulkan_projects }}
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 backends
id: plan
run: |
# schedule uses defaults (build both, push); workflow_dispatch respects inputs
if [[ "${{ github.event_name }}" == "schedule" ]]; then
build_cuda=true; build_vulkan=true; push=true
else
build_cuda="${{ inputs.build_cuda }}"
build_vulkan="${{ inputs.build_vulkan }}"
push="${{ inputs.push_to_ghcr }}"
fi
{
echo "build_cuda=${build_cuda}"
echo "build_vulkan=${build_vulkan}"
echo "push_to_ghcr=${push}"
# ik_llama.cpp has no Vulkan build.
echo 'cuda_projects=["whisper","sd","audio","llama","ik-llama"]'
echo 'vulkan_projects=["whisper","sd","audio","llama"]'
} >> "$GITHUB_OUTPUT"
cuda:
needs: setup
if: ${{ needs.setup.outputs.build_cuda == 'true' }}
uses: ./.github/workflows/unified-docker-backend.yml
permissions:
contents: read
packages: write
with:
backend: cuda
projects: ${{ needs.setup.outputs.cuda_projects }}
push_to_ghcr: ${{ needs.setup.outputs.push_to_ghcr == 'true' }}
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:
needs: setup
if: ${{ needs.setup.outputs.build_vulkan == 'true' }}
uses: ./.github/workflows/unified-docker-backend.yml
permissions:
contents: read
packages: write
with:
backend: vulkan
projects: ${{ needs.setup.outputs.vulkan_projects }}
push_to_ghcr: ${{ needs.setup.outputs.push_to_ghcr == 'true' }}
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 }}