From c03c6c96ad4b71aa98050a000ec81bc168d5929a Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Sat, 9 May 2026 16:34:13 +0000 Subject: [PATCH] ci: add pre-built base-grpc-builder image infrastructure (PR 1/2) Introduces a parameterized Dockerfile.base-grpc-builder that produces a fully-prepped builder base image (apt deps + protoc + cmake + gRPC at /opt/grpc + conditional CUDA/ROCm/Vulkan toolchains) and a base-images.yml workflow that builds + pushes 9 variants to quay.io/go-skynet/ci-cache:base-grpc-*: base-grpc-amd64 (Ubuntu 24.04, CPU-only) base-grpc-arm64 (Ubuntu 24.04, CPU-only) base-grpc-cuda-12-amd64 (Ubuntu 24.04 + CUDA 12.8) base-grpc-cuda-13-amd64 (Ubuntu 22.04 + CUDA 13.0) base-grpc-cuda-13-arm64 (Ubuntu 24.04 + CUDA 13.0 sbsa) base-grpc-rocm-amd64 (rocm/dev-ubuntu-24.04:7.2.1 + hipblas) base-grpc-vulkan-amd64 (Ubuntu 24.04 + Vulkan SDK 1.4.335) base-grpc-vulkan-arm64 (Ubuntu 24.04 + Vulkan SDK ARM 1.4.335) base-grpc-intel-amd64 (intel/oneapi-basekit:2025.3.2) The variant Dockerfiles (Dockerfile.llama-cpp, ik-llama-cpp, turboquant) are NOT touched in this PR. PR 2 will refactor them to FROM these prebuilt bases. This PR is intentionally inert - landing it changes no existing CI behavior. The base images don't exist on quay until someone manually triggers the workflow. Bootstrap after merge: gh workflow run base-images.yml --ref master Wait ~30 min for all 9 variants to push, then merge PR 2 (the consumer-side refactor that uses BUILDER_BASE_IMAGE build-arg to FROM these tags). Triggers afterwards: - Saturdays 05:00 UTC (cron) - picks up upstream security updates, runs ~24h before the backend.yml Sunday cron so bases are fresh. - workflow_dispatch - manual ad-hoc rebuild. - master push touching Dockerfile.base-grpc-builder or this workflow. Why split into two PRs: the variant Dockerfiles in PR 2 will FROM the prebuilt bases and have no from-source fallback. Their CI builds fail if the bases don't exist on quay yet. Landing infrastructure first + manual bootstrap + then consumer refactor avoids a broken-master window. Assisted-by: Claude:claude-opus-4-7 Signed-off-by: Ettore Di Giacinto --- .github/workflows/base-images.yml | 138 ++++++++++++++ backend/Dockerfile.base-grpc-builder | 268 +++++++++++++++++++++++++++ 2 files changed, 406 insertions(+) create mode 100644 .github/workflows/base-images.yml create mode 100644 backend/Dockerfile.base-grpc-builder diff --git a/.github/workflows/base-images.yml b/.github/workflows/base-images.yml new file mode 100644 index 000000000000..a8baece3c1f8 --- /dev/null +++ b/.github/workflows/base-images.yml @@ -0,0 +1,138 @@ +--- +name: 'build base-grpc images' + +# Builds + pushes pre-compiled builder base images that downstream +# llama-cpp / ik-llama-cpp / turboquant variant Dockerfiles will FROM +# (PR 2). Each base contains apt deps + protoc + cmake + gRPC at +# /opt/grpc + (conditionally) CUDA / ROCm / Vulkan toolchains. +# +# Triggers: +# - schedule (Saturdays 05:00 UTC) - picks up Ubuntu/CUDA/ROCm +# security updates and re-runs ahead of the backend.yml weekly +# cron (Sundays 06:00 UTC). +# - workflow_dispatch - manual one-off rebuild. +# - push to master that touches Dockerfile.base-grpc-builder or +# this workflow itself - keeps bases in sync with their inputs. +# +# Bootstrap (one-time after this PR merges): +# gh workflow run base-images.yml --ref master +# Wait ~30 min for all 9 matrix variants to push to +# quay.io/go-skynet/ci-cache:base-grpc-* before merging PR 2. + +on: + schedule: + - cron: '0 5 * * 6' + workflow_dispatch: + push: + branches: [master] + paths: + - 'backend/Dockerfile.base-grpc-builder' + - '.github/workflows/base-images.yml' + +concurrency: + group: ci-base-images-${{ github.event.pull_request.number || github.sha }}-${{ github.repository }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +jobs: + build: + if: github.repository == 'mudler/LocalAI' + runs-on: ${{ matrix.runs-on }} + strategy: + fail-fast: false + matrix: + include: + - tag: 'base-grpc-amd64' + runs-on: 'ubuntu-latest' + base-image: 'ubuntu:24.04' + build-type: '' + cuda-major-version: '' + cuda-minor-version: '' + ubuntu-version: '2404' + - tag: 'base-grpc-arm64' + runs-on: 'ubuntu-24.04-arm' + base-image: 'ubuntu:24.04' + build-type: '' + cuda-major-version: '' + cuda-minor-version: '' + ubuntu-version: '2404' + - tag: 'base-grpc-cuda-12-amd64' + runs-on: 'ubuntu-latest' + base-image: 'ubuntu:24.04' + build-type: 'cublas' + cuda-major-version: '12' + cuda-minor-version: '8' + ubuntu-version: '2404' + - tag: 'base-grpc-cuda-13-amd64' + runs-on: 'ubuntu-latest' + base-image: 'ubuntu:22.04' + build-type: 'cublas' + cuda-major-version: '13' + cuda-minor-version: '0' + ubuntu-version: '2204' + - tag: 'base-grpc-cuda-13-arm64' + runs-on: 'ubuntu-24.04-arm' + base-image: 'ubuntu:24.04' + build-type: 'cublas' + cuda-major-version: '13' + cuda-minor-version: '0' + ubuntu-version: '2404' + - tag: 'base-grpc-rocm-amd64' + runs-on: 'ubuntu-latest' + base-image: 'rocm/dev-ubuntu-24.04:7.2.1' + build-type: 'hipblas' + cuda-major-version: '' + cuda-minor-version: '' + ubuntu-version: '2404' + - tag: 'base-grpc-vulkan-amd64' + runs-on: 'ubuntu-latest' + base-image: 'ubuntu:24.04' + build-type: 'vulkan' + cuda-major-version: '' + cuda-minor-version: '' + ubuntu-version: '2404' + - tag: 'base-grpc-vulkan-arm64' + runs-on: 'ubuntu-24.04-arm' + base-image: 'ubuntu:24.04' + build-type: 'vulkan' + cuda-major-version: '' + cuda-minor-version: '' + ubuntu-version: '2404' + - tag: 'base-grpc-intel-amd64' + runs-on: 'ubuntu-latest' + base-image: 'intel/oneapi-basekit:2025.3.2-0-devel-ubuntu24.04' + build-type: 'sycl' + cuda-major-version: '' + cuda-minor-version: '' + ubuntu-version: '2404' + steps: + - uses: actions/checkout@v6 + with: + submodules: false + - name: Free disk space + uses: ./.github/actions/free-disk-space + - name: Set up build disk + uses: ./.github/actions/setup-build-disk + - uses: docker/setup-qemu-action@master + with: + platforms: all + - uses: docker/setup-buildx-action@master + - uses: docker/login-action@v4 + with: + registry: quay.io + username: ${{ secrets.LOCALAI_REGISTRY_USERNAME }} + password: ${{ secrets.LOCALAI_REGISTRY_PASSWORD }} + - uses: docker/build-push-action@v7 + with: + context: . + file: ./backend/Dockerfile.base-grpc-builder + build-args: | + BASE_IMAGE=${{ matrix.base-image }} + BUILD_TYPE=${{ matrix.build-type }} + CUDA_MAJOR_VERSION=${{ matrix.cuda-major-version }} + CUDA_MINOR_VERSION=${{ matrix.cuda-minor-version }} + UBUNTU_VERSION=${{ matrix.ubuntu-version }} + cache-from: type=registry,ref=quay.io/go-skynet/ci-cache:cache-${{ matrix.tag }} + cache-to: type=registry,ref=quay.io/go-skynet/ci-cache:cache-${{ matrix.tag }},mode=max,ignore-error=true + provenance: false + tags: quay.io/go-skynet/ci-cache:${{ matrix.tag }} + push: true diff --git a/backend/Dockerfile.base-grpc-builder b/backend/Dockerfile.base-grpc-builder new file mode 100644 index 000000000000..ab1b6eadf3c6 --- /dev/null +++ b/backend/Dockerfile.base-grpc-builder @@ -0,0 +1,268 @@ +# syntax=docker/dockerfile:1.7 +# +# Pre-built builder base image for LocalAI's C++ backends. +# +# This Dockerfile is the source of truth for the +# `quay.io/go-skynet/ci-cache:base-grpc-*` images that +# `.github/workflows/base-images.yml` builds and pushes. The output of a +# build is a fully-prepped builder layer containing: +# +# - apt build deps (build-essential, ccache, git, make, pkg-config, +# libcurl4-openssl-dev, libssl-dev, curl, unzip, wget, ca-certificates) +# - cmake (apt or, when CMAKE_FROM_SOURCE=true, compiled from +# ${CMAKE_VERSION}) +# - protoc v27.1 at /usr/local/bin/protoc +# - gRPC ${GRPC_VERSION} compiled and installed at /opt/grpc +# - Conditional CUDA toolkit (BUILD_TYPE=cublas|l4t, SKIP_DRIVERS=false) +# including the cuda-13 + arm64 cudss/nvpl special case +# - Conditional ROCm/HIP build deps (BUILD_TYPE=hipblas) +# - Conditional Vulkan SDK 1.4.335.0 (BUILD_TYPE=vulkan) +# +# Variants built by the workflow (matrix in base-images.yml): +# +# base-grpc-amd64 ubuntu:24.04, CPU-only +# base-grpc-arm64 ubuntu:24.04, CPU-only +# base-grpc-cuda-12-amd64 ubuntu:24.04 + CUDA 12.8 +# base-grpc-cuda-13-amd64 ubuntu:22.04 + CUDA 13.0 +# base-grpc-cuda-13-arm64 ubuntu:24.04 + CUDA 13.0 (sbsa) +# base-grpc-rocm-amd64 rocm/dev-ubuntu-24.04:7.2.1 + hipblas +# base-grpc-vulkan-amd64 ubuntu:24.04 + Vulkan SDK 1.4.335 +# base-grpc-vulkan-arm64 ubuntu:24.04 + Vulkan SDK ARM 1.4.335 +# base-grpc-intel-amd64 intel/oneapi-basekit:2025.3.2 (sycl) +# +# This is a SINGLE-stage Dockerfile by design: the final image IS the +# builder base. The intermediate gRPC compile happens inside this same +# stage so consumer Dockerfiles in PR 2 can simply +# `FROM quay.io/go-skynet/ci-cache:base-grpc-` without needing a +# COPY --from=grpc step. /opt/grpc is the canonical install prefix and +# downstream builds will add it to CMAKE_PREFIX_PATH (or copy to +# /usr/local) the same way Dockerfile.llama-cpp does today. +# +# Install logic is copied verbatim from backend/Dockerfile.llama-cpp on +# master so the resulting image is bit-identical to what the variant +# Dockerfile produces today. Do not paraphrase apt invocations — PR 2 +# depends on bit-equivalence. + +ARG BASE_IMAGE=ubuntu:24.04 + +FROM ${BASE_IMAGE} + +ARG BASE_IMAGE=ubuntu:24.04 +ARG BUILD_TYPE="" +ARG CUDA_MAJOR_VERSION="" +ARG CUDA_MINOR_VERSION="" +ARG CMAKE_FROM_SOURCE=false +# CUDA Toolkit 13.x compatibility: CMake 3.31.9+ fixes toolchain +# detection / arch table issues. +ARG CMAKE_VERSION=3.31.10 +ARG GRPC_VERSION=v1.65.0 +ARG GRPC_MAKEFLAGS="-j4 -Otarget" +ARG SKIP_DRIVERS=false +ARG TARGETARCH +ARG UBUNTU_VERSION=2404 +ARG APT_MIRROR="" +ARG APT_PORTS_MIRROR="" +ARG AMDGPU_TARGETS="" + +ENV BUILD_TYPE=${BUILD_TYPE} +ENV CUDA_MAJOR_VERSION=${CUDA_MAJOR_VERSION} +ENV CUDA_MINOR_VERSION=${CUDA_MINOR_VERSION} +ENV AMDGPU_TARGETS=${AMDGPU_TARGETS} +ENV MAKEFLAGS=${GRPC_MAKEFLAGS} +ENV DEBIAN_FRONTEND=noninteractive + +# CUDA on PATH (no-op when CUDA isn't installed) +ENV PATH=/usr/local/cuda/bin:${PATH} +# HipBLAS / ROCm on PATH (no-op when ROCm isn't installed) +ENV PATH=/opt/rocm/bin:${PATH} + +WORKDIR /build + +# Base apt build deps. Mirrors backend/Dockerfile.llama-cpp lines 85-97 +# (the `builder` stage's apt block) — superset of the gRPC stage's deps +# so the same image can compile gRPC and downstream backends. +RUN --mount=type=bind,source=.docker/apt-mirror.sh,target=/usr/local/sbin/apt-mirror \ + APT_MIRROR="${APT_MIRROR}" APT_PORTS_MIRROR="${APT_PORTS_MIRROR}" sh /usr/local/sbin/apt-mirror && \ + apt-get update && \ + apt-get install -y --no-install-recommends \ + build-essential \ + ccache git \ + ca-certificates \ + make \ + pkg-config libcurl4-openssl-dev \ + curl unzip \ + libssl-dev wget && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# Vulkan SDK install. Mirrors backend/Dockerfile.llama-cpp lines 107-154. +RUN </dev/null || ls /opt/rocm*/lib64/rocblas/library/Kernels* 2>/dev/null) | grep -oP 'gfx[0-9a-z+-]+' | sort -u || \ + echo "WARNING: No rocBLAS kernel data found" \ + ; fi + +RUN echo "TARGETARCH: $TARGETARCH" + +# protoc download. Mirrors backend/Dockerfile.llama-cpp lines 237-248. +# We need protoc installed, and the version in 22.04 is too old. We will create one as part of installing the GRPC build below +# but that will also bring in a newer version of absl which stablediffusion cannot compile with. This version of protoc is only +# here so that we can generate the grpc code for the stablediffusion build. +RUN < /usr/local exactly like +# `COPY --from=grpc /opt/grpc /usr/local` does today. +# +# We install GRPC to a different prefix here so that we can copy in only the build artifacts later +# saves several hundred MB on the final docker image size vs copying in the entire GRPC source tree +# and running make install in the target container +RUN git clone --recurse-submodules --jobs 4 -b ${GRPC_VERSION} --depth 1 --shallow-submodules https://github.com/grpc/grpc && \ + mkdir -p /build/grpc/cmake/build && \ + cd /build/grpc/cmake/build && \ + sed -i "216i\ TESTONLY" "../../third_party/abseil-cpp/absl/container/CMakeLists.txt" && \ + cmake -DgRPC_INSTALL=ON -DgRPC_BUILD_TESTS=OFF -DCMAKE_INSTALL_PREFIX:PATH=/opt/grpc ../.. && \ + make && \ + make install && \ + rm -rf /build + +WORKDIR /