feat: k8s support and some fixes #317
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |