Skip to content

feat: k8s support and some fixes #317

feat: k8s support and some fixes

feat: k8s support and some fixes #317

Workflow file for this run

name: Create and publish Docker images
on:
workflow_dispatch:
workflow_call:
inputs:
tag_suffix:
description: 'Custom tag suffix for the Docker image'
required: false
type: string
default: ''
is_nightly:
description: 'Whether this is a nightly build'
required: false
type: boolean
default: false
use_cross_compilation:
description: "Use cross-compilation instead of emulation for ARM64"
required: false
type: boolean
default: true
push:
branches: [ "main" ]
pull_request:
paths:
- ".github/workflows/docker-publish.yml"
- "Dockerfile*"
- "candle-binding/**"
- "src/**"
- "e2e-tests/llm-katan/**"
jobs:
# Build job for multi-architecture Docker images
build_multiarch:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
strategy:
matrix:
image: [extproc, llm-katan, dashboard]
# Multi-architecture build strategy:
# - AMD64: Native build on ubuntu-latest (fast)
# - ARM64: Cross-compilation on ubuntu-latest (faster than emulation)
# arch: ${{ github.event_name == 'pull_request' && fromJSON('["amd64"]') || fromJSON('["amd64", "arm64"]') }}
arch: ["amd64", "arm64"]
fail-fast: false
steps:
- name: Check out the repo
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Set up QEMU for cross-compilation
if: matrix.arch == 'arm64'
uses: docker/setup-qemu-action@v3
with:
platforms: arm64
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Enhanced Rust caching for extproc builds with incremental compilation
- name: Cache Rust dependencies (extproc)
if: matrix.image == 'extproc'
uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
candle-binding/target/
~/.rustup/
key: ${{ runner.os }}-cargo-${{ matrix.arch }}-${{ hashFiles('candle-binding/Cargo.toml') }}-${{ hashFiles('candle-binding/Cargo.lock') }}-${{ hashFiles('candle-binding/src/**/*.rs') }}
restore-keys: |
${{ runner.os }}-cargo-${{ matrix.arch }}-${{ hashFiles('candle-binding/Cargo.toml') }}-${{ hashFiles('candle-binding/Cargo.lock') }}-
${{ runner.os }}-cargo-${{ matrix.arch }}-${{ hashFiles('candle-binding/Cargo.toml') }}-
${{ runner.os }}-cargo-${{ matrix.arch }}-
${{ runner.os }}-cargo-
# Python caching for llm-katan builds
- name: Cache Python dependencies (llm-katan)
if: matrix.image == 'llm-katan'
uses: actions/cache@v4
with:
path: |
~/.cache/pip
e2e-tests/llm-katan/.venv
key: ${{ runner.os }}-pip-${{ matrix.arch }}-${{ hashFiles('e2e-tests/llm-katan/requirements.txt', 'e2e-tests/llm-katan/pyproject.toml') }}
restore-keys: |
${{ runner.os }}-pip-${{ matrix.arch }}-
${{ runner.os }}-pip-
# Node.js and Go caching for dashboard builds
- name: Cache Node.js dependencies (dashboard)
if: matrix.image == 'dashboard'
uses: actions/cache@v4
with:
path: |
~/.npm
dashboard/frontend/node_modules
key: ${{ runner.os }}-node-${{ matrix.arch }}-${{ hashFiles('dashboard/frontend/package.json', 'dashboard/frontend/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-${{ matrix.arch }}-
${{ runner.os }}-node-
- name: Cache Go dependencies (dashboard)
if: matrix.image == 'dashboard'
uses: actions/cache@v4
with:
path: |
~/.cache/go-build
~/go/pkg/mod
dashboard/backend/go.sum
key: ${{ runner.os }}-go-${{ matrix.arch }}-${{ hashFiles('dashboard/backend/go.mod', 'dashboard/backend/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ matrix.arch }}-
${{ runner.os }}-go-
- name: Generate date tag for nightly builds
id: date
if: inputs.is_nightly == true
run: echo "date_tag=$(date +'%Y%m%d')" >> $GITHUB_OUTPUT
- name: Set lowercase repository owner
run: echo "REPOSITORY_OWNER_LOWER=$(echo $GITHUB_REPOSITORY_OWNER | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
- name: Set build parameters
id: build-params
run: |
# Default to cross-compilation for ARM64 (always enabled for better performance)
USE_CROSS_COMPILATION="${{ inputs.use_cross_compilation || 'true' }}"
if [ "${{ matrix.image }}" = "extproc" ]; then
echo "context=." >> $GITHUB_OUTPUT
if [ "$USE_CROSS_COMPILATION" = "true" ] && [ "${{ matrix.arch }}" = "arm64" ]; then
echo "dockerfile=./Dockerfile.extproc.cross" >> $GITHUB_OUTPUT
echo "platform=linux/${{ matrix.arch }}" >> $GITHUB_OUTPUT
else
echo "dockerfile=./Dockerfile.extproc" >> $GITHUB_OUTPUT
echo "platform=linux/${{ matrix.arch }}" >> $GITHUB_OUTPUT
fi
elif [ "${{ matrix.image }}" = "llm-katan" ]; then
echo "context=./e2e-tests/llm-katan" >> $GITHUB_OUTPUT
echo "dockerfile=./e2e-tests/llm-katan/Dockerfile" >> $GITHUB_OUTPUT
echo "platform=linux/${{ matrix.arch }}" >> $GITHUB_OUTPUT
elif [ "${{ matrix.image }}" = "dashboard" ]; then
echo "context=." >> $GITHUB_OUTPUT
echo "dockerfile=./dashboard/backend/Dockerfile" >> $GITHUB_OUTPUT
echo "platform=linux/${{ matrix.arch }}" >> $GITHUB_OUTPUT
fi
- name: Generate tags
id: tags
run: |
REPO_LOWER=$(echo $GITHUB_REPOSITORY_OWNER | tr '[:upper:]' '[:lower:]')
ARCH_SUFFIX="${{ matrix.arch }}"
if [ "${{ inputs.is_nightly }}" = "true" ]; then
echo "tags=ghcr.io/${REPO_LOWER}/semantic-router/${{ matrix.image }}:nightly-${{ steps.date.outputs.date_tag }}-${ARCH_SUFFIX}" >> $GITHUB_OUTPUT
else
if [ "${{ github.event_name }}" != "pull_request" ]; then
echo "tags=ghcr.io/${REPO_LOWER}/semantic-router/${{ matrix.image }}:${{ github.sha }}-${ARCH_SUFFIX}" >> $GITHUB_OUTPUT
else
echo "tags=ghcr.io/${REPO_LOWER}/semantic-router/${{ matrix.image }}:pr-${{ github.event.number }}-${ARCH_SUFFIX}" >> $GITHUB_OUTPUT
fi
fi
- name: Build and push ${{ matrix.image }} Docker image
id: build
uses: docker/build-push-action@v5
with:
context: ${{ steps.build-params.outputs.context }}
file: ${{ steps.build-params.outputs.dockerfile }}
platforms: ${{ steps.build-params.outputs.platform }}
push: ${{ github.event_name != 'pull_request' }}
load: ${{ github.event_name == 'pull_request' }}
tags: ${{ steps.tags.outputs.tags }}
cache-from: |
type=gha
type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache,mode=max
build-args: |
BUILDKIT_INLINE_CACHE=1
CARGO_BUILD_JOBS=${{ github.event_name == 'pull_request' && '8' || '16' }}
CARGO_INCREMENTAL=1
RUSTC_WRAPPER=""
CARGO_NET_GIT_FETCH_WITH_CLI=true
BUILDKIT_PROGRESS=plain
TARGETARCH=${{ matrix.arch }}
# Optimize Rust compilation for ARM64
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc
# Enable link-time optimization for release builds
CARGO_PROFILE_RELEASE_LTO=thin
CARGO_PROFILE_RELEASE_CODEGEN_UNITS=1
# Use faster linker
CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUSTFLAGS="-C link-arg=-fuse-ld=lld"
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUSTFLAGS="-C link-arg=-fuse-ld=lld"
# Create multi-arch manifest for final images
create_manifest:
needs: build_multiarch
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
if: github.event_name != 'pull_request'
strategy:
matrix:
image: [extproc, llm-katan, dashboard]
steps:
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set lowercase repository owner
run: echo "REPOSITORY_OWNER_LOWER=$(echo $GITHUB_REPOSITORY_OWNER | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
- name: Generate date tag for nightly builds
id: date
if: inputs.is_nightly == true
run: echo "date_tag=$(date +'%Y%m%d')" >> $GITHUB_OUTPUT
- name: Create and push manifest
run: |
REPO_LOWER=$(echo $GITHUB_REPOSITORY_OWNER | tr '[:upper:]' '[:lower:]')
# Create manifest for the specific image
if [ "${{ inputs.is_nightly }}" = "true" ]; then
TAG="nightly-${{ steps.date.outputs.date_tag }}"
else
if [ "${{ github.event_name }}" != "pull_request" ]; then
TAG="${{ github.sha }}"
else
TAG="pr-${{ github.event.number }}"
fi
fi
# Create and push manifest by combining architecture-specific images
docker buildx imagetools create \
--tag ghcr.io/${REPO_LOWER}/semantic-router/${{ matrix.image }}:${TAG} \
ghcr.io/${REPO_LOWER}/semantic-router/${{ matrix.image }}:${TAG}-amd64 \
ghcr.io/${REPO_LOWER}/semantic-router/${{ matrix.image }}:${TAG}-arm64
# Also tag as latest for non-nightly builds
if [ "${{ inputs.is_nightly }}" != "true" ]; then
docker buildx imagetools create \
--tag ghcr.io/${REPO_LOWER}/semantic-router/${{ matrix.image }}:latest \
ghcr.io/${REPO_LOWER}/semantic-router/${{ matrix.image }}:${TAG}-amd64 \
ghcr.io/${REPO_LOWER}/semantic-router/${{ matrix.image }}:${TAG}-arm64
fi
- name: Build summary
if: always()
run: |
if [ "${{ job.status }}" = "success" ]; then
echo "::notice title=Build Success::${{ matrix.image }} multi-arch manifest created successfully"
else
echo "::error title=Build Failed::${{ matrix.image }} build failed"
fi