diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..f64dfb7 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,97 @@ +name: Build-Publish + +on: + push: + # Trigger on version tags like v1.0.0 + tags: + - 'v*' + # Trigger on pushes to main (typically PR merges) + branches: + - main + # Allow manual trigger + workflow_dispatch: + +permissions: + contents: read + packages: write + +# Cancel superseded builds so rapid pushes don't queue duplicates. +# Never cancel tag builds — each tag is a distinct release artifact. +concurrency: + group: build-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref_type != 'tag' }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + image_config: + # A2A runner used by the k8s Job in + # exgentic_a2a_runner/k8s/job.yaml. + - name: exgentic-a2a-runner + context: ./exgentic_a2a_runner + dockerfile: ./exgentic_a2a_runner/Dockerfile + + steps: + # 1. Checkout code + - name: Checkout repository + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + + # 2. Set up QEMU for multi-arch builds + - name: Set up QEMU + uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4 + + # 3. Set up Docker Buildx + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4 + + # 4. Log in to GitHub Container Registry + - name: Log in to ghcr.io + uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + # 5. Resolve the image tag: + # - on v* tag → the tag name (e.g. v0.0.1) + # - otherwise → - + - name: Generate image tag + id: tag + run: | + if [[ "${{ github.ref_type }}" == "tag" ]]; then + echo "tag=${{ github.ref_name }}" >> "$GITHUB_OUTPUT" + else + BRANCH="${{ github.ref_name }}" + BRANCH="${BRANCH//\//-}" + SHORT_SHA="$(echo "${{ github.sha }}" | cut -c1-7)" + echo "tag=${BRANCH}-${SHORT_SHA}" >> "$GITHUB_OUTPUT" + fi + + # 6. Extract Docker metadata. Apply `latest` on v* tag pushes, + # pushes to main, and manual dispatches. + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6 + with: + images: ghcr.io/${{ github.repository }}/${{ matrix.image_config.name }} + tags: | + type=raw,value=${{ steps.tag.outputs.tag }} + type=raw,value=latest,enable=${{ (github.ref_type == 'tag' && startsWith(github.ref_name, 'v')) || github.event_name == 'workflow_dispatch' || github.ref == 'refs/heads/main' }} + + # 7. Build and push image. Note: no build-args here — the runner + # doesn't need any today, and specifying `build-args:` twice (as + # cortex's build.yaml does) silently drops matrix-level args + # because the second key wins. + - name: Build and push ${{ matrix.image_config.name }} + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7 + with: + context: ${{ matrix.image_config.context }} + file: ${{ matrix.image_config.dockerfile }} + push: true + platforms: linux/amd64,linux/arm64 + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/README.md b/README.md index cb8d29f..ecc3075 100644 --- a/README.md +++ b/README.md @@ -906,15 +906,11 @@ The runner can execute entirely inside the cluster as a Kubernetes Job — no lo `k8s/job.yaml` is the launch template. It references secrets for credentials and passes benchmark/agent flags as container `args`. The job container uses cluster-internal DNS to reach the Kagenti API, Keycloak, MCP server, and agent — no port-forwarding is required. MLflow tracing switches automatically to HTTP/protobuf when `KUBERNETES_SERVICE_HOST` is set. -### Step 1 — Build and push the runner image +### Step 1 — Pull (or build) the runner image -```bash -cd exgentic_a2a_runner -docker build -t ghcr.io/exgentic/runner:latest . -docker push ghcr.io/exgentic/runner:latest -``` +Prebuilt multi-arch images are published to GHCR on every push to `main` and every `v*` tag — see [Container images](#container-images) below. `k8s/job.yaml` points at `:latest` (which tracks `main`) by default, so no build is required. -Replace `ghcr.io/exgentic/runner:latest` with your own registry path if needed, and update `k8s/job.yaml` → `image:` to match. +To build locally instead — for example, to test unreleased changes — see [Iterating with a locally-built image](#iterating-with-a-locally-built-image). ### Step 2 — Set up required secrets @@ -996,12 +992,40 @@ AGENT PROCESSING LATENCY To test a local image change without pushing to a registry, sync it into the kind cluster first: ```bash -export REMOTE_IMAGE_NAME=ghcr.io/exgentic/runner:dev +cd exgentic_a2a_runner +docker build -t ghcr.io/rossoctl/workload-harness/exgentic-a2a-runner:dev . +export REMOTE_IMAGE_NAME=ghcr.io/rossoctl/workload-harness/exgentic-a2a-runner:dev export KIND_CLUSTER_NAME=kagenti source ./sync-image-to-cluster.sh ``` -Then set `imagePullPolicy: IfNotPresent` in `k8s/job.yaml` and submit as above. +Update `k8s/job.yaml` → `image:` to match your local tag, set `imagePullPolicy: IfNotPresent`, and submit as above. + +## Container images + +The runner image is built and published by [`.github/workflows/build.yaml`](.github/workflows/build.yaml) on every push to `main`, every `v*` tag, and manual workflow dispatch. Images are multi-arch (`linux/amd64`, `linux/arm64`). + +| Image | Source | +|-------|--------| +| `ghcr.io/rossoctl/workload-harness/exgentic-a2a-runner` | [`exgentic_a2a_runner/Dockerfile`](exgentic_a2a_runner/Dockerfile) | + +**Tags:** + +| Ref pushed | Tags produced | +|------------|---------------| +| `v*` tag (e.g. `v0.0.1`) | `v0.0.1`, `latest` | +| Push to `main` | `main-`, `latest` | +| Manual dispatch on any branch | `-`, `latest` | +| Push to any other branch | `-` | + +`latest` tracks `main` — pin to a `v*` or `main-` tag for reproducible deploys. + +**Build locally:** + +```bash +cd exgentic_a2a_runner +docker build -t ghcr.io/rossoctl/workload-harness/exgentic-a2a-runner:dev . +``` ## E2E Test Script diff --git a/exgentic_a2a_runner/k8s/job.yaml b/exgentic_a2a_runner/k8s/job.yaml index 70438bd..6cbe085 100644 --- a/exgentic_a2a_runner/k8s/job.yaml +++ b/exgentic_a2a_runner/k8s/job.yaml @@ -13,7 +13,9 @@ spec: # All cluster interaction goes through the Kagenti API and Keycloak over HTTP. containers: - name: runner - image: ghcr.io/exgentic/runner:latest + # Published by .github/workflows/build.yaml. `:latest` tracks + # main; use a `main-` or `v*` tag to pin a specific build. + image: ghcr.io/rossoctl/workload-harness/exgentic-a2a-runner:latest imagePullPolicy: IfNotPresent args: - "--benchmark"