Files
zeekay 9f50e10468 release-0.18: build this fork, pinned at upstream v0.18.1
ns kserve runs docker.io/kserve/kserve-controller:v0.18.0 and three more
upstream images the controller injects (storage-initializer into every
InferenceService, agent for logger/batcher, router for InferenceGraph -- all
named in cm/inferenceservice-config). It runs them because no
ghcr.io/hanzoai/kserve-* image exists: this fork had no build lane, only
upstream .github/workflows, which do not run on our estate.

Cut from the upstream RELEASE TAG v0.18.1, not from master. master here is a
mirror of upstream master; publishing it would ship an unreleased main-branch
build, and v0.18.1 is the last patch on the line the cluster already runs --
so this is a patch bump, not a version jump.

NOTICE carries the upstream attribution by name alongside the verbatim
Apache-2.0 LICENSE, and states the release-pin invariant in a form that can be
checked: the fork point is `git describe --tags --abbrev=0`.
2026-08-04 00:04:04 -07:00

128 lines
4.9 KiB
YAML

name: build
# KServe is a FORK (hanzo-ml/kserve), so the images ns kserve runs must come from
# here. Until this lane existed there was no ghcr.io/hanzoai/kserve-* image at
# all, which is why the cluster ran docker.io/kserve/* -- the fork carried the
# maintenance and upstream carried the risk.
#
# RELEASE BRANCHES ONLY. `master` here is a mirror of upstream master; building
# it would publish an unreleased main-branch build, which is what a fork is meant
# to protect against. A release-* branch is cut from an upstream RELEASE TAG, so
# `git describe --tags --abbrev=0` names the fork point and the diff after it is
# ours.
#
# Five images, because that is exactly what the plane consumes: the controller
# Deployment, and the four the controller INJECTS -- storage-initializer into
# every InferenceService, agent for logger/batcher, router for InferenceGraph
# (all four named in ns kserve cm/inferenceservice-config).
#
# huggingfaceserver is NOT built here. It compiles vLLM against a CUDA devel base
# and nothing in the cluster runs it; its ClusterServingRuntime still points at
# docker.io/kserve/huggingfaceserver:latest and needs its own lane and its own
# runner class. Building artifacts nothing deploys is how a pipeline rots
# unnoticed.
on:
push:
branches: ['release-*']
paths:
- 'cmd/**'
- 'pkg/**'
- 'python/kserve/**'
- 'python/storage-initializer.Dockerfile'
- 'go.mod'
- 'go.sum'
- 'Dockerfile'
- 'agent.Dockerfile'
- 'router.Dockerfile'
- '.hanzo/workflows/deploy.yml'
workflow_dispatch: {}
concurrency:
group: build-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: [hanzo-build-linux-amd64]
strategy:
fail-fast: false
matrix:
include:
- image: kserve-controller
dockerfile: Dockerfile
context: .
- image: kserve-agent
dockerfile: agent.Dockerfile
context: .
- image: kserve-router
dockerfile: router.Dockerfile
context: .
- image: kserve-storage-initializer
dockerfile: python/storage-initializer.Dockerfile
context: python
steps:
- uses: actions/checkout@v4
with:
# Tags, so the release the branch is pinned at is readable from the
# checkout. Without them `git describe` has nothing to name and the
# published tag cannot say which upstream release it is.
fetch-depth: 0
- id: meta
run: |
set -euo pipefail
echo "sha=sha-$(echo "$GITHUB_SHA" | cut -c1-7)" >> "$GITHUB_OUTPUT"
rel="$(git describe --tags --abbrev=0)"
echo "rel=${rel}-hanzo.$(git rev-list "${rel}..HEAD" --count)" >> "$GITHUB_OUTPUT"
# hanzo-ml is a separate org from hanzoai and gets its own credentials. If
# it has none, BUILD anyway -- that the fork still compiles is the thing
# most worth knowing -- and say plainly in the log that nothing shipped,
# rather than leaving the cluster on upstream with a green tick.
- id: creds
run: |
set -euo pipefail
if [ -n "${{ secrets.GHCR_TOKEN }}" ]; then
echo "push=true" >> "$GITHUB_OUTPUT"
else
echo "push=false" >> "$GITHUB_OUTPUT"
echo "::warning::hanzo-ml has no GHCR_TOKEN -- building only, nothing will be published."
fi
- uses: docker/setup-buildx-action@v3
with:
driver: docker-container
driver-opts: network=host
- uses: docker/login-action@v3
if: ${{ steps.creds.outputs.push == 'true' }}
with:
registry: ghcr.io
username: ${{ secrets.GHCR_USER }}
password: ${{ secrets.GHCR_TOKEN }}
- uses: docker/build-push-action@v6
with:
context: ${{ matrix.context }}
file: ${{ matrix.dockerfile }}
platforms: linux/amd64
push: ${{ steps.creds.outputs.push == 'true' }}
tags: |
ghcr.io/hanzoai/${{ matrix.image }}:${{ steps.meta.outputs.sha }}
ghcr.io/hanzoai/${{ matrix.image }}:${{ steps.meta.outputs.rel }}
# build-push-action can exit 0 before the manifest resolves, so a green run
# is weaker evidence than a tag that actually pulls. Print the digest: it
# is what the values file pins, and reading it out of the log beats a
# second round trip to the registry.
- name: the pushed image resolves
if: ${{ steps.creds.outputs.push == 'true' }}
run: |
set -euo pipefail
img="ghcr.io/hanzoai/${{ matrix.image }}:${{ steps.meta.outputs.sha }}"
for i in 1 2 3 4 5 6; do
if docker buildx imagetools inspect "${img}" >/dev/null 2>&1; then
docker buildx imagetools inspect "${img}" | head -3
exit 0
fi
[ "${i}" = 6 ] && { echo "::error::pushed image never resolved: ${img}"; exit 1; }
sleep 5
done