Skip to content

Build On Demand

Build On Demand #556

# SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
name: Build On Demand
on:
workflow_dispatch:
inputs:
build_vllm:
description: 'Build and push vllm image, tagged with branch name'
type: boolean
default: false
build_sglang:
description: 'Build and push sglang image, tagged with branch name'
type: boolean
default: false
build_trtllm:
description: 'Build and push trtllm image, tagged with branch name'
type: boolean
default: false
build_operator:
description: 'Build and push operator image, tagged with branch name'
type: boolean
default: false
env:
BUILDER_NAME: b-${{ github.run_id }}-${{ github.run_attempt }}
jobs:
init:
runs-on: ubuntu-slim
outputs:
builder_name: ${{ steps.export-builder-name.outputs.builder_name }}
sanitized_ref_name: ${{ steps.sanitize-ref.outputs.sanitized_ref_name }}
steps:
- name: Export builder name
id: export-builder-name
run: |
echo "builder_name=${{ env.BUILDER_NAME }}" >> $GITHUB_OUTPUT
- name: Sanitize ref name for container tags
id: sanitize-ref
shell: bash
run: |
sanitized=$(echo "${{ github.ref_name }}" | sed 's/[^a-zA-Z0-9._-]/-/g' | sed 's/^-//;s/-$//' | cut -c1-128)
echo "sanitized_ref_name=${sanitized}" >> $GITHUB_OUTPUT
# ============================================================================
# FRAMEWORK PIPELINES (build-only)
# ============================================================================
vllm-build:
name: vllm-runtime # This name overlaps with other vllm jobs to group them in the UI
needs: [init]
if: inputs.build_vllm
uses: $/.github/workflows/shared-build-image.yml
with:
framework: vllm
target: runtime
cuda_version: '["13.0"]'
platform: 'linux/amd64,linux/arm64'
builder_name: ${{ needs.init.outputs.builder_name }}
build_timeout_minutes: 60
secrets: inherit
sglang-build:
name: sglang-runtime # This name overlaps with other sglang jobs to group them in the UI
needs: [init]
if: inputs.build_sglang
uses: $/.github/workflows/shared-build-image.yml
with:
framework: sglang
target: runtime
cuda_version: '["13.0"]'
platform: 'linux/amd64,linux/arm64'
builder_name: ${{ needs.init.outputs.builder_name }}
build_timeout_minutes: 60
secrets: inherit
trtllm-build:
name: trtllm-runtime # This name overlaps with other trtllm jobs to group them in the UI
needs: [init]
if: inputs.build_trtllm
uses: $/.github/workflows/shared-build-image.yml
with:
framework: trtllm
target: runtime
cuda_version: '["13.1"]'
platform: 'linux/amd64,linux/arm64'
builder_name: ${{ needs.init.outputs.builder_name }}
build_timeout_minutes: 60
secrets: inherit
vllm-copy-to-acr:
name: vllm-runtime # This name overlaps with other vllm jobs to group them in the UI
needs: [vllm-build]
uses: $/.github/workflows/shared-copy.yml
with:
target_tag_plain: ${{ needs.vllm-build.outputs.target_tag_plain }}
cuda_version: '["13.0"]'
copy_timeout_minutes: 20
secrets: inherit
sglang-copy-to-acr:
name: sglang-runtime # This name overlaps with other sglang jobs to group them in the UI
needs: [sglang-build]
uses: $/.github/workflows/shared-copy.yml
with:
target_tag_plain: ${{ needs.sglang-build.outputs.target_tag_plain }}
cuda_version: '["13.0"]'
copy_timeout_minutes: 20
secrets: inherit
trtllm-copy-to-acr:
name: trtllm-runtime # This name overlaps with other trtllm jobs to group them in the UI
needs: [trtllm-build]
uses: $/.github/workflows/shared-copy.yml
with:
target_tag_plain: ${{ needs.trtllm-build.outputs.target_tag_plain }}
cuda_version: '["13.1"]'
override_arch: amd64 # We are using AMD64 images only on the rest of the clusters.
copy_timeout_minutes: 10
secrets: inherit
# ============================================================================
# OPERATOR (build-only)
# ============================================================================
operator:
needs: [init]
if: inputs.build_operator
name: Operator
runs-on: prod-default-v2
env:
ECR_REGISTRY: ${{ vars.ECR_REGISTRY }}
ECR_REPOSITORY: ${{ vars.ECR_REPOSITORY }}
ACR_REPOSITORY: ${{ vars.ACR_REPOSITORY }}
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Initialize Dynamo Builder
uses: $/.github/actions/init-dynamo-builder
with:
builder_name: ${{ needs.init.outputs.builder_name }}
flavor: general
arch: 'linux/amd64,linux/arm64'
namespace: ${{ vars.BUILDKIT_NAMESPACE }}
- name: Docker Login
uses: $/.github/actions/docker-login
with:
aws_default_region: ${{ vars.AWS_DEFAULT_REGION }}
ecr_registry: ${{ vars.ECR_REGISTRY }}
azure_acr_hostname: ${{ secrets.AZURE_ACR_HOSTNAME }}
azure_acr_user: ${{ secrets.AZURE_ACR_USER }}
azure_acr_password: ${{ secrets.AZURE_ACR_PASSWORD }}
- name: Build and push Container
shell: bash
working-directory: ./deploy/operator
run: |
ECR_DEFAULT_IMAGE_BASE="${ECR_REGISTRY}/${ECR_REPOSITORY}"
ACR_IMAGE_BASE="${{ secrets.AZURE_ACR_HOSTNAME }}/${ACR_REPOSITORY}"
DEFAULT_TAG="${{ github.sha }}-operator"
BRANCH_TAG="${{ needs.init.outputs.sanitized_ref_name }}-operator"
IMAGE_URIS=(
"${ECR_DEFAULT_IMAGE_BASE}:${DEFAULT_TAG}"
"${ACR_IMAGE_BASE}:${DEFAULT_TAG}"
"${ECR_DEFAULT_IMAGE_BASE}:${BRANCH_TAG}"
"${ACR_IMAGE_BASE}:${BRANCH_TAG}"
)
TAGGING_FLAGS=$(printf -- '-t %s ' "${IMAGE_URIS[@]}")
echo "flags for docker buildx: ${TAGGING_FLAGS}"
# deploy/operator/Dockerfile's licenses stage does `COPY --from=compliance`,
# which resolves as an image unless the named build context is supplied.
# Without this the build fails pulling docker.io/library/compliance.
# .github/actions/build-deploy-component passes the same flag.
docker buildx build --push \
--platform linux/amd64,linux/arm64 \
--build-arg DOCKER_PROXY=${ECR_REGISTRY}/dockerhub/ \
--build-context compliance=../../container/compliance \
${TAGGING_FLAGS} -f Dockerfile .
echo "### Operator Container Images" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Image URI |" >> $GITHUB_STEP_SUMMARY
echo "|-----|" >> $GITHUB_STEP_SUMMARY
for image_uri in "${IMAGE_URIS[@]}"; do
echo "| \`${image_uri}\` |" >> $GITHUB_STEP_SUMMARY
done
# ============================================================================
# CLEANUP
# ============================================================================
clean-k8s-builder:
name: Clean K8s builder if exists
runs-on: prod-default-small-v2
if: always()
needs: [init, vllm-build, sglang-build, trtllm-build, operator]
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Create K8s builders (skip bootstrap)
uses: $/.github/actions/bootstrap-buildkit
continue-on-error: true
with:
builder_name: ${{ needs.init.outputs.builder_name }}
buildkit_worker_addresses: ''
namespace: ${{ vars.BUILDKIT_NAMESPACE }}
skip_bootstrap: true
- name: Builder Cleanup in case of k8s builder
shell: bash
run: |
docker buildx rm ${{ needs.init.outputs.builder_name }} || true